将小数位移到双精度值

2022-08-31 10:24:25

所以我有一个双精度设置为等于1234,我想移动一个小数位以使其为12.34

所以要做到这一点,我将.1乘以1到1234两次,有点像这样

double x = 1234;
for(int i=1;i<=2;i++)
{
  x = x*.1;
}
System.out.println(x);

这将打印结果“12.3400000000000002”

有没有办法,不简单地将其格式化为两个小数位,就可以正确使用双存储12.34?


答案 1

如果使用 或 ,则应使用舍入,否则可能会看到一些舍入错误。如果无法执行此操作,请使用 .doublefloatBigDecimal

您遇到的问题是0.1不是一个精确的表示,并且通过执行两次计算,您将使该误差更加复杂。

但是,100 可以准确表示,因此请尝试:

double x = 1234;
x /= 100;
System.out.println(x);

哪些打印:

12.34

这之所以有效,是因为代表您执行少量舍入,但并不多。如果您想知道如果不舍入,它可能会是什么样子:Double.toString(d)

System.out.println(new BigDecimal(0.1));
System.out.println(new BigDecimal(x));

指纹:

0.100000000000000005551115123125782702118158340454101562
12.339999999999999857891452847979962825775146484375

简而言之,对于浮点的合理答案,舍入是不可避免的,无论你是否明确这样做。


注意:当涉及到舍入误差时,它们并不完全相同。这是因为第一个表达式的舍入误差取决于 x 的值,而第二个表达式中的舍入误差是固定的。x / 100x * 0.010.01

for(int i=0;i<200;i++) {
    double d1 = (double) i / 100;
    double d2 = i * 0.01;
    if (d1 != d2)
        System.out.println(d1 + " != "+d2);
}

指纹

0.35 != 0.35000000000000003
0.41 != 0.41000000000000003
0.47 != 0.47000000000000003
0.57 != 0.5700000000000001
0.69 != 0.6900000000000001
0.7 != 0.7000000000000001
0.82 != 0.8200000000000001
0.83 != 0.8300000000000001
0.94 != 0.9400000000000001
0.95 != 0.9500000000000001
1.13 != 1.1300000000000001
1.14 != 1.1400000000000001
1.15 != 1.1500000000000001
1.38 != 1.3800000000000001
1.39 != 1.3900000000000001
1.4 != 1.4000000000000001
1.63 != 1.6300000000000001
1.64 != 1.6400000000000001
1.65 != 1.6500000000000001
1.66 != 1.6600000000000001
1.88 != 1.8800000000000001
1.89 != 1.8900000000000001
1.9 != 1.9000000000000001
1.91 != 1.9100000000000001

注:这与系统(或电源)中的随机性无关。这是由于表示错误造成的,每次都会产生相同的结果。的精度是有限的,以 2 为基数而不是以 10 为基数,因此可以用十进制精确表示的数字通常不能以 2 为底精确表示。double


答案 2

否 - 如果要准确存储十进制值,请使用 。 根本无法精确地表示像0.1这样的数字,就像您可以用有限数量的十进制数字精确地写入三分之一的值一样。BigDecimaldouble