咱們在寫程序時,老是會自覺或不自覺地頻繁用到類型轉換,好比將整數轉換爲浮點數或反之。函數
今天的題目主要討論基本類型的轉換(但和普通的類型轉換有所不一樣哦,詳見後文),考考你是否真的理解了類型轉換的本質。在面向對象系統中還會涉及類和接口的類型轉換,但它們和基本類型的轉換仍是有區別的,今天暫時不考慮。spa
(本人博客中全部題目都是我原創的,僅此一家,不買也來看看啊)指針
開始了,請聽題。code
題目很簡單,本身編寫一個模擬double到long的強制類型轉換實現。即實現以下效果但不能使用語言提供的強制類型轉換功能:對象
long a_long = (long) a_double;blog
考慮到語言之間的差別,下面分別說明一下題目的詳細要求。接口
1. 喜歡C語言的看這裏ip
請編寫一個函數get_int_from_float,其原型以下: long get_int_from_double(double *) 該函數接受一個double指針類型的參數並返回其整數部分。
例如調用get_int_from_float(5.2),返回5。
注意,對於很是大的數,例如1.5E100,其實際的整數部分(實際上它就是一個整數)應該是15後面跟99個0這個數,但這個數太大,即便是long型也表示不了。此時不得不對結果進行截斷(沒辦法,客觀上被限制了)。 已知條件:各種型的長度肯定,int和float都是32位,long和double都是64位。其餘已知條件見後文。 要求:見後文
2. Java或C#版get
請編寫一個方法或函數:getIntFromFloat,它具備一個double類型的參數,返回的是浮點數的整數部分。
其原型爲: long getIntFromFloat(double)
注意事項見C語言版。
已知條件:參數始終是有效的浮點數,不考慮NaN等狀況。其餘見後文
要求:見後文
3. 喜歡Javascript或其餘腳本語言的看這裏:原型
請編寫一個函數getIntFromFloat,它接受一個浮點數,並返回該浮點數的整數部分。例如調用getIntFromFloat(5.2)則返回5 其原型爲: function getIntFromFloat(f)
注意事項見C語言版。
已知條件:參數始終是有效的浮點數,不考慮NaN、非數字類型等狀況。其餘見後文 要求:見後文
共同的已知條件:
1. 浮點數的儲存格式(同時也是一個IEEE754浮點數的簡介哦,對題目不感興趣的也能夠看看這個)
(1) 題目裏的浮點數都是64位IEEE754雙精度浮點數,它們具備以下位模式(由低位到高位): 第0~51位,共52位:小數位,或尾數位 第52~62,共11位:指數部分 第63位:符號位,0爲正1爲負
(2) 尾數的規範化:
與咱們熟悉的十進制科學計數法相似,浮點數的小數不能隨便寫,必須是規範形式。規範形式就是整數部分爲1的小數,例如1.1、1.01等,非規範形式的尾數必須先轉成規範形式。
(下面都以2進制舉例)
例如101.11須要先轉成規範形式1.0111(至關於小數點左移了2位,即縮小了4倍)
規範化的好處是小數點位置固定了,不須要再額外花一些位來記錄小數點在哪裏了。
另外一個衍生出來的好處是整數部分的1是徹底固定的,因此能夠不要,使其變成隱藏的默認位。即只要存儲後面的0111便可,計算時,再將前面的1和.補上。
(3) 指數部分
指數部分也有講究。
首先是尾數轉成規範化之後須要調整指數部分的值,使得規範化先後整個數的值不變。
例如原來的101.11至關於101.11×2^0,尾數規範化爲1.0111後,指數部分須要補上2才行,即1.0111×2^2
這跟十進制是同樣的。例如123.45轉成科學計數法後是1.2345×10^2。
另一點是,指數部分不是直接存儲的,實際存儲的是原值減去一個「修正值」後的結果,對double來講,修正值是1023。計算時,將存儲的值加上1023計算出真正的指數大小(計算結果按11位有符號數來對待)。
這一點會讓不少人迷惑:爲何要這麼規定?這不是蛋疼嗎!要說尾數規範化能夠簡化實現並節約一個實實在在的位出來,那指數的這個規定是爲了什麼呢?表示範圍沒有變大,也沒有節省位數,更是增長了一步額外的計算,真是出力不討好啊!
關於這一點,這裏先賣個關子,我後面再另開一篇博文詳細討論浮點數的時候再來解釋吧,嘿嘿。
---------------------------
好了,總結一下:
要將一個以位模式存儲的double轉換爲咱們能看懂的二進制科學計數法,須要先提取出符號位、指數和尾數部分,而後就能夠將其寫爲下面的形式:
(+-) 1.尾數 × 2^(指數+1023)
關於浮點數的詳細解釋可參考維基百科(英文的。沒辦法,中文的寫的太渣了)
http://en.wikipedia.org/wiki/Floating_point
2. 取得double的位模式
假設已有以下的實現,你在程序中可使用它們來獲取一個double的位模式: long getDoubleBitPattern(double) // Java或C#
function getDoubleBitPattern(d) // JS等
long get_double_bit_pattern(double *) // C 注意:該方法或函數返回的long和原double具備相同的位模式(所以它們表示的是徹底不一樣的2個值)
共同的要求:
不能使用任何系統或語言提供的類型轉換功能,包括隱式轉換。
---------------------------
呼~~~好了,have fun!