一个 Java 的问题,我不理解 - V2EX
sisi041
V2EX    Java

一个 Java 的问题,我不理解

  •  
  •   sisi041 Mar 21, 2024 5571 views
    This topic created in 787 days ago, the information mentioned may be changed or developed.
    public static void main(String[] args) {
    Double a=-0.57;
    a=a*100;
    System.out.println(a);
    }

    为啥打印出来的不是 -57 ?
    17 replies    2024-09-03 20:03:47 +08:00
    cococaoliug
        1
    cococaoliug  
       Mar 21, 2024
    因为 double 是整型,你得用 loat 浮点数
    rimwindy
        2
    rimwindy  
       Mar 21, 2024   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  
       Mar 21, 2024
    java 中的 double 是一个 64 位的 IEEE 754 浮点数,这使得它在很多情况下足够精确,但对于某些数值,例如 0.57 ,就会出现这种舍入误差。
    wenhuibrave
        4
    wenhuibrave  
       Mar 21, 2024
    想要输出-57 ,可以用 BigDecimal 表示,避免传统的浮点数舍入误差。
    Curtion
        6
    Curtion  
       Mar 21, 2024


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