成人欧美一区二区三区的电影,日韩一级一欧美一级国产,国产成人国拍亚洲精品,无码人妻精品一区二区三区毛片,伊人久久无码大香线蕉综合

LOGO OA教程 ERP教程 模切知識(shí)交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

為什么不該用 Double 表示金額及解決方案

freeflydom
2025年10月11日 8:33 本文熱度 486

眾所周知,double 和 float 這些浮點(diǎn)數(shù)其實(shí)是不精確的。

比如 0.1 + 0.2 并不等于 0.3,而是等于 0.30000000000000004——這也一度成為程序員圈子里的經(jīng)典梗。所以用浮點(diǎn)數(shù)表示金額這種需要精確計(jì)算的數(shù)值,是會(huì)出現(xiàn)精度丟失問題的。

double a = 0.1;
double b = 0.2;
System.out.println(a + b);  // 輸出: 0.30000000000000004
System.out.println(a + b == 0.3);  // 輸出: false

再看一個(gè)更實(shí)際的例子,假設(shè)你在做一個(gè)電商系統(tǒng)的金額計(jì)算:

double price = 2.0;
double discount = 0.9;
System.out.println(price * discount);  // 輸出: 1.7999999999999998

你看,原本應(yīng)該是 1.8 的結(jié)果,卻變成了 1.7999999999999998。如果這是真實(shí)的訂單金額,那可就出大問題了

為什么會(huì)精度丟失

為什么會(huì)有這種精度丟失呢?因?yàn)橛?jì)算機(jī)底層都是用二進(jìn)制存儲(chǔ)的,但并不是所有十進(jìn)制數(shù)都能用二進(jìn)制精確表示。各位有興趣的話可以試著算一下 0.1 的二進(jìn)制是多少,算出來可以在評(píng)論區(qū)分享一下。

算了一會(huì)你可能會(huì)發(fā)現(xiàn):這怎么算不完?沒錯(cuò),出現(xiàn)了無限循環(huán)的情況——(0.1)?? = (0.000110011001100...)? 像這種情況,計(jì)算機(jī)就沒辦法用二進(jìn)制精確表示 0.1 了。

而 double 類型在 Java 中占 64 位,按照 IEEE 754 標(biāo)準(zhǔn),其中 1 位是符號(hào)位,11 位是指數(shù)位,52 位是尾數(shù)位。當(dāng)遇到無限循環(huán)的二進(jìn)制小數(shù)時(shí),只能截?cái)啾4?這就導(dǎo)致了精度丟失。

BigDecimal

在 Java 中,無論是單精度還是雙精度,表示的都是近似值。

為了表示精確的小數(shù)值,Java 提供了 BigDecimal 類型。BigDecimal 由兩個(gè)部分組成:無標(biāo)度值(unscaled value)和標(biāo)度(scale)。無標(biāo)度值是一個(gè)整數(shù),表示實(shí)際的數(shù)值;標(biāo)度也是一個(gè)整數(shù),表示小數(shù)點(diǎn)后的位數(shù)。

舉個(gè)例子,數(shù)字 123.45 在 BigDecimal 中:

  • 無標(biāo)度值是 12345
  • 標(biāo)度是 2

實(shí)際值就是:12345 × 10?2 = 123.45

用 BigDecimal 來處理剛才的金額計(jì)算:

BigDecimal price = new BigDecimal("2.0");
BigDecimal discount = new BigDecimal("0.9");
BigDecimal result = price.multiply(discount);
System.out.println(result);  // 輸出: 1.80

這下結(jié)果就對(duì)了

equals 的坑

在 BigDecimal 中不能用 equals 方法做等值比較,因?yàn)?equals 會(huì)同時(shí)比較無標(biāo)度值和標(biāo)度這兩個(gè)內(nèi)容。

BigDecimal a = new BigDecimal("0.1");
BigDecimal b = new BigDecimal("0.10");
System.out.println(a.equals(b));  // 輸出: false

我們都知道 0.1 和 0.10 在數(shù)值上是相等的,但 equals 的結(jié)果卻是 false。這是因?yàn)?

  • a 的無標(biāo)度值是 1,標(biāo)度是 1
  • b 的無標(biāo)度值是 10,標(biāo)度是 2

雖然值相同,但它們的標(biāo)度不同,所以 equals 返回 false。

compareTo

比較 BigDecimal 大小時(shí)應(yīng)該使用 compareTo 方法,返回值為 1、-1、0,分別代表大于、小于、等于。

BigDecimal a = new BigDecimal("0.1");
BigDecimal b = new BigDecimal("0.10");
System.out.println(a.compareTo(b));  // 輸出: 0,表示相等
BigDecimal c = new BigDecimal("0.2");
System.out.println(a.compareTo(c));  // 輸出: -1,表示 a < c
System.out.println(c.compareTo(a));  // 輸出: 1,表示 c > a

創(chuàng)建 BigDecimal 的正確姿勢(shì)

創(chuàng)建 BigDecimal 時(shí),建議使用 String 類型的構(gòu)造方法,也就是 new BigDecimal("0.1") 這樣。

BigDecimal right = new BigDecimal("0.1");
System.out.println(right);  // 輸出: 0.1
BigDecimal wrong = new BigDecimal(0.1);
System.out.println(wrong);  // 輸出: 0.1000000000000000055511151231257827021181583404541015625

如果你用了 new BigDecimal(0.1) 的方式,創(chuàng)建出來的值其實(shí)也不是 0.1,而是一個(gè)近似值。這是因?yàn)閭魅氲?double 本身就已經(jīng)是近似值了,BigDecimal 只是忠實(shí)地把這個(gè)近似值保存下來而已。

還有一個(gè)更方便的方法:
BigDecimal bd = BigDecimal.valueOf(0.1);
System.out.println(bd);  // 輸出: 0.1

valueOf 方法內(nèi)部會(huì)先把 double 轉(zhuǎn)成 String,再調(diào)用 String 構(gòu)造方法,所以也是安全的。

常用的 BigDecimal 運(yùn)算

BigDecimal a = new BigDecimal("10.5");
BigDecimal b = new BigDecimal("2.3");
// 加法
System.out.println(a.add(b));  // 12.8
// 減法
System.out.println(a.subtract(b));  // 8.2
// 乘法
System.out.println(a.multiply(b));  // 24.15
// 除法(需要指定精度和舍入模式)
System.out.println(a.divide(b, 2, RoundingMode.HALF_UP));  // 4.57

注意除法操作時(shí),如果不指定精度,遇到除不盡的情況會(huì)拋出 ArithmeticException。所以建議都加上精度和舍入模式。

總之,涉及金額計(jì)算時(shí),千萬別圖省事用 double,老老實(shí)實(shí)用 BigDecimal 才是王道。


轉(zhuǎn)自https://www.cnblogs.com/longlonglong777/p/19133663


該文章在 2025/10/11 8:33:59 編輯過
關(guān)鍵字查詢
相關(guān)文章
正在查詢...
點(diǎn)晴ERP是一款針對(duì)中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國(guó)內(nèi)大量中小企業(yè)的青睞。
點(diǎn)晴PMS碼頭管理系統(tǒng)主要針對(duì)港口碼頭集裝箱與散貨日常運(yùn)作、調(diào)度、堆場(chǎng)、車隊(duì)、財(cái)務(wù)費(fèi)用、相關(guān)報(bào)表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點(diǎn),圍繞調(diào)度、堆場(chǎng)作業(yè)而開發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點(diǎn)晴WMS倉(cāng)儲(chǔ)管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購(gòu)管理,倉(cāng)儲(chǔ)管理,倉(cāng)庫(kù)管理,保質(zhì)期管理,貨位管理,庫(kù)位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號(hào)管理軟件。
點(diǎn)晴免費(fèi)OA是一款軟件和通用服務(wù)都免費(fèi),不限功能、不限時(shí)間、不限用戶的免費(fèi)OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved