iOS 時(shí)間戳精度丟失問題(float=longlong/float)

問題現(xiàn)象

使用long long 格式保持服務(wù)端返回的時(shí)間戳塌忽,然后本地展示該時(shí)間戳?xí)r,發(fā)現(xiàn)總是差一兩分鐘

    NSDate *currentDate = [NSDate date];
    //模擬獲得服務(wù)器傳回的單位是毫秒的時(shí)間戳
    long long timeInterval = [currentDate timeIntervalSince1970] * 1000;
    //毫秒轉(zhuǎn)化為秒失驶,再轉(zhuǎn)化為日期類型
    NSDate *convertDate = [NSDate dateWithTimeIntervalSince1970:(timeInterval/1000.f)];
    NSLog(@"currentDate:%@,convertDate:%@",currentDate,convertDate);

輸出效果: 這里注意分鐘和秒已經(jīng)出現(xiàn)了誤差(實(shí)際是精度丟失)
currentDate:Wed Jun 10 11:17:34 2020,
convertDate:Wed Jun 10 11:18:24 2020

問題原因

時(shí)間戳(精確到毫秒)使用long long 格式存儲(chǔ)土居,2020年目前的時(shí)間戳位數(shù)是13位,long long絕對(duì)足夠存儲(chǔ)下來嬉探,由于是整數(shù)類型擦耀,精度也肯定不會(huì)丟失。
但是當(dāng)將該時(shí)間戳轉(zhuǎn)化為NSDate類型時(shí)涩堤,精度缺丟失了眷蜓,問題肯定出現(xiàn)在下面這行代碼中:

NSDate *convertDate = [NSDate dateWithTimeIntervalSince1970:(timeInterval/1000.f)];

這行代碼中,存在一個(gè)隱式類型轉(zhuǎn)換胎围,long long / float 類型吁系,默認(rèn)得到的是float類型,float類型存不下一個(gè)時(shí)間戳嗎白魂?答案是肯定能存下汽纤,但是精度沒保障。

float的十進(jìn)制精度是小數(shù)點(diǎn)后6~7位福荸,能絕對(duì)保證的只有6位蕴坪。
粗略得看一下這個(gè)13位的時(shí)間戳1591760542219,轉(zhuǎn)化為浮點(diǎn)數(shù)的十進(jìn)制1.1591760542219 * 10^13,即1.159176之后的小數(shù)都是無法精確保證。
實(shí)際測(cè)試背传,13位時(shí)間戳(毫秒)
1591760542219
移除1000.0得到的浮點(diǎn)數(shù)時(shí)間戳(單位是秒)
1591760512.000000
對(duì)比已經(jīng)出現(xiàn)了精度丟失呆瞻,丟失的范圍在100秒以內(nèi),這也是上面問題現(xiàn)象中時(shí)間出現(xiàn)偏差的原因径玖;

問題解法

  1. 本地使用double存儲(chǔ)服務(wù)端給的時(shí)間戳
  2. 將代碼中的隱式轉(zhuǎn)換去掉痴脾,強(qiáng)制將long long 格式的時(shí)間戳轉(zhuǎn)為double后再除以1000.0

根本原因:float的表示精度很低

這就要從浮點(diǎn)數(shù)的表示法講起了IEEE754 浮點(diǎn)數(shù)的表示方法

浮點(diǎn)數(shù)表示法的簡(jiǎn)要總結(jié)

float.jpeg

浮點(diǎn)數(shù)在計(jì)算機(jī)中的存儲(chǔ)格式如上圖所示,由符號(hào)位挺狰,指數(shù)明郭,尾數(shù)三部分構(gòu)成买窟,float和double的區(qū)別僅體現(xiàn)在指數(shù)和尾數(shù)所占位數(shù)不同丰泊。
以float為例,符號(hào)位1bit,指數(shù)占8bit,尾數(shù)23bit始绍。為了直觀簡(jiǎn)化得說明瞳购,我們假設(shè)其指數(shù)和尾數(shù)都是以原碼(正數(shù)符號(hào)位為0,負(fù)數(shù)符號(hào)位為1亏推,其中指數(shù)部分也包含一個(gè)符號(hào)位)的方式來表示学赛,簡(jiǎn)化的示例:

0.75 = 0100 0000 1100 0000 0000 0000 0000 0000

符號(hào)位 0 表示為正;指數(shù)位1000 0001表示為-1 尾數(shù)100 …… (此處省略20個(gè)0)表示1.1(二進(jìn)制是1.1吞杭,十進(jìn)制就是1.5)(由于尾數(shù)使用“二進(jìn)制的科學(xué)計(jì)數(shù)法”盏浇,所以首位的整數(shù)部分的1默認(rèn)存在,不占實(shí)際的空間芽狗,僅存儲(chǔ)小數(shù)點(diǎn)后面尾數(shù)绢掰,這也是為什么取名為尾數(shù)的原因吧) 所以

0.75 = 1.5 * 2^(-1)

通過上面的示例,我們可以知道童擎,決定float表示范圍的是指數(shù)滴劲,決定float表示精度的是尾數(shù)
再來粗略得計(jì)算一下float的表示范圍
8bit 指數(shù)顾复,可以表示的指數(shù)為 -126~+127(0和255有其它用戶班挖,這里不展開講)則float能表示的最大值為
floatMax = +(1.11111111111111111111111) × 2 ^127 ≈ 3.402823 e +38
這里用10進(jìn)制直觀的展示一下340282346638528859811704183484516925440.000000,整數(shù)位有39位
對(duì)應(yīng)的float能表示的最小值為
floatMin = -(1.11111111111111111111111) × 2 ^(-126) ≈ ?1.175494e ?38
float能表示的精度由23bit的尾數(shù)決定,其最大值為2^23-1 = 8388607,也就是說尾數(shù)數(shù)值超過這個(gè)值芯砸,float將無法精確表示萧芙,所以float最多能表示小數(shù)點(diǎn)后7位,但絕對(duì)能保證的為6位(這里指科學(xué)計(jì)數(shù)法的方式)假丧,用普通十進(jìn)制標(biāo)識(shí)一下340282346638528859811704183484516925440.000000 后面的數(shù)值范圍都是無法精確表示的双揪。
再看一眼double的表示精度:尾數(shù)域?yàn)?2位,最大值2^52?1=4,503,599,627,370,495 所以雙精度浮點(diǎn)數(shù)的十進(jìn)制的精度最高為 16 位虎谢,絕對(duì)保證的為15位盟榴,

所以float能表示的數(shù)值范圍很大(+-10^38),但是對(duì)于一個(gè)精確到毫秒的只有13位有效數(shù)值的時(shí)間戳卻無能為力婴噩,iOS系統(tǒng)存儲(chǔ)的時(shí)間戳也是默認(rèn)使用的double類型擎场,所以自己處理時(shí)間戳格式類型轉(zhuǎn)換時(shí)羽德,需要注意float的表示精度問題。

參考文獻(xiàn):IEEE754 浮點(diǎn)數(shù)的表示方法

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末迅办,一起剝皮案震驚了整個(gè)濱河市宅静,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌站欺,老刑警劉巖姨夹,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異矾策,居然都是意外死亡磷账,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門贾虽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來逃糟,“玉大人,你說我怎么就攤上這事蓬豁〈卵剩” “怎么了?”我有些...
    開封第一講書人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵地粪,是天一觀的道長(zhǎng)取募。 經(jīng)常有香客問我,道長(zhǎng)蟆技,這世上最難降的妖魔是什么玩敏? 我笑而不...
    開封第一講書人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮付魔,結(jié)果婚禮上聊品,老公的妹妹穿的比我還像新娘。我一直安慰自己几苍,他們只是感情好翻屈,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著妻坝,像睡著了一般伸眶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上刽宪,一...
    開封第一講書人閱讀 51,541評(píng)論 1 305
  • 那天厘贼,我揣著相機(jī)與錄音,去河邊找鬼圣拄。 笑死嘴秸,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播岳掐,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼凭疮,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了串述?” 一聲冷哼從身側(cè)響起执解,我...
    開封第一講書人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎纲酗,沒想到半個(gè)月后衰腌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡觅赊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年右蕊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片茉兰。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡尤泽,死狀恐怖欣簇,靈堂內(nèi)的尸體忽然破棺而出规脸,到底是詐尸還是另有隱情,我是刑警寧澤熊咽,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布莫鸭,位于F島的核電站,受9級(jí)特大地震影響横殴,放射性物質(zhì)發(fā)生泄漏被因。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一衫仑、第九天 我趴在偏房一處隱蔽的房頂上張望梨与。 院中可真熱鬧,春花似錦文狱、人聲如沸粥鞋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至昼扛,卻和暖如春苏研,著一層夾襖步出監(jiān)牢的瞬間等浊,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來泰國打工摹蘑, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留筹燕,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像撒踪,于是被迫代替她去往敵國和親踪少。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355