双原始类型数据的意外行为 [英] Unexpected behavior of double primitive type data

查看:264
本文介绍了双原始类型数据的意外行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想了解Java double 类型如何将其值存储在Java中的内存中。
当我运行下面的代码时,我得到了意想不到的输出:

pre $ public static void main(String [] args){

float a = 1.5f;
float b = 0.5f;
double c = 1.5;
double d = 0.5;

float a1 = 1.4f;
float b1 = 0.5f;
double c1 = 1.4;
double d1 = 0.5;

System.out.println(a- b是+(a-b));
System.out.println(c-d is+(c-d));
System.out.println(a1-b1 is+(a1-b1));
System.out.println(c1-d1 is+(c1-d1));

}



输出:

 
a- b是1.0
c- d是1.0
a1-b1是0.9
c1-d1是0.8999999999999999

为什么 c1-d1 不等于 0.9



我也尝试了其他不同的值,但是有一段时间它会返回预期的结果,有些时候不会。
虽然您可能听说过四舍五入的错误,但您可能想知道为什么在这里出现四舍五入错误。

  float a1 = 1.4f; 
float b1 = 0.5f;
double c1 = 1.4;
double d1 = 0.5;

BigDecimal(a1)+ - + new BigDecimal(b1)+is+
new BigDecimal(a1).subtract(new BigDecimal(b1) ))+或作为一个浮点数是+(a1 - b1));
System.out.println(new BigDecimal(c1)+ - + new BigDecimal(d1)+is+
new BigDecimal(c1).subtract(new BigDecimal(d1))+或作为一个双是+(c1 - d1));

打印

  1.39999997615814208984375  -  0.5是0.89999997615814208984375或作为浮点数是0.9 
1.399999999999999911182158029987476766109466552734375 - 0.5是
0.899999999999999911182158029987476766109466552734375
或作为双倍数是0.8999999999999999
/ pre>

正如你所看到的,既不是 float 也不是 double 可以精确地表示这些值,当打印浮点数或双精度数时,会发生一些舍入来将其隐藏起来。在这种浮动的情况下,四舍五入到小数点后七位产生您所期望的数字。在double精度为16位的情况下,舍入错误是可见的。



作为@Eric Postpischil,注意 float code>或 double 操作有一个舍入错误完全取决于所使用的值。在这种情况下,即使通过代表值比0.9倍还要高,也是更准确的。

简而言之:如果你打算要使用 float double ,您应该使用明智的舍入策略。如果你不能这样做,请使用BigDecimal。

  System.out.printf(a1  -  b1 is%.2f% n,(a1-b1)); 
System.out.printf(c1 - d1 is%.2f%n,(c1 - d1));

打印

  a1  -  b1是0.90 
c1 - d1是0.90

一个浮点数或双精度浮点数,它假设最接近的十进制小数点是你真正想要的。即在0.5 ulp以内。

例如

  double d = 1.4  - 0.5; 
float f = d;
System.out.println(d =+ d +f =+ f);

打印

  d = 0.8999999999999999 f = 0.9 


I want to understand how the Java double type will store its value in memory in Java. When I run the following code I get unexpected output:

public static void main(String[] args)  {

    float a = 1.5f;
    float b= 0.5f;
    double c= 1.5;
    double d = 0.5;

    float a1 = 1.4f;
    float b1= 0.5f;
    double c1= 1.4;
    double d1 = 0.5;

    System.out.println(" a- b is " + (a-b));
    System.out.println(" c- d is " + (c-d));
    System.out.println("a1-b1 is " + (a1-b1));
    System.out.println("c1-d1 is " + (c1-d1));

}

Output:

 a- b is 1.0
 c- d is 1.0
a1-b1 is 0.9
c1-d1 is 0.8999999999999999

Why is c1-d1 not equal to 0.9?

I also tried other different values but some time it return expected result and some time not.

解决方案

While you might have heard about rounding errors, you might be wondering why you have a rounding error here.

float a1 = 1.4f;
float b1 = 0.5f;
double c1 = 1.4;
double d1 = 0.5;

System.out.println(new BigDecimal(a1) + " - " + new BigDecimal(b1) + " is " +
        new BigDecimal(a1).subtract(new BigDecimal(b1)) + " or as a float is " + (a1 - b1));
System.out.println(new BigDecimal(c1) + " - " + new BigDecimal(d1) + " is " +
        new BigDecimal(c1).subtract(new BigDecimal(d1)) + " or as a double is " + (c1 - d1));

prints

1.39999997615814208984375 - 0.5 is 0.89999997615814208984375 or as a float is 0.9
1.399999999999999911182158029987476766109466552734375 - 0.5 is
     0.899999999999999911182158029987476766109466552734375 
     or as a double is 0.8999999999999999

As you can see, neither float nor double can represent these values exactly, and when the float or double is printed, some rounding occurs to hide this from you. In this case of float, the rounding to 7 decimal places yields the number you expected. In the case of double which has 16 digits of precision, the rounding error is visible.

As @Eric Postpischil, notes whether the float or double operation has a rounding error depends entirely on the values used. In this situation, it was the float which appeared to be more accurate even through the represented value was further from 0.9 than the double value.

In short: if you are going to use float or double you should use a sensible rounding strategy. If you can't do this, use BigDecimal.

System.out.printf("a1 - b1 is %.2f%n", (a1 - b1));
System.out.printf("c1 - d1 is %.2f%n", (c1 - d1));

prints

a1 - b1 is 0.90
c1 - d1 is 0.90

When you print a float or double, it assumes that the nearest short decimal value is the one you really want. i.e. within 0.5 ulp.

E.g.

double d = 1.4 - 0.5;
float f = d;
System.out.println("d = " + d + " f = " + f);

prints

d = 0.8999999999999999 f = 0.9

这篇关于双原始类型数据的意外行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆