这个重复的十进制乘法如何得到准确的结果

时间:2018-04-16 10:15:15

标签: java floating-point

如何(1/3)* 3 = 1.00000000000000000000,是否从0.9999舍入......?

public static void main(String[] args) {
    double numerator = 1.0;
    double denominator = 3.0;
    double result = numerator / denominator;
    System.out.printf("1 / 3 = %f \n", result);
    double multiplied = result * 3;
    System.out.printf("3 * (1/3) = %.20f \n", multiplied);
    System.out.format("%.14f", 1.0/3.0 * 3);
}

结果

1 / 3 = 0.333333 
3 * (1/3) = 1.00000000000000000000 
1.00000000000000

3 个答案:

答案 0 :(得分:2)

就像1/3.0无法用Java中的double精确表示一样,也无法准确表示3 * 1.0/3.0可以准确地由double表示的最接近的数字是1。 你很幸运。

您可以使用Double.doubleToLongBits将双精度的64位转换为长整数。这表明以下3个双表达式在double的位中具有相同的表示形式:

System.out.println(Double.doubleToLongBits(1.0 / 3.0 * 3));
System.out.println(Double.doubleToLongBits(1d));
System.out.println(Double.doubleToLongBits(0.99999999999999999d));

节目:

4607182418800017408
4607182418800017408
4607182418800017408

答案 1 :(得分:1)

我修改了你的程序以显示确切的值,没有输出舍入。 Set found = Range("A:A").Find(what:=DatetoRun, LookIn:=xlFormulas, lookat:=xlPart) 对于探究BigDecimal的行为非常有用。

double

输出结果为:

import java.math.BigDecimal;

public class Test {
  public static void main(String[] args) {
    double numerator = 1.0;
    double denominator = 3.0;
    double result = numerator / denominator;
    System.out.printf("1 / 3 = %s \n", new BigDecimal(result));
    double multiplied = result * 3;
    System.out.printf("3 * (1/3) = %s \n", new BigDecimal(multiplied));
    BigDecimal exactMultiplied = new BigDecimal(result).multiply(new BigDecimal(3));
    System.out.println(exactMultiplied);
    BigDecimal upError = BigDecimal.ONE.subtract(exactMultiplied);
    System.out.printf("Error on round up %s \n", upError);
    BigDecimal downError = exactMultiplied.subtract(new BigDecimal(Math.nextDown(1.0)));
    System.out.printf("Error on round down %s \n", downError);
  }
}

乘以3的结果恰好是介于1.0和最大双倍之间的一半,小于1.0。在这种情况下,圆形到均匀的规则发挥作用。 1.0的有效数字的最低有效位为零,因此1.0就是答案。圆形到偶数规则确实倾向于支持整数和其他整数数字而不是邻居。

答案 2 :(得分:0)

0.333333已经四舍五入。

double存储在三个部分,sign,exponent和fraction

double

实际上,1/3存储为0x3FD5555555555555,不等于0.333333,而是3.33333333333333314829616256247E-1。

即使它已经四舍五入,它也足够准确,因此这个数字* 3等于1