java浮點數(shù)金額精確計算_第1頁
java浮點數(shù)金額精確計算_第2頁
java浮點數(shù)金額精確計算_第3頁
java浮點數(shù)金額精確計算_第4頁
java浮點數(shù)金額精確計算_第5頁
已閱讀5頁,還剩10頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、個人收集整理 僅供參考學(xué)習(xí)Java 浮點數(shù)的精確計算及表示(1) 、浮點數(shù)精確計算 項目中一直存在一個問題,就是每次報表統(tǒng)計的物資金額和實際的金額要差那么幾分 錢,和實際金額不一致,讓客戶覺得總是不那么舒服,原因是因為我們使用 java 的浮 點類型 double 來定義物資金額,并且在報表統(tǒng)計中我們經(jīng)常要進行一些運算,但 Java 中浮點數(shù)( double 、float )的計算是非精確計算,請看下面一個例子:System.out.println(0.05 + 0.01);System.out.println(1.0 - 0.42);System.out.println(4.015 * 10

2、0);System.out.println(123.3 / 100);你的期望輸出是什么?可實際的輸出確實這樣的:0.0600000000000000050.5800000000000001401.499999999999941.2329999999999999這個問題就非常嚴重了,如果你有 123.3 元要購買商品,而計算機卻認為你只有 123.29999999999999 元,錢不夠,計算機拒絕交易。(2) 、四舍五入 是否可以四舍五入呢?當然可以,習(xí)慣上我們本能就會這樣考慮,但四舍五入意味著誤 差,商業(yè)運算中可能意味著錯誤,同時 Java 中也沒有提供保留指定位數(shù)的四舍五入方 法,只提供

3、了一個 Math.round(double d) 和 Math.round(float f) 的方法,分別返回長整型 和整型值。 round 方法不能設(shè)置保留幾位小數(shù),我們只能象這樣(保留兩位):public double round(double value)return Math.round( value * 100 ) / 100.0;但非常不幸的是,上面的代碼并不能正常工作,給這個方法傳入 4.015 它將返回 4.01 而不是 4.02 ,如我們在上面看到的4.015 * 100 = 401.49999999999994個人收集整理 僅供參考學(xué)習(xí)因此如果我們要做到精確的四舍五入,這種

4、方法不能滿足我們的要求。還有一種方式是使用 java.text.DecimalFormat ,但也存在問題, format 采用的舍入模式 是 ROUND_HALF_DOWN (舍入模式在下面有介紹),比如說 4.025 保留兩位小數(shù)會 是4.02,因為.025 距離” nearest neighbor ( .”02 和.03)長度是相等,向下舍入就是 .02, 如果是 4.0251 那么保留兩位小數(shù)就是 4.03 。System.out.println(new java.text.DecimalFormat(0.00).format(4.025);System.out.println(new

5、 java.text.DecimalFormat(0.00).format(4.0251);輸出是4.024.03(3) 、浮點數(shù)輸出(科學(xué)記數(shù)法)Java 浮點型數(shù)值在大于 9999999.0 就自動轉(zhuǎn)化為科學(xué)記數(shù)法來表示,我們看下面的例 子:System.out.println(999999999.04);System.out.println(99999999.04);System.out.println(10000000.01);System.out.println(9999999.04);輸出的結(jié)果如下:9.9999999904E89.999999904E71.000000001E79

6、999999.04但有時我們可能不需要科學(xué)記數(shù)法的表示方法,需要轉(zhuǎn)換為字符串,還不能直接用 toString() 等方法轉(zhuǎn)換,很煩瑣。BigDecimal 介紹BigDecimal 是 Java 提供的一個不變的、任意精度的有符號十進制數(shù)對象。它提供了四個人收集整理 僅供參考學(xué)習(xí)個構(gòu)造器,有兩個是用 BigInteger 構(gòu)造,在這里我們不關(guān)心,我們重點看用 double 和 String 構(gòu)造的兩個構(gòu)造器(有關(guān) BigInteger 詳細介紹請查閱 j2se API 文檔)。BigDecimal(double val)Translates a double into a BigDecimal

7、.BigDecimal(String val)Translates the String representation of a BigDecimal into a BigDecimal.BigDecimal(double) 是把一個 double 類型十進制數(shù)構(gòu)造為一個 BigDecimal 對象實例。 BigDecimal(String) 是把一個以 String 表示的 BigDecimal 對象構(gòu)造為 BigDecimal 對象 實例。習(xí)慣上,對于浮點數(shù)我們都會定義為 double 或 float ,但 BigDecimal API 文檔中對于 BigDecimal(double) 有

8、這么一段話:Note: the results of this constructor can be somewhat unpredictable. One might assume that new BigDecimal(.1) is exactly equal to .1, but it is actually equal to .10000000000000000555111512312578 27021181583404541015625. This is so because .1 cannot be represented exactly as a double (or, for

9、that matter, as a binary fraction of any finite length). Thus, the long value that is being passed in to the constructor is not exactly equal to .1, appearances notwithstanding.The (String) constructor, on the other hand, is perfectly predictable: new BigDecimal(.1) is exactly equal to .1, as one wo

10、uld expect. Therefore, it is generally recommended that the (String) constructor be used in preference to this one 下面對這段話做簡單解釋: 注意:這個構(gòu)造器的結(jié)果可能會有不可預(yù)知的結(jié)果。有人可能設(shè)想 new BigDecimal(.1) 等于.1 是正確的,但它實際上是等 于.1000000000000000055511151231257827021181583404541015625,這就是為什么.1 不能用一個 double 精確表示的原因,因此,這個被放進構(gòu)造器中的長值并不

11、精確 的等于 .1,盡管外觀看起來是相等的。然而( String )構(gòu)造器,則完全可預(yù)知的, new BigDecimal( “ .1 ”如)同期望的那樣精確的 等于.1,因此,( String )構(gòu)造器是被優(yōu)先推薦使用的。看下面的結(jié)果:System.out.println(new BigDecimal(123456789.02).toString();個人收集整理 僅供參考學(xué)習(xí)System.out.println(new BigDecimal(123456789.02).toString();輸出為:123456789.01999999582767486572265625123456789.

12、02現(xiàn)在我們知道,如果需要精確計算,非要用 String 來夠造 BigDecimal 不可!實現(xiàn)方案 現(xiàn)在我們已經(jīng)知道怎么解決這個問題了,原則上是使用 BigDecimal ( String )構(gòu)造器, 我們建議,在商業(yè)應(yīng)用開發(fā)中,涉及金額等浮點數(shù)計算的數(shù)據(jù),全部定義為 String ,數(shù) 據(jù)庫中可定義為字符型字段,在需要使用這些數(shù)據(jù)進行運算的時候,使用BigDecimal(String )構(gòu)造 BigDecimal 對象進行運算,保證數(shù)據(jù)的精確計算。同時避免了科學(xué)記數(shù) 法的出現(xiàn) 。如果科學(xué)記數(shù)表示法在應(yīng)用中不是一種負擔的話 ,可以考慮定義為浮點類型 。這里我們提供了一個工具類,定義浮點數(shù)的

13、加、減、乘、除和四舍五入等運算方法。以 供參考。源文件 MathExtend.java :import java.math.BigDecimal;public class MathExtend/默認除法運算精度private static final int DEFAULT_DIV_SCALE = 10;/* 提供精確的加法運算。* param v1* param v2* return 兩個參數(shù)的和*/public static double add(double v1, double v2)個人收集整理 僅供參考學(xué)習(xí)BigDecimal b1 = new BigDecimal(Double.

14、toString(v1);BigDecimal b2 = new BigDecimal(Double.toString(v2);return b1.add(b2).doubleValue();/* 提供精確的加法運算* param v1* param v2* return 兩個參數(shù)數(shù)學(xué)加和,以字符串格式返回*/public static String add(String v1, String v2) BigDecimal b1 = new BigDecimal(v1);BigDecimal b2 = new BigDecimal(v2); return b1.add(b2).toString

15、();/*提供精確的減法運算param v1param v2return 兩個參數(shù)的差*/public static double subtract(double v1, double v2)個人收集整理 僅供參考學(xué)習(xí)BigDecimal b1 = new BigDecimal(Double.toString(v1);BigDecimal b2 = new BigDecimal(Double.toString(v2);return b1.subtract(b2).doubleValue();/*提供精確的減法運算param v1param v2return 兩個參數(shù)數(shù)學(xué)差,以字符串格式返回*/

16、public static String subtract(String v1, String v2) BigDecimal b1 = new BigDecimal(v1);BigDecimal b2 = new BigDecimal(v2);return b1.subtract(b2).toString(); 提供精確的乘法運算param v1param v2return 兩個參數(shù)的積個人收集整理 僅供參考學(xué)習(xí)*/public static double multiply(double v1, double v2)BigDecimal b1 = new BigDecimal(Double.t

17、oString(v1);BigDecimal b2 = new BigDecimal(Double.toString(v2);return b1.multiply(b2).doubleValue();* 提供精確的乘法運算* param v1* param v2* return 兩個參數(shù)的數(shù)學(xué)積,以字符串格式返回*/public static String multiply(String v1, String v2)BigDecimal b1 = new BigDecimal(v1);BigDecimal b2 = new BigDecimal(v2);return b1.multiply(b

18、2).toString();提供(相對)精確的除法運算,當發(fā)生除不盡的情況時,精確到小數(shù)點以后 10 位,以后的數(shù)字四舍五入 ,舍入模式采用 ROUND_HALF_EVENparam v1個人收集整理 僅供參考學(xué)習(xí)* param v2* return 兩個參數(shù)的商*/public static double divide(double v1, double v2)return divide(v1, v2, DEFAULT_DIV_SCALE);* 提供(相對)精確的除法運算。當發(fā)生除不盡的情況時,由 scale 參數(shù)指* 定精度,以后的數(shù)字四舍五入。舍入模式采用 ROUND_HALF_EVEN

19、* param v1* param v2* param scale 表示需要精確到小數(shù)點以后幾位。* return 兩個參數(shù)的商*/public static double divide(double v1,double v2, int scale)return divide(v1, v2, scale, BigDecimal.ROUND_HALF_EVEN);提供(相對)精確的除法運算。當發(fā)生除不盡的情況時,由 scale 參數(shù)指定精度,以后的數(shù)字四舍五入。舍入模式采用用戶指定舍入模式param v1個人收集整理 僅供參考學(xué)習(xí)* param v2* param scale 表示需要精確到小數(shù)

20、點以后幾位* param round_mode 表示用戶指定的舍入模式* return 兩個參數(shù)的商*/public static double divide(double v1,double v2,int scale, int round_mode)if(scale 0)throw new IllegalArgumentException(The scale must be a positive integer or zero);BigDecimal b1 = new BigDecimal(Double.toString(v1);BigDecimal b2 = new BigDecimal(

21、Double.toString(v2);return b1.divide(b2, scale, round_mode).doubleValue();提供(相對)精確的除法運算,當發(fā)生除不盡的情況時,精確到小數(shù)點以后 10 位,以后的數(shù)字四舍五入 ,舍入模式采用 ROUND_HALF_EVENparam v1param v2return 兩個參數(shù)的商,以字符串格式返回*/public static String divide(String v1, String v2)return divide(v1, v2, DEFAULT_DIV_SCALE);個人收集整理 僅供參考學(xué)習(xí)提供(相對)精確的除法

22、運算。當發(fā)生除不盡的情況時,由 scale 參數(shù)指定精度,以后的數(shù)字四舍五入。舍入模式采用 ROUND_HALF_EVEN* param v1* param v2* param scale 表示需要精確到小數(shù)點以后幾位* return 兩個參數(shù)的商,以字符串格式返回*/public static String divide(String v1, String v2, int scale)return divide(v1, v2, DEFAULT_DIV_SCALE,BigDecimal.ROUND_HALF_EVEN);提供(相對)精確的除法運算。當發(fā)生除不盡的情況時,由 scale 參數(shù)指定

23、精度,以后的數(shù)字四舍五入。舍入模式采用用戶指定舍入模式param v1param v2param scale 表示需要精確到小數(shù)點以后幾位param round_mode 表示用戶指定的舍入模式return 兩個參數(shù)的商,以字符串格式返回*/public static String divide(String v1, String v2, int scale, int round_mode)個人收集整理 僅供參考學(xué)習(xí)if(scale 0)throw new IllegalArgumentException(The scale must be a positive integer or zero

24、);BigDecimal b1 = new BigDecimal(v1);BigDecimal b2 = new BigDecimal(v2);return b1.divide(b2, scale, round_mode).toString();提供精確的小數(shù)位四舍五入處理 ,舍入模式采用 ROUND_HALF_EVENparam v 需要四舍五入的數(shù)字param scale 小數(shù)點后保留幾位return 四舍五入后的結(jié)果*/public static double round(double v,int scale)return round(v, scale, BigDecimal.ROUND

25、_HALF_EVEN);/* 提供精確的小數(shù)位四舍五入處理* param v 需要四舍五入的數(shù)字* param scale 小數(shù)點后保留幾位param round_mode 指定的舍入模式個人收集整理 僅供參考學(xué)習(xí)* return 四舍五入后的結(jié)果*/public static double round(double v, int scale, int round_mode)if(scale0)throw new IllegalArgumentException(The scale must be a positive integer or zero);BigDecimal b = new B

26、igDecimal(Double.toString(v);return b.setScale(scale, round_mode).doubleValue();提供精確的小數(shù)位四舍五入處理 ,舍入模式采用 ROUND_HALF_EVENparam v 需要四舍五入的數(shù)字param scale 小數(shù)點后保留幾位return 四舍五入后的結(jié)果,以字符串格式返回*/public static String round(String v, int scale)return round(v, scale, BigDecimal.ROUND_HALF_EVEN);/*提供精確的小數(shù)位四舍五入處理param

27、 v 需要四舍五入的數(shù)字個人收集整理 僅供參考學(xué)習(xí)* param scale 小數(shù)點后保留幾位* param round_mode 指定的舍入模式* return 四舍五入后的結(jié)果,以字符串格式返回*/public static String round(String v, int scale, int round_mode)if(scale0)throw new IllegalArgumentException(The scale must be a positive integer or zero);BigDecimal b = new BigDecimal(v);return b.set

28、Scale(scale, round_mode).toString();BigDecimal 舍入模式( Rounding mode )介紹:BigDecimal 定義了一下舍入模式,只有在作除法運算或四舍五入時才用到舍入模式, 下面簡單介紹,詳細請查閱 J2se API 文檔static int ROUND_CEILINGRounding mode to round towards positive infinity.向正無窮方向舍入static int ROUND_DOWNRounding mode to round towards zero.向零方向舍入個人收集整理 僅供參考學(xué)習(xí)stat

29、ic intROUND_FLOORRounding mode to round towards negative infinity.向負無窮方向舍入static int ROUND_HALF_DOWNRounding mode to round towards nearest neighbor unless both neighbors are equidistant, in which case round down.向(距離)最近的一邊舍入,除非兩邊(的距離)是相等,如果是這樣,向下舍入 , 例如1.55 保留一位小數(shù)結(jié)果為 1.5static intROUND_HALF_EVENRounding mode to round towards the nearest neighbor unless both neighbors are equidistant, in which case, round towards the even neighbor.向(距離)最近的一邊舍入,除

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論