一个 Java 的问题,我不理解 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
sisi041
V2EX    Java

一个 Java 的问题,我不理解

  •  
  •   sisi041 2024-03-21 21:46:48 +08:00 3991 次点击
    这是一个创建于 633 天前的主题,其中的信息可能已经有所发展或是发生改变。
    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  
       2024-03-21 21:52:11 +08:00
    因为 double 是整型,你得用 float 浮点数
    rimwindy
        2
    rimwindy  
       2024-03-21 22:09:20 +08:00   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  
       2024-03-21 22:09:23 +08:00
    java 中的 double 是一个 64 位的 IEEE 754 浮点数,这使得它在很多情况下足够精确,但对于某些数值,例如 0.57 ,就会出现这种舍入误差。
    wenhuibrave
        4
    wenhuibrave  
       2024-03-21 22:10:34 +08:00
    想要输出-57 ,可以用 BigDecimal 表示,避免传统的浮点数舍入误差。
    Curtion
        6
    Curtion  
       2024-03-21 22:21:59 +08:00


    因为 IEEE 754
    sisi041
        7
    sisi041  
    OP
       2024-03-21 23:33:37 +08:00
    @wenhuibrave 如果不用 BigDecimal , 我 Math.round 一下,是不是也可以解决?
    me1onsoda
        8
    me1onsoda  
       2024-03-21 23:36:08 +08:00
    @cococaoliug double 是双精度浮点型。。
    hapeman
        9
    hapeman  
       2024-03-21 23:54:28 +08:00   1
    计算机实际存储是通过二进制进行的,所以存储非整型的数据时允许存在一定的误差
    所以你输入的其实是一个近似于-0.57 的二进制数,你*100 之后就出现了丢失经度的情况
    这一情况可以通过使用 BigDecimal 解决,需要注意的是在使用 BigDecimal 的构造函数初始化一个值的时候使用 String 类型而不是 Double ,使用 Double 也会丢失精度
    在设计金额之类字段的时候一定不能使用 Double 、Float 等类型,请使用 BigDecimal
    andrewpsy
        10
    andrewpsy  
       2024-03-22 07:30:20 +08:00
    对待楼主这种情况:
    1. 如果有 BigDecimal 这类带精度的数值 type 那必须用。
    2. 没有精度 type 的话尽量不用或少用除法。比如想把 2600 秒换算成分钟,尽量一直用秒甚至毫秒表示,这样不涉及除法。实在需要除法(想得到小时为单位的答案)就尽量整合除法只除一次。比如把 2600 秒/60/60=?小时变成 2600/(60*60),这时 round 只出现一次除法误差。
    nitmali
        11
    nitmali  
       2024-03-22 09:05:27 +08:00
    System.out.println(0.1 + 0.2);
    githmb
        12
    githmb  
       2024-03-22 10:05:53 +08:00
    balalaFairty
        13
    balalaFairty  
       2024-03-22 11:34:22 +08:00
    @sisi041 『如果不用 BigDecimal , 我 Math.round 一下,是不是也可以解决?』不能应对所有情况,不推荐这么做。如果你的应用场景里小数点只有 2 位,不涉及与其他浮点数的运算,并且下限不超过 [2^63-1, -2^63],你可以底层存储的时候改成 long 来存储和计算,最后展示输出的时候再除以 100 ,这样可以在大部分场景下避免使用 BigDecimal 。
    sisi041
        14
    sisi041  
    OP
       2024-03-22 12:19:44 +08:00 via Android
    @balalaFairty 明白了,多谢
    vituralfuture
        15
    vituralfuture  
       2024-03-22 17:33:31 +08:00 via Android
    复习一下计算机组成原理就明白了,典型的浮点数误差,另外比较两个浮点数相等也一般不用==,而是判断两者差值是否足够小
    hkdcl
        16
    hkdcl  
       2024-03-24 22:22:27 +08:00 via Android
    @cococaoliug 我支持你,op 太菜了
    lixiaolin123
        17
    lixiaolin123  
       2024-09-03 20:03:47 +08:00
    Effective Java, Third Edition -Item 60: Avoid float and double if exact answers are required
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3232 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 11:23 PVG 19:23 LAX 03:23 JFK 06:23
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86