日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java,Math类中的ceil、floor和round函数源码解析以及自己重写实现

發布時間:2025/3/19 java 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java,Math类中的ceil、floor和round函数源码解析以及自己重写实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1. ceil、floor和round的功能

首先,這三個方法都是Math類的靜態方法,而且類Math在java.lang包下,所以我們在代碼中可以直接調用Math的方法。

Math.ceil(double a)實現的是對小數向右取整,如 Math.ceil(-0.7) = -0.0,Math.ceil(0.5) = 1.0, Math.ceil(1.3) = 2.0

Math.floor(double a)實現的是對小數向左取整,如 Math.floor(-0.7) = -1.0,Math.floor(0.5) = 0.0, Math.floor(1.3) = 1.0

Math.round(double a)實現的邏輯是四舍五入,但是對于負數有點不一樣,如 Math.round(-1.5) = -1,Math.round(-0.5) = 0,有點繞,所以為了好記點,等效為 Math.floor(a+0.5),而且返回的是整數。

?

2. ceil、floor源碼?

2.1 ceil和floor代碼

因為round可通過floor來實現,所以round源碼就不多加分析,主要分析ceil和floor方法,從下圖我們可以知道ceil和floor方法實際上都是調用floorOrCeil方法實現,只是參數不一樣。參數后續分析,所以我們接下來分析floorOrCeil這個方法。

2.2??floorOrCeil源碼

看了源代碼,有點復雜,接下來我們一段一段分析?

?

2.2.1?

int exponent = Math.getExponent(a);

這個方法是得到浮點數a的指數部分,這個指數不是我們的科學計算法中的以10為底的指數,這個指數是以2為底的指數。不懂就舉例,如82.2的指數為6,0.23的指數為 -3,-0.1的指數為 -4,-6.3的指數為2,這個是怎么算的?

不知道怎么算出來的,那我們反推一下這些數字用指數怎么表示的,如下圖,不知道你們能不能看懂,如果看不懂慢慢分析一下吧,講也不太好講。

?

2.2.2?

在知道指數怎么算出來后,我們應該知道指數小于0的情況是什么了,其實就是浮點數范圍處于 -1<a<1,接下來用到了三目運算符 a ?b:c,如果a==0.0,注意 -0.0=0.0,?直接返回a?,如果不是0.0,判斷是負數還是整數,如果是負數取負邊界,如果是正數,取正邊界。這個時候用到了我們前面提到的floorOrCeil參數問題,我們先考慮如果是ceil方法,ceil方法調用floorOrCeil,傳入的負邊界是 -0.0,正邊界是1.0,那么負數取負邊界得到 -0.0,整數取正邊界得到 1.0,剛好是向右取整;如果是floor調用floorOrCeil,傳入的負邊界是 -1.0,正邊界是0.0,負數取負邊界 -1.0,整數取正邊界 0.0,剛好是向左取整

?

2.2.3?

如果指數大于52會怎么樣呢?這里涉及浮點數的底層存儲了,接下來請仔細閱讀,如下圖

一個double浮點數8個字節64位,一位符號位,11位存放指數值,52位存放數值,不懂就舉例。比如76.3,十進制小數轉為二進制不懂的可以看我另一篇博客,76.3轉為二進制是 100 1100.01001 1001 1001... (1001一直循環),和以10為底的指數原理一樣,這個數字以2為底的指數知道是幾位嗎?對的,指數段是6,使用了指數,以2為底的指數,我們用P來表示,那么76.3就變為了 1.00110001001 1001 1001...P6。然后接下來76.3的64位是怎么存儲的呢?符號位是0,指數是6,但是還要加上 1023,也就是1029,指數段二進制表示是 10000000101,然后數值段記錄的數據是小數位,也就是 1.00110001001 1001 1001...E6截取 00110001001 1001 1001...?部分,要完整表示52位的話,數值段二進制則是 0011 0001 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011,至此,我們得到了76.3的二進制表示,接下來我們通過代碼驗證一下,如下。

現在我們來談談如果指數位大于等于52會怎么樣?當指數位等于52時,那么數值段存的內容都是整數部分的二進制,小數部分根本沒有存,所以會有官方注釋提的“a value so large it must be integral”,也就是說這個浮點數小數部分在52位數值段得不到存儲,所以認為是整數,那么就直接return。

?

2.2.4

“assert exponent >= 0 && exponent <= 51;”沒什么好說的,進一步判斷指數位是否處于0和51之間。從if語句中的mask和doppel相與和0比較,我們可以推斷程序是想判斷浮點數的小數部分是不是都是0,如果小數部分是0,我們可以直接返回。經過上面對浮點數的存儲分析,我們怎么得到浮點數的小數部分呢?

首先,小數部分在數值段存儲,但是指數部分也在數值段中存儲,因為我們可以得到指數部分的位數,這樣我們就可以通過向左移位把指數段的11位和數值段的指數部分移除,注意:符號位是不會被移除的。所以如果是負數的話,我們在移位結束之后還得把二進制的首位符號位去掉。

源碼中首先通過Double.doubleToRawLongBits(a)求得浮點數的二進制表示 0100 0000 0101 0011 0001 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011,然后將DoubleConsts.SIGNIF_BIT_MASK >> exponent向右移動,其中DoubleConsts.SIGNIF_BIT_MASK是個常量,數值大小如下圖,exponent是6。因此得到二進制表示 0000 0000 0000 0000 0011 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111。然后進行 與 運算,最后得到浮點數的小數部分二進制表示為 0000 0000 0000 0000 0001 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011,然后再和0比較,如果相等,說明小數部分是0,那么說明這個浮點數其實是個整數,直接return。

?

?2.2.5

終于來到了最后,上面計算得到小數部分不是0,那我們需要先得到浮點數的整數部分,然后再考慮是向右取整還是向左取整?。先前求得的mask小數部分的二進制位全是1,現在取反則是符號位、指數段和數值段指數部分的二進制是1,那么 (~mask)的二進制表示是?1111 1111 1111 1111 1100?0000 0000 0000 0000?0000 0000 0000 0000 0000 0000 0000,和doppel進行與運算得到?0100 0000 0101 0011 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000,該二進制表示為76.0。緊接著判斷是ceil還是floor,如果是ceil,那么sign是1.0,然后如果浮點數是負數,我們剛剛取整相當于已經向右取整,只考慮正數,所以sign*a>0.0,整數+1(sign是 1.0);如果是floor,那么sign是 -1.0,然后如果浮點數是正數,我們剛剛取整相當于已經向左取整,只考慮負數,所以sign*a>0.0,整數-1(sign是 -1.0),到此源碼分析結束。

?

?

3. 自己重寫實現ceil和floor以及round方法

我們自己重寫的話,主要是取整那一塊代碼可以修改,其它的比較簡單容易理解也不需要重寫。所以,我們有什么方法可以取出浮點數的整數部分呢?

public static double ceilOrFloor(double a, double negative, double positive, double sign){int exp = Math.getExponent(a);if(exp<0){return (a==0.0) ? a : (a<0.0 ? negative : positive);}else if(exp>51){return a;}String s = String.valueOf(a);String s2 = s.substring(0, s.indexOf('.'));double result = Double.valueOf(s2);if(a==result){return a;}else{if(sign*a > 0.0)result += sign;return result;}}public static double floor(double a){return ceilOrFloor(a, -1.0, 0.0, -1.0);}public static double ceil(double a){return ceilOrFloor(a, -0.0, 1.0, 1.0);}public static long round(double a){return (long)floor(a+0.5);}

?

部分測試結果如下

?

總結

以上是生活随笔為你收集整理的Java,Math类中的ceil、floor和round函数源码解析以及自己重写实现的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 欧美日韩中文国产 | 国产又黄又粗又爽 | 美攻壮受大胸奶汁(高h) | 亚洲精品视频在线观看免费视频 | 电影桑叶2在线播放完整版 222aaa | 青青草综合在线 | 国产chinese中国hdxxxx | 日韩欧美成人一区二区三区 | 欧美精彩视频 | 美日韩成人 | 欧美69影院 | 78日本xxxxxxxxx59 亚洲图片小说视频 | 国产无精乱码一区二区三区 | 国产高清精品一区 | 亚洲av熟女国产一区二区性色 | 在线观看麻豆视频 | 麻豆av在线看 | 福利电影一区二区三区 | 一个色在线视频 | 经典杯子蛋糕日剧在线观看免费 | 狠狠插狠狠操 | 国产成人自拍视频在线观看 | 在线看黄色的网站 | 成人激情免费视频 | 国产91在线高潮白浆在线观看 | 亚洲综合日韩精品欧美综合区 | 91在线播放视频 | 波多野结衣办公室双飞 | 国产精品制服丝袜 | 99视频久久 | 国产福利91 | www.色哟哟 | 免费h片网站 | 国产素人在线观看 | 日日干天天爽 | 40一50一60老女人毛片 | 国产精品一卡二卡三卡 | 男女ss视频 | 男女做激情爱呻吟口述全过程 | 久久久久国产精品一区二区 | 老司机深夜福利影院 | 国产免费无码XXXXX视频 | 国产一区二区99 | 国产又粗又猛又色 | 亚洲精品无码久久久 | 国产高潮在线观看 | 色久阁 | 欧美一区二区久久久 | 少妇野外性xx老女人野外性xx | 国产一级淫片免费 | 91免费网站| 日日爱视频 | www.毛片.com | 91在线视频免费看 | 国产曰肥老太婆无遮挡 | 天天干天天操天天摸 | 欧美激情一二三区 | 日韩啪| 国产精品探花一区二区三区 | 国产精品久久久久久69 | 尤物在线视频观看 | caoprom97| 欧洲三级视频 | 亚洲va视频 | 一区二区三区四区在线视频 | 免费看黄网站在线 | www.一起操| 国产视频在线观看一区二区 | 妺妺窝人体色777777 | 亚洲九区 | 中国av免费 | 日韩一区二区免费看 | 天天爱天天色 | 天天草天天射 | 人人插人人射 | cao死你 | 日本xxx在线观看 | 久福利 | 国产精品自拍第一页 | 先锋影音av资源在线观看 | 波多野结衣av在线观看 | 青青在线精品 | 国产自产视频 | 一区二区三区麻豆 | 日韩精品在线观看一区 | 日韩高清在线播放 | 波多野结衣在线一区 | 欧美大片xxxx | 久久久久人妻精品一区二区三区 | 亚洲精品www久久久久久广东 | 成人精品动漫 | 激情视频网站在线观看 | 自拍偷拍一区二区三区 | 第一av | 久久久久亚洲av片无码下载蜜桃 | 四虎网站在线观看 | 六月激情| 欧美变态口味重另类在线视频 | 国产福利小视频在线 |