在Java中计算小数点后的双精度数的程序



下面是一个程序,用来计算小数点后的双精度值的位数。在输入一些双精度值时,程序倾向于开始一个无限循环(可能是由于浮点不精确)。I希望使用任何包装器方法(包括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);
}
}

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

考虑用户输入"3.1415"。3.1415在double格式中无法表示,因此将其转换为最接近的可表示值3.141500000000000181188397618825547397136688232421875。首先,它有如此多的十进制数字,以至于即使用精确的实数算术进行10的乘法运算,也不会产生整数结果,直到数字达到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,因此不可能知道原始数字是什么。要计算用户输入中的小数位数,将其作为字符串读取,查找小数点,并计算其后面的数字字符(如果需要,不包括后面的零)。

相关内容

  • 没有找到相关文章

最新更新