【Java】深入探讨Java数值舍入问题
常見的舍入方式
四舍五入
我們在學習計算機科學之前,以及日常生活中,用的是四舍五入。
所謂四舍五入,就是取4即歸0,取5即歸1,這個問題與我們需要的精度有關。
在計算機科學中一般用round() 表示四舍五入。
比如0.499999,這是一個六位小數,我們想要四舍五入,就要看精度。
精確到1,結果是0
精確到0.1.結果是0.5
精確到0.01,結果是0.50
……
向上取整
向上取整是一種無視四舍五入的行為,在計算機科學中應用廣泛,意為取大于等于該數值的最小整數。
符號??,英文Ceiling,通常寫作ceil()。
英語中,ceil 的一個意思是 “天花板”,這樣我們就不難理解了。
ceil()一般應用于浮點數,如果不是浮點的話,本就是整數,有什么取整的必要呢?
比如0.499999,上整就是1
比如-0.499999,上整就是0
向下取整
向下取整是一種無視四舍五入的行為,在計算機科學中應用廣泛,意為取小于等于該數值的最大整數。
符號??,英文Floor,通常寫作floor()。
英語中,floor 的一個意思是 “地板”,這樣我們就不難理解了。
不難發現,上整和下整是恰好相反的,所以也是應用于浮點的。
比如0.499999,下整就是0
比如-0.499999,下整就是-1
不難發現,?x? - ?x? = 1
截斷取整
截斷取整是一種無視四舍五入的行為,在計算機科學中應用廣泛,意為取舍去小數點和小數點后所有數位的整數。
比如0.499999,截斷取整就是0
比如-0.499999,截斷取整也是0
向兩端取整
向兩端取整是一種無視四舍五入的行為,在計算機科學中應用廣泛,意為取臨近的∞方向的整數。
比如0.5,向兩端取整就是1
比如-0.5,向兩端取整就是-1
Math類中的舍入問題
主要有以下幾種舍入方式:
- ceil?(double a):作用是返回大于或等于參數且數值上等于整數的最小(最接近負無窮大)的浮點數
返回double型
解釋的通俗點就是向上取整后轉成數學上相等的double型 - floor?(double a):作用是返回小于或等于參數且數值上等于整數的最大(最接近正無窮大)的浮點數
返回double型 - nextDown?(…d/f):作用是返回在負無窮大方向上與d/f相鄰的浮點值
參數可以是double d、float f兩種,返回對應的類型 - nextUp?(…d/f):作用是返回在正無窮大方向上與d/f相鄰的浮點值
參數可以是double d、float f兩種,返回對應的類型 - rint?(double a):作用是返回在數學上等于與參數值最接近且是整數的double
返回double型
解釋的通俗一點就是四舍五入后取數學上相等的double型浮點 - round?(…a):作用是返回參數四舍五入后的整數值
參數可以是double、float兩種
double參數返回long,float參數返回int
nextDown()?、nextUp()?、rint?()? 按照各自的規則舍入得浮點。
ceil?()?、floor()??、round()?分別是前面提的,取整得整數,很常見。
除法的舍入問題
System.out.println(1/2);結果是什么?
System.out.println(-1/2);結果又是什么?
答案都是一樣的:
0
為什么呢?
整數除整數,除號直接截斷取整,正負號規則相同,相當于直接砍去小數點和小數點后數位。
Java不像Python還分/和//,只有/,那怎么能精確呢?
當然是轉型為浮點啦:
答案:
0.5
那浮點精確嗎?
System.out.println(0.1+0.2);結果是什么?
答案:
0.30000000000000004
為什么呢?
簡而言之,double雙精度浮點數,遵循IEEE754,64位,52位小數+11位指數+1位符號。
計算機沒有分數,也沒有十進制小數,所以只能用二進制小數表示,難免不精確。
用更精確的BigDecimal算一下:
0.3000000000000000166533453693773481063544750213623046875
只能說相對精確了很多,也不能說完全精確了,畢竟是計算機。
printf()的舍入問題
System.out.printf("%.0f", 0.5);結果是什么?
System.out.printf("%.0f", -0.5);結果又是什么?
答案分別是:
1
-1
可見printf()的浮點舍入方式是向兩端取整。
double向float強轉的舍入問題
我們都知道,double表示64位雙精度浮點數,float代表32位單精度浮點數,double精確度高,也是默認的浮點數類型。
看下面的代碼:
double a = 0.555555555; float b = (float)a;b的值是多少?
答案是:
0.5555556
而下面的情況呢?
double a = 0.55555554; float b = (float)a;b的值是:
0.5555555
可見printf()的浮點舍入方式是四舍五入。
BigDecimal處理舍入問題的八種方式
原先BigDecimal類舍入采取本類中屬性值來定義,后被標定為 @Deprecated。
新的方式被定義在枚舉類 java.math.RoundingMode 中,有以下八種情況:
- CEILING :向正無窮大舍入
- DOWN :向零舍入
- FLOOR :向負無窮大舍入
- HALF_DOWN :向“最近的鄰居”舍入,除非兩個鄰居都等距,在這種情況下,將向下舍入
- HALF_EVEN :向“最近的鄰居”舍入,除非兩個鄰居都等距,在這種情況下,將向相鄰偶數舍入。
- HALF_UP :向“最近的鄰居”舍入,除非兩個鄰居都等距,在這種情況下,將向上舍入
- UNNECESSARY :舍入模式可以斷言所請求的操作具有準確的結果,因此不需要舍入
- UP :舍入模式從零舍入(向著遠離零的方向)
對此的理解可以參考上面的例子啦……
反思
雖說進行了整理,但我也有一個困惑:是不是我理解這個舍入問題還是站在了十進制的角度而計算機站在二進制的角度呢?這兩種思維看待舍入問題會有哪些差別呢?
確實有點困惑,待我思索一下……有確定答案的讀者還請留言,感謝……
總結
以上是生活随笔為你收集整理的【Java】深入探讨Java数值舍入问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Python】Matplotlib使用
- 下一篇: 根据特殊EOF的序列判断比赛输赢(洛谷P