V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
sisi041
V2EX  ›  Java

一个 Java 的问题,我不理解

  •  
  •   sisi041 · 281 天前 · 2886 次点击
    这是一个创建于 281 天前的主题,其中的信息可能已经有所发展或是发生改变。
    public static void main(String[] args) {
    Double a=-0.57;
    a=a*100;
    System.out.println(a);
    }

    为啥打印出来的不是 -57 ?
    17 条回复    2024-09-03 20:03:47 +08:00
    cococaoliug
        1
    cococaoliug  
       281 天前
    因为 double 是整型,你得用 float 浮点数
    rimwindy
        2
    rimwindy  
       281 天前   ❤️ 1
    ```
    jshell> Double a = -0.57; System.out.println(a * 100);
    a ==> -0.57
    -56.99999999999999
    ```

    你指的是浮点数溢出吗?正如十进制无法精确表示 1/3 、1/6 、1/7 、1/9 一样,因为二进制中唯一的质因数是 2 ,所以只能精确表示 1/2 、1/4 、1/8 这样的数。
    wenhuibrave
        3
    wenhuibrave  
       281 天前
    java 中的 double 是一个 64 位的 IEEE 754 浮点数,这使得它在很多情况下足够精确,但对于某些数值,例如 0.57 ,就会出现这种舍入误差。
    wenhuibrave
        4
    wenhuibrave  
       281 天前
    想要输出-57 ,可以用 BigDecimal 表示,避免传统的浮点数舍入误差。
    Curtion
        6
    Curtion  
       281 天前


    因为 IEEE 754
    sisi041
        7
    sisi041  
    OP
       280 天前
    @wenhuibrave 如果不用 BigDecimal , 我 Math.round 一下,是不是也可以解决?
    me1onsoda
        8
    me1onsoda  
       280 天前
    @cococaoliug double 是双精度浮点型。。
    hapeman
        9
    hapeman  
       280 天前   ❤️ 1
    计算机实际存储是通过二进制进行的,所以存储非整型的数据时允许存在一定的误差
    所以你输入的其实是一个近似于-0.57 的二进制数,你*100 之后就出现了丢失经度的情况
    这一情况可以通过使用 BigDecimal 解决,需要注意的是在使用 BigDecimal 的构造函数初始化一个值的时候使用 String 类型而不是 Double ,使用 Double 也会丢失精度
    在设计金额之类字段的时候一定不能使用 Double 、Float 等类型,请使用 BigDecimal
    andrewpsy
        10
    andrewpsy  
       280 天前
    对待楼主这种情况:
    1. 如果有 BigDecimal 这类带精度的数值 type 那必须用。
    2. 没有精度 type 的话尽量不用或少用除法。比如想把 2600 秒换算成分钟,尽量一直用秒甚至毫秒表示,这样不涉及除法。实在需要除法(想得到小时为单位的答案)就尽量整合除法只除一次。比如把 2600 秒/60/60=?小时变成 2600/(60*60),这时 round 只出现一次除法误差。
    nitmali
        11
    nitmali  
       280 天前
    System.out.println(0.1 + 0.2);
    githmb
        12
    githmb  
       280 天前
    balalaFairty
        13
    balalaFairty  
       280 天前
    @sisi041 『如果不用 BigDecimal , 我 Math.round 一下,是不是也可以解决?』不能应对所有情况,不推荐这么做。如果你的应用场景里小数点只有 2 位,不涉及与其他浮点数的运算,并且下限不超过 [2^63-1, -2^63],你可以底层存储的时候改成 long 来存储和计算,最后展示输出的时候再除以 100 ,这样可以在大部分场景下避免使用 BigDecimal 。
    sisi041
        14
    sisi041  
    OP
       280 天前 via Android
    @balalaFairty 明白了,多谢
    vituralfuture
        15
    vituralfuture  
       280 天前 via Android
    复习一下计算机组成原理就明白了,典型的浮点数误差,另外比较两个浮点数相等也一般不用==,而是判断两者差值是否足够小
    hkdcl
        16
    hkdcl  
       278 天前 via Android
    @cococaoliug 我支持你,op 太菜了
    lixiaolin123
        17
    lixiaolin123  
       115 天前
    Effective Java, Third Edition -Item 60: Avoid float and double if exact answers are required
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2723 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 14:39 · PVG 22:39 · LAX 06:39 · JFK 09:39
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.