最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

iOS浮點類型精度問題的原因與解決辦法

 更新時間:2022年01月27日 16:16:57   作者:夢回吹角連營  
在iOS開發(fā)中,我們經(jīng)常要使用浮點類型去接收后臺返回過來的的數(shù)據(jù),這時往往會遇到精度問題,這篇文章主要給大家介紹了關(guān)于iOS浮點類型精度問題的原因與解決辦法,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下

前言

相信不少人(其實我覺得應(yīng)該是每個人)都遇到過一個問題,那就是當服務(wù)端返回的JSON數(shù)據(jù)中出現(xiàn)了小數(shù)時,客戶端用CGFloat去解析時總是會出現(xiàn)精度丟失的問題,尤其當遇到敏感數(shù)據(jù)時,這種精度丟失是完全不能被容忍的,本文會從簡單的解決方案和原理出發(fā),一起帶大家回顧一下這個其實大家以前都學(xué)過但是都忘的差不多了的小問題。

如何解決浮點型精度問題

四舍五入處理

//例如服務(wù)端返回了這么一個json
{
    "price":1.9
}

// 客戶端解析price后并且打印1.9
CGFloat price = model.price
NSLog(@"%f",price)
得到的結(jié)果是 1.8999999999999999

這個時候呢,作為一個咸魚開發(fā)者,可以寫下如下代碼:

NSLog(@"%.2f",price)
輸出:1.89
//不夠準確,沒關(guān)系,還有辦法
NSLog(@"f%@",round(price*10)/10);
輸出1.9

當然了,還有apple專門為精度問題提供的 NSDecimalNumber類型也可以解決這個問題。NSDecimalNumber的用法非常簡單。(至于怎么個簡單,請自行百度,別問我,我不百度也寫不出來)

更優(yōu)的解決方案

  • 那么問題來了,作為一個懶到一整年都不愿意寫文章的咸魚中的咸魚,我應(yīng)該選擇哪種方式去解決這個問題呢?

好的,重頭戲來了,接下來,我們上代碼!

//服務(wù)端必須返回字符串類型,如果服務(wù)端沒有照做: **請帶著錘子和煤氣罐去找后端開發(fā)人員解決**
@property (nonatomic,copy) NSString *price;

是的,我會選擇不解決這個問題,把皮球踢出去,這才是一個合格的開發(fā)者該做的事情嘛!

精度丟失的原因

解決浮點精度問題是一個方面,但是如此簡單的內(nèi)容不足以我水完一整篇文章,那么接下來,我們來講講為什么好好的數(shù)字解析出來,他咋就不準確了呢?

可能很多人都能大概講出來精度丟失是因為浮點數(shù)存儲方式的問題,畢竟這玩意兒其實專業(yè)對口的筒子們在校的時候都學(xué)過,但是大家摸摸自己的小腦袋,嘿,是不是和我一樣?全忘光了?

而且鑒于總有些基礎(chǔ)很牛逼的面試官和剛好復(fù)習過這部分內(nèi)容的裝逼面試官就是喜歡挑這些小問題來刁難咱們這些老年摸魚程序員,下面我們就來復(fù)習一下這部分的知識吧。

浮點類型的存儲方式

浮點類型在計算機中的存儲方式是以科學(xué)計數(shù)法的方式來存儲的:

例如: 科學(xué)計數(shù)法表示小數(shù)
90.9 => 9.09 x 10^1
8.3  => 8.3 x 10^0

我們以8.3為例子,要存儲8.3 (8.3 x 10^0), 首先肯定要將8.3轉(zhuǎn)化為2進制,8轉(zhuǎn)為二進制時1000,那么0.3呢?

年邁的程序員喲,你是不是猛然發(fā)現(xiàn)居然忘了小數(shù)是如何轉(zhuǎn)化為2進制的呀,放下你準備百度的顫抖的雙手,你想要的,我這里都有!

以0.9為例子,將0.9乘以2,得到的數(shù)字整數(shù)部分為二進制的小數(shù)第一位,將結(jié)果部分的小數(shù)部分取出并再乘以2,取整數(shù)部分為第2位,不斷重復(fù)以上操作,直到結(jié)果等于0或者出現(xiàn)循環(huán)為止。

0.9 *2 = 1.8  第1位 1
0.8 *2 = 1.6  第2位 1
0.6 *2 = 1.2  第3位 1
0.2 *2 = 0.4  第4位 0
0.4 *2 = 0.8  第5位 0
0.8 *2 = 1.6  第6位 1 出現(xiàn)循環(huán)了

那么0.9的二進制就是 0.1 1100 1100 1100 1100... 其中1100無限循環(huán)

經(jīng)過上面一番復(fù)習我們知道8.3的二進制可表示為 1000.0 1001 1001 1001... (1001無限循環(huán)) 用科學(xué)計數(shù)法表示則為, 1.000 0 1001 1001 1001 x 2^3

整數(shù)部分指數(shù)部分小數(shù)部分
13.000 0 1001 1001 1001

而我們知道float是4(32位)個字節(jié),在存儲時他的每個bit是如下分配的

第31位符號位23-30位(指數(shù)位)0-22位(小數(shù)位)
13.000 0 1001 1001 1001

有效位數(shù)

可以看到尾數(shù)部分有23位,但是由于是科學(xué)技術(shù)法之后任何一個數(shù)字都可以用  1.aaa x 2^b 這種形式來表示,所以1可以省略,(這個時候就有人要抬杠了,為啥,那遇到0.aaa x 2^b這種咋辦呀! 答曰:b可以是負數(shù)?。敲纯偣?3位的數(shù)據(jù)實際可以表達的位數(shù)其實就是24位。

  • 24位可以表達的最大數(shù)字是 16777215 ,如果大于這個數(shù)就無法精確表示了。

當然大于16777215一不定是完全不能精確表示的,比如16777216,他的二進制表達形式是1后面帶1堆0. 因為他是2的整數(shù)次冪,那么后面全是0 所以23位能把該數(shù)字存儲下來,如果在23位0后面還出現(xiàn)了1就不行了,以此類推,16777215 后面還會有數(shù)字剛好可以滿足這種2的整數(shù)次冪的條件,也可以正確表達。

雖然大于16777215的數(shù)字也有部分可以精確表達,但是我們談精度的話肯定就要精確了,那么能精確表達的數(shù)字就只有0-16777215之間的了,16777215之間我們數(shù)一下,一共是8位,但是由于最高位1開頭并不能全部包含,所以說精度應(yīng)該是7位有效數(shù)子。

另外提一下浮點數(shù)的表達范圍,這個范圍肯定是由指數(shù)來確定了,具體是多少我就不算了,大家有興趣的可以去算一算。

指數(shù)的存儲方式:移位存儲

可以看到指數(shù)部分一共是給了8個bit位,由于指數(shù)有正負,那么假設(shè)我們第一位表示符號位,那么我們可以表示的數(shù)字范圍為 -127 ~ +127

那么能表示的范圍被分為兩部分:

  • 1 000000 0~ 1 111111 1 => -0 到 -127

  • 0 000000 0~ 0 111111 1 => +0 到 127

很明顯,如果這樣會出現(xiàn)一個 -0 和一個 +0,為了避免這個問題所以出現(xiàn)了移位存儲:即如果最高位不用來表示符號位,8個bit 可以存儲的范圍是 0-255,我們重新來規(guī)劃下兩個區(qū)間:

  • 00000000 - 01111111 => 0-127 減去127則表示-127-0之前的數(shù)字
  • 10000000 - 11111111 => 128-256 減去127則表示1-127之前的數(shù)字

這樣一來規(guī)避了+-0的問題, 上文中所說的8.3 轉(zhuǎn)化為小數(shù)后的指數(shù)位是3,那么3實際存儲的時130,也就是 10000010,我們更新一下實際存儲的表格

第31位符號位23-30位(指數(shù)位)0-22位(小數(shù)位)
110000010.000 0 1001 1001 1001

double類型

double類型是8字節(jié)64位,其表示的位數(shù)和float所不同只有位數(shù)差別,其他都一樣,雙精度表示的位數(shù)如下:

第63位符號位52-62位(指數(shù)位)0-51位(小數(shù)位)

總結(jié):輸出結(jié)果丟失精度原因

回到最初的1.9這個數(shù)字打印為1.8999999999999999,現(xiàn)在我們應(yīng)該知道為什么了,因為1.9轉(zhuǎn)2進制時是個無限循環(huán),由于存儲的原因后面的循環(huán)部分被只被截取了23位,還原回來的十進制數(shù)字和原先肯定就不一樣了。 同理,如果小數(shù)點后面是.5這種5的倍數(shù)的小數(shù),打印出來的小數(shù)一般都會是正常的,因為.5轉(zhuǎn)2進制時并不是無限循環(huán)的。

到此這篇關(guān)于iOS浮點類型精度問題的原因與解決辦法的文章就介紹到這了,更多相關(guān)iOS浮點類型精度問題內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳細整理iOS中UITableView的性能優(yōu)化

    詳細整理iOS中UITableView的性能優(yōu)化

    最近在微博上看到一個很好的開源項目,是關(guān)于如何優(yōu)化UITableView的,加上正好最近也在優(yōu)化項目中的類似朋友圈功能這塊,思考了很多關(guān)于UITableView的優(yōu)化技巧,所以決定詳細的整理下對優(yōu)化UITableView的理解,需要的朋友們可以參考借鑒。
    2017-03-03
  • iOS 對當前webView進行截屏的方法

    iOS 對當前webView進行截屏的方法

    下面小編就為大家?guī)硪黄猧OS 對當前webView進行截屏的方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-04-04
  • 在IOS系統(tǒng)上滾動條滾動到指定的位置出現(xiàn)空白頁面的解決方案

    在IOS系統(tǒng)上滾動條滾動到指定的位置出現(xiàn)空白頁面的解決方案

    這篇文章主要介紹了 在IOS系統(tǒng)上滾動條滾動到指定的位置出現(xiàn)空白頁面的解決方案,需要的朋友可以參考下
    2017-01-01
  • iOS實現(xiàn)圓環(huán)比例圖

    iOS實現(xiàn)圓環(huán)比例圖

    這篇文章主要為大家詳細介紹了iOS實現(xiàn)圓環(huán)比例圖,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • iOS-Mac遠程連接控制Window

    iOS-Mac遠程連接控制Window

    這篇文章主要為大家詳細介紹了iOS-Mac遠程連接控制Window,蘋果電腦遠程連接控制Windows電腦,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • IOS  AFNetworking的Post失敗及requestSerializer的正確使用

    IOS AFNetworking的Post失敗及requestSerializer的正確使用

    這篇文章主要介紹了IOS AFNetworking的Post失敗及requestSerializer的正確使用的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • iOS開發(fā)中使用UIScrollView實現(xiàn)無限循環(huán)的圖片瀏覽器

    iOS開發(fā)中使用UIScrollView實現(xiàn)無限循環(huán)的圖片瀏覽器

    這篇文章主要介紹了iOS開發(fā)中使用UIScrollView實現(xiàn)無限循環(huán)的圖片瀏覽器的方法,感興趣的小伙伴們可以參考一下
    2016-03-03
  • iOS中UIView實現(xiàn)不同方向的導(dǎo)角

    iOS中UIView實現(xiàn)不同方向的導(dǎo)角

    這篇文章主要給大家介紹了關(guān)于iOS中UIView實現(xiàn)不同方向的導(dǎo)角的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學(xué)習或使用iOS具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧
    2018-05-05
  • iOS實現(xiàn)攝像頭實時采集圖像

    iOS實現(xiàn)攝像頭實時采集圖像

    這篇文章主要為大家詳細介紹了iOS實現(xiàn)攝像頭實時采集圖像,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-04-04
  • 個人對于異步和多線程的關(guān)系的理解分享

    個人對于異步和多線程的關(guān)系的理解分享

    異步和多線程并不是一個同等關(guān)系,異步是最終目的,多線程只是我們實現(xiàn)異步的一種手段。異步是當一個調(diào)用請求發(fā)送給被調(diào)用者,而調(diào)用者不用等待其結(jié)果的返回而可以做其它的事情。
    2014-08-08

最新評論

青河县| 诸城市| 岱山县| 漳浦县| 平昌县| 福贡县| 上高县| 西畴县| 乡城县| 高邑县| 贺州市| 永康市| 通化县| 崇信县| 湟中县| 前郭尔| 梁河县| 闽侯县| 如皋市| 鄂托克前旗| 新乡县| 泽库县| 苍梧县| 宁安市| 淄博市| 南开区| 如东县| 米易县| 藁城市| 呼和浩特市| 临洮县| 阳东县| 启东市| 内黄县| 义马市| 梓潼县| 甘孜县| 田阳县| 焦作市| 九江市| 秦皇岛市|