有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

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

共 (1) 个答案

  1. # 1 楼答案

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

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

    事实上,十的乘法不是用精确的实数运算来完成的。在每次乘法中,结果四舍五入到double中表示的最接近的值。因此,第一个收益率为31.4150000000000027006239588380706310272216796875,下一个收益率为314.150000000003410605131648480892181396484375,依此类推。第一个整数结果是31415000000000004。同样,它太大,无法在int中表示,因此tmp != (int) tmp被计算为31415000000000004 != 2147483647,这当然是正确的,因此循环继续

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

    一旦用户的输入被转换为double,就无法正确计算用户输入的小数位数,因为原始值丢失了。如果用户输入“3.1415”或“3.141500000000000181188397618825547397136688232421875”,则生成的double将是3.14150000000000011883976188255497136688232421875,因此无法判断原始数字是什么。要计算用户输入中的小数位数,请将其作为字符串读取,查找小数点,并计算小数点后的数字字符(如果需要,不包括尾随的零)