【问题标题】:How to get the number of decimal digits from a double in Java? (Ex: 2.34 => 2 , 2.340 => 2 , 0.921 => 3)如何从 Java 中的 double 中获取小数位数? (例如:2.34 => 2、2.340 => 2、0.921 => 3)
【发布时间】:2014-11-04 14:13:05
【问题描述】:

标题是不言自明的。有什么好的方法,最好只用数学,从 Java double 中获取位数?

123 => 0
1.12 => 2
1.0001 => 4
2.340000 => 2
0.10 => 1

例如,我有一个双倍 d = 0.320。

据我所知,对于编译器/jvm/计算机:

System.out.println(0.0100000 == 0.01); // prints true...

【问题讨论】:

  • 0.10怎么算1的长度?
  • 0.10 实际上是 0.1。编译器/计算机也是如此。
  • @ElliottFrisch Guess - 小数部分的重要数字
  • @chrisapotek System.out.println(0.10 + 0.10 + 0.10); // prints 0.30000000000000004
  • @ElliottFrisch 与System.out.println(0.1 + 0.1 + 0.1); 相同,但这并不能改变 0.100000 == 0.1

标签: java floating-point integer double


【解决方案1】:

这应该得到十进制之后的金额:

 Double d = 123.9343;
 String[] div = d.toString().split("\\.");
 div[0].length();   // Before Decimal Count
 div[1].length();   // After  Decimal Count   

解释:你先把double转成字符串,然后使用split函数将字符串从.中拆分出来
一旦它分成两部分,您就可以使用length 函数轻松找到字符串的长度。

【讨论】:

  • 你必须小心科学记数法,不是吗?例如:9E-1 ?
  • 是的,但是如果您尝试使用 2.340,它会返回 3。但是 chrisapotek 希望它返回 2。
  • @TheCazziator33:试试看,它返回 2。
  • 您确定科学记数法不会成为问题吗?例如:9E-1 ?
  • 等一下你问这个函数是否接受9E-1作为输入?因为它不应该
【解决方案2】:

您需要使用指定精度的BigDecimal 类。其他一切都只是一个技巧。

This is required reading as a computer scientist,您必须阅读它才能理解为什么您的问题如此糟糕。

【讨论】:

  • 我认为你不需要阅读 Goldberg 的所有论文来理解二进制浮点是什么。
  • 他的问题没有被打破。这只是一个问题。
  • @rocksNwaves 在谷歌上搜索了一下这显然是一个比我想象的更晦涩的短语。有一个 ELL https://ell.stackexchange.com/questions/34974/what-does-broken-question-mean 询问我使用它的 不同 时间,并且与“滥用符号”、“乞求问题”和其他与哲学相关的短语不同,上面没有 wiki 页面。话虽如此,这意味着这个问题是不恰当的。在这种情况下,它基于一个无效的前提,即双倍“有”任何意义上的数字。
【解决方案3】:

我不会给你代码,只是方法。一种方法是将数字打印到字符串中,然后在该字符串上使用正则表达式。获取小数点后的字符串部分并计算数字,直到得到 0。有一些极端情况,但你可以处理它。但有一件事,有些数字不能精确表示,比如 4/3,所以理论上小数位数是无限的。但是如果你打印到一个字符串,你会限制小数位数,这使得计算变得容易。只要知道,如果你限制在 N 个小数位并且你的计数器返回 N ,那么它究竟是 N 个小数位还是无穷大有点怀疑。如果您在实施此方法时遇到困难,请告诉我您有什么以及您遇到的问题,我可以为您提供进一步的帮助。

【讨论】:

    【解决方案4】:

    短版:使用BigDecimal,它是scale() 方法。随心所欲地初始化。

    长版:

    您特别提到您更喜欢您使用的解决方案

    • “仅限数学”(模棱两可,但我能猜出你的意思)
    • double 中获取位数,大概是小数部分(根据您的预期输出)

    这是一个使用java.math.BigDecimal 的解决方案:

    List<BigDecimal> list = new ArrayList<BigDecimal>() {{
        add(BigDecimal.valueOf(0.0000000018));
        add(BigDecimal.valueOf(123));
        add(BigDecimal.valueOf(1.12));
        add(BigDecimal.valueOf(1.0001));
        add(BigDecimal.valueOf(2.340000));
        add(BigDecimal.valueOf(0.10));
    }};
    
    for (BigDecimal bd : list) { 
        System.out.println(bd + " --> " + bd.scale());
    }
    

    输出:

    1.8E-9 --> 10
    123 --> 0
    1.12 --> 2
    1.0001 --> 4
    2.34 --> 2
    0.1 --> 1
    

    请注意,像这样从double 实例化BigDecimal 最终会给您带来令人惊讶的结果。考虑BigDecimal.valueOf(0.1 + 0.1 + 0.1)scale(),即17。这是因为0.1(以及范围内大多数其他约 97% 的数字)不能由 double 精确表示,这会在计算中引入舍入误差。

    另请注意,使用 scale() 函数的解决方案涉及操纵 toString() 的结果将失败。 Double.toString() 定义明确,并且可以产生超出人们可能认为的double 的“十进制表示法”的一系列输出。

    【讨论】:

      【解决方案5】:

      没有与您给出的结果一致的“Java double 的位数”​​的有用概念。 double 是二进制浮点数,而不是十进制浮点数,例如,Java 中的double 1.12 实际上是数字1.12000000000000010658141036401502788066864013671875,它的小数点后有 50 位重复零。

      【讨论】:

      • 那是因为你添加的十进制数字超出了支持的数量,伙计。它们被编译器丢弃。 System.out.println(1.1200000000000001); // prints 1.12
      • @chrisapotek:“支持的小数位数”没有连贯的概念。编译器不会“丢弃”一些但不是其他十进制数字。
      【解决方案6】:

      双精度数中的小数位数为 15.9。期间。(我会让你弄清楚如何对待 0.9。)

      如果您有一个浮点数 1.00000000000001,您不知道(没有更多信息)该数字右端的“1”是“信息”还是“噪声”。与 0.9999999999999 类似——它真的是 1.0,还是所有这些 9 都很重要? 你不知道没有一些关于计算/测量精度的信息,而不是产生数字。

      通常将数字格式化为 N 位,然后在右侧“修剪”零字符串(或四舍五入的 9),但这充其量只是一个有根据的赌注。在最坏的情况下,它会丢弃关键数据。

      【讨论】:

      • 某些浮点值不能在不使用 17 位的情况下表示,但并非所有 16 位十进制数都具有唯一表示。因此,有意义的数字在某些情况下只有 15 个,在某些情况下是 17 个,尽管通常是 16 个。
      猜你喜欢
      • 2022-12-01
      • 2016-10-04
      • 2021-02-15
      • 2010-09-25
      • 1970-01-01
      • 1970-01-01
      • 2023-03-05
      • 2017-03-25
      • 2012-07-04
      相关资源
      最近更新 更多