日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
浮點(diǎn)運(yùn)算潛在的結(jié)果不一致問(wèn)題

昨天阿楠發(fā)現(xiàn)了項(xiàng)目中的一個(gè) bug ,是因?yàn)楦↑c(diǎn)運(yùn)算的前后不一致導(dǎo)致的。明明是完全相同的 C 代碼,參數(shù)也嚴(yán)格一致,但是計(jì)算出了不相同的結(jié)果。我對(duì)這個(gè)現(xiàn)象非常感興趣,仔細(xì)研究了一下成因。

專注于為中小企業(yè)提供做網(wǎng)站、網(wǎng)站設(shè)計(jì)服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)清江浦免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了上千家企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過(guò)網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。

原始代碼比較繁雜。在弄清楚原理后,我簡(jiǎn)化了出問(wèn)題的代碼,重現(xiàn)了這個(gè)問(wèn)題:

 
 
 
  1. static void 
  2. foo(float x) { 
  3.     float xxx = x * 0.01f; 
  4.     printf("%d\n", (int)(x * 0.01f)); 
  5.     printf("%d\n", (int)xx); 
  6.  
  7. int 
  8. main() { 
  9.     foo(2000.0f); 
  10.     return 0; 

使用 gcc 4.9.2 ,強(qiáng)制使用 x87 浮點(diǎn)運(yùn)算編譯運(yùn)行,你會(huì)發(fā)現(xiàn)令人詫異的結(jié)果。

 
 
 
  1. gcc a.c -mfpmath=387 
  2.  
  3. 19 
  4. 20 

前一次的輸出是 19 ,后一次是 20 。

這是為什么呢?讓我們來(lái)看看 gcc 生成的代碼,我截取了相關(guān)的段落:

 
 
 
  1. flds    16(%rbp) 
  2.  flds    .LC0(%rip) 
  3.  fmulp   %st, %st(1) 
  4.  fstps   -4(%rbp)          ; 1. x * 0.01f 結(jié)果保存到內(nèi)存中的 float 變量中 
  5.  flds    16(%rbp) 
  6.  flds    .LC0(%rip) 
  7.  fmulp   %st, %st(1) 
  8.  fisttpl -20(%rbp)        ; 2. x * 0.01f 結(jié)果直接轉(zhuǎn)換為整型 
  9.  movl    -20(%rbp), %eax 
  10.  movl    %eax, %edx 
  11.  leaq    .LC1(%rip), %rcx 
  12.  call    printf 
  13.  flds    -4(%rbp)                 ; 3. 讀出 1. 保存的乘法結(jié)果 
  14.  fisttpl -20(%rbp) 
  15.  movl    -20(%rbp), %eax 
  16.  movl    %eax, %edx 
  17.  leaq    .LC1(%rip), %rcx 
  18.  call    printf 

這里我做了三行注釋。

首先,0.01 是無(wú)法精確表示成 2 進(jìn)制的,所以 * 0.01 這個(gè)操作一定會(huì)存在誤差。

兩次運(yùn)算都是 x * 0.01f ,雖然按 C 語(yǔ)言的轉(zhuǎn)換規(guī)則,表達(dá)式中都是 float 時(shí),按 float 精度運(yùn)算。但這里 gcc 生成的代碼并沒(méi)有嚴(yán)格設(shè)置 FPU 的精度控制,在注釋 2 這個(gè)地方,乘法結(jié)果是直接從浮點(diǎn)寄存器轉(zhuǎn)換為整數(shù)的。而在注釋 1 這個(gè)地方,把乘法結(jié)果通過(guò) fstps 以低精度形式保存到內(nèi)存,再在注釋 3 的地方 flds 讀回。

所以在注釋 2 和注釋 3 的地方,浮點(diǎn)寄存器 st 內(nèi)的值其實(shí)是有差別的,這導(dǎo)致了 fisttpl 轉(zhuǎn)換為整數(shù)后結(jié)果不同。


當(dāng)前標(biāo)題:浮點(diǎn)運(yùn)算潛在的結(jié)果不一致問(wèn)題
鏈接URL:http://www.dlmjj.cn/article/dpohjhc.html