Java中的数学 - 不同对象的不同结果

Joe*_*oel 4 java math

我正在为我正在处理的应用程序计算得到一些奇怪的结果,我认为这里的某个人可能能够帮助弄清楚发生了什么.

此特定计算的要求表明计算应如下所示:

A和B是已知的

A * B = C
Run Code Online (Sandbox Code Playgroud)

对于这个特定的计算

A = 0.0410
B = 123456789010
Run Code Online (Sandbox Code Playgroud)

以下是我看到的结果:

计算器:

0.0410 * 123456789010 = 5061728349.41
Run Code Online (Sandbox Code Playgroud)

Java的:

B是双:

0.0410f * 123456789010d = 5.061728489223363E9 = 5061728489.223363
Run Code Online (Sandbox Code Playgroud)

B很长:

0.0410f * 123456789010l = 5.0617288E9 
Run Code Online (Sandbox Code Playgroud)

对于我来说,精度的损失并不重要(我只需要9位数的精度),而不是10s和1s点的差异.为什么使用double进行计算会给出"错误"结果?

顺便说一句,我尝试使用计算进行计算,BigDecimal并得到与使用double时相同的结果.

ass*_*ias 6

发生的各种类型转换由JLS#5.6.2指定.在你的情况下(摘录):

  • 如果任一操作数的类型为double,则另一个操作数转换为double.
  • 否则,如果任一操作数的类型为float,则另一个操作数转换为float.

In 0.0410f * 123456789010d = 506172848.9223363,0.0410f首先转换为不一定等于的double 0.0410d.实际上你可以尝试一下,看看那不是:

    double d1 = 0.041d;
    double d2 = 0.041f;
    System.out.println(new BigDecimal(d1));
    System.out.println(new BigDecimal(d2));
Run Code Online (Sandbox Code Playgroud)

输出:

0.041000000000000001720845688168992637656629085540771484375
0.041000001132488250732421875

在下一个示例中:

0.0410f * 123456789010L = 506172832
Run Code Online (Sandbox Code Playgroud)

long被转换为float,您可以使用此示例进行验证:

    float f1 = 0.0410f;
    float f2 = 123456789010L;
    System.out.println(new BigDecimal(f1)); // 0.041000001132488250732421875
    System.out.println(new BigDecimal(f2)); // 123456790528
    System.out.println(new BigDecimal(0.0410f * 123456789010L)); // 5061728768
    System.out.println(new BigDecimal(f1 * f2)); // 5061728768
Run Code Online (Sandbox Code Playgroud)

至于浮动/双重操作的精度,请检查这个问题.

最后,如果你使用BigDecimal,你会得到正确的答案:

    BigDecimal a = new BigDecimal("0.041");
    BigDecimal b = new BigDecimal("123456789010");
    System.out.println(a.multiply(b)); // outputs 5061728349.410
Run Code Online (Sandbox Code Playgroud)