为什么java + =得到错误的结果,我该如何防止这种情况?

时间:2016-06-02 02:47:23

标签: java

为什么java +=得到错误的结果,我该如何防止这个问题? (例如在IDE中以任何方式显示warning?)

我试过eclipse& IntelliJ但都没有显示任何警告。

示例代码:

    {
        long a = 20000000000000000L;
        double b = 90.0;
        a += b;
        System.out.println(a); // 20000000000000088 NG
    }

    {
        long a = 10000000000000000L;
        double b = 90.0;
        a += b;
        System.out.println(a); // 10000000000000090 OK
    }

    {
        long a = 20000000000000000L;
        double b = 90.0;
        a += (long) b;
        System.out.println(a); // 20000000000000090 OK
    }

3 个答案:

答案 0 :(得分:10)

根据JLS,compound assignment expression

a += b;

相当于

a = (long) (a + b);

由于bdoublebinary numeric promotion会在添加发生之前发生。两个操作数都转换为double值,并且使用浮点运算进行加法。

20000000000000090无法完全表示为double,因此您会失去精确度,而是获得20000000000000088。然后它会被转换回long,它具有足够的精度来表示20000000000000088

您的第二个代码段生成10000000000000090,可以完全表示为double

您的第三个代码段相当于

a = (long) (a + (long) b);

使用integer arithmetic20000000000000090可以表示为long

我不知道有任何工具可以警告你。

相关:

答案 1 :(得分:1)

Java使用64-bit IEEE floating point numbers,它使用53个二进制数字来表示重要数字。在第一个例子中,

import pymongo
db_connect = pymongo.MongoClient('192.168.4.202', 20020)
database_name = 'MY_DATABASE_NAME'
database = db_connect[database_name]
collection = database.collection_names(include_system_collections=False)
for collect in collection:
    print collect

此处变量{ long a = 20000000000000000L; double b = 90.0; a += b; System.out.println(a); // 20000000000000088 NG } 将转换为必须使用大于1的指数来表示它的double,并且它将不再是值20000000000000000L的精确表示。

在此示例中,可以仅使用有效数和指数为1来表示a

a

在此示例中,{ long a = 10000000000000000L; double b = 90.0; a += b; System.out.println(a); // 10000000000000090 OK } 显式转换为long,从而无需将b转换为double并执行浮点运算。

a

答案 2 :(得分:0)

并非所有程序员(像我一样)都能理解binary numeric promotion

为防止此类COMPGED编码丢失,我找到了一种简单的方法:只禁止所有+=作为编码规则。

我只是在我的项目中点击所有+=,然后将+=更改为a += b

IDE在a = a + b操作时类型不匹配时显示错误,如下所示:

IDE show compile errors