【问题标题】:Program to count number of digits in a double following decimal point in Java程序在Java中计算双后小数点中的位数
【发布时间】:2021-11-19 10:53:31
【问题描述】:

下面是一个程序,它应该计算小数点后双精度值的位数。在输入一些双精度值时,程序往往会启动一个无限循环(可能是由于浮点不精确)。我想使用任何包装方法(包括 String 类)。有人可以为某些输入的无限循环提供解释并提供解决方案吗?

import java.util.*;
class Flt
{
    public static void main(String args[])
    {
        Scanner sc = new Scanner(System.in);
        
        System.out.print("Enter a double number: ");
        double f = sc.nextDouble();
        double tmp = f;
        
        int len = 0;
        while(tmp != (int) tmp)
        {
            tmp *= 10;
            len++;
        }
        System.out.println(len);
    }
}

【问题讨论】:

  • 一个很可能的原因是浮点精度问题。最简单和最强大的解决方案实际上是使用BigDecimal 或字符串表示。除此之外,您可以尝试使用阈值来比较这些值(即,如果绝对差小于 0.0000001,则认为它们相等 - 您需要找到一个合理的值)。但是请注意,即使是涉及double 的单个计算也已经可以更改小数位数(0.12345 * 10 已经是 1.2345000000000002)。
  • Java 的double 格式使用二进制浮点格式,因此它没有正确的小数位。尝试计算小数位是对浮点运算工作原理的误解。

标签: java floating-point double precision floating-accuracy


【解决方案1】:

问题在转换为int 时溢出,因此tmp != (int) tmp 永远不会为真。

考虑用户输入“3.1415”。 3.1415 无法以double 格式表示,因此将其转换为最接近的可表示值,3.141500000000000181188397618825547397136688232421875。首先,它有很多十进制数字,即使乘以十是用精确的实数算术执行的,它们也不会产生整数结果,直到数字达到 3141500000000000181188397618825547397136688232421875。但是,如果没有,该数字无法转换为 int溢出,因为它太大而无法在 int 中表示。转换产生int 中可表示的最大值,2147483647。然后将数字 3141500000000000181188397618825547397136688232421875 与转换结果 2147483647 进行比较,表明它们不相等,循环继续。

事实上,乘以 10 并不是用精确的实数算术来执行的。在每次乘法中,结果将四舍五入为double 中可表示的最接近的值。所以第一个产生 31.415000000000002700062395888380706310272216796875,下一个产生 314.15000000000003410605131648480892181396484375,等等。第一个整数结果是 31415000000000004。同样,这太大了,无法在 int 中表示,所以 tmp != (int) tmp 被评估为 31415000000000004 != 2147483647,这当然是真的,所以循环继续。

可以通过消除对int的转换来解决无限循环。例如,只要tmp 除以 1 有余数(因此不是整数),就可以将测试表达式替换为 tmp % 1 != 0 循环。但是,“3.1415”的输入产生 16——它不计算用户输入或扫描它产生的 double 中的小数位数,而是计算迭代次数,直到四舍五入的乘法产生一个整数.

一旦用户的输入被转换为double,就无法正确计算用户输入的小数位数,因为原始值丢失了。如果用户输入的不是“3.1415”或“3.141500000000000181188397618825547397136688232421875”,所产生的double会3.141500000000000181188397618825547397136688232421875,所以这是不可能的,告诉一下原来的数量。要计算用户输入中的小数位数,将其作为字符串读取,查找小数点,并计算其后的数字字符(如果需要,不包括尾随零)。

【讨论】:

  • 那么,只是为了确认一下,没有万无一失的方法可以通过数学语句计算实数的位数吗?我必须使用 String 来应对不精确?
  • @millionleafclover:一旦将数字转换为double,就可以计算double值的十进制表示中的有效位数,但不可能知道在转换和四舍五入到最接近的double之前,原始数字中有多少位。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多