Perl 板


問題情境: 最近在寫 MODBUS Communication (用 ActivePerl v5.16.3 for Windows) 主要是接收 32bits register value 然後轉成「浮點數」 其中手冊裡面有一段 Note:「 If the register value is 3.0+E38, which value represents communication error. 」 於是我用以下寫法來判斷: ############################ # read 32bits register value # # 這裡假設讀到的值為: 0x7F61B1E6(hexadecimal as 3.0E+38) $v = 0x7F61B1E6; ####### # error if(unpack('f',pack('V',$v)) == 3.0E+38) { ... } 發現永遠不會跑到 error 的區塊裡面 查到網頁: http://www-cgi.cs.cmu.edu/afs/cs/user/rgs/mosaic/pl-exp-conv.html 裡面有重要的一段訊息:「 Real numbers (floats and doubles) are in the native machine format only; due to the multiplicity of floating formats around, and the lack of a standard "network" representation, no facility for interchange has been made. This means that packed floating point data written on one machine may not be readable on another - even if both use IEEE floating point arithmetic (as the endian-ness of the memory representation is not part of the IEEE spec). Note that perl uses doubles internally for all numeric calculation, and converting from double -> float -> double will lose precision (i.e. unpack("f", pack("f", $foo)) will not in general equal $foo). 」 於是我瞭解直接用 == operator 來比較是行不通的 i.e. if(unpack("f", pack("V", $v)) == 3.0E+38) { ... } does not work 又查到網頁: http://perldoc.perl.org/perlop.html 裡面有提供一個比較 robust 的方法: sub fp_equal { my ($X, $Y, $POINTS) = @_; my ($tX, $tY); $tX = sprintf("%.${POINTS}g", $X); $tY = sprintf("%.${POINTS}g", $Y); return $tX eq $tY; } Ex. $float = unpack("f", pack("V", $v)); if(fp_equal($float,3.0E+38,8)) { ... } 其中 POINTS 代 8 進去 是我看 http://babbage.cs.qc.cuny.edu/IEEE-754.old/Decimal.html 它 32bits floating-point 的 decimal value of the significand 都是 8 位 這樣的寫法的確可以正確比較 32bits floaint-point 是否等於 3.0E+38 了 但如果我今天要比較的常數值不是 3.0E+38 而是其它的值 這樣的寫法依舊可以 work 嗎?? 於是我故意找了一個反例,要比較的常數值改成 1.06 結果會是如何: ##################### # hexadecimal as 1.06 $v = 0x3F87AE14; $float = unpack("f", pack("V", $v)); ######################### # $tX will be "1.0599999" $tX = sprintf("%.8g", $float); #################### # $tY will be "1.06" $tY = sprintf("%.8g", 1.06); 顯然 "1.0599999"(字串) 不等於 "1.06"(字串) 所以「指定精確度」後再比較,在某些 case 下還是會發生問題 我就在想還有什麼方法可以更 robust 於是我又想到: re-pack 後再比較呢 -------以下實驗------- 程式網址: http://codepad.org/3UTfradi 從 Ouput 可看出 re-pack 後再比較好像更 robust ?? 不知道大家有什麼想法 程式碼: ################################################## # 以下舉例 32bits floating-point 比較(等於) 的問題 $float1 = 3.0e+38; $float2 = 1.06; ####################################################################### # pack 成 32bits floating-point 後再 unpack(i.e. double->float->double) # # ref. http://www-cgi.cs.cmu.edu/afs/cs/user/rgs/mosaic/pl-exp-conv.html $new_float1 = unpack('f',pack('f',$float1)); $new_float2 = unpack('f',pack('f',$float2)); ################################# # 直接用 == operator 比較是否等於 &fp_equal_method1($float1,$new_float1); &fp_equal_method1($float2,$new_float2); ####################################### # 指定精確度(significant)後比較是否等於 &fp_equal_method2($float1,$new_float1); &fp_equal_method2($float2,$new_float2); ############################## # 再重新 pack 後再比較是否等於 &fp_equal_method3($float1,$new_float1); &fp_equal_method3($float2,$new_float2); #################### # 直接用 == operator sub fp_equal_method1{ my $v1 = shift; my $v2 = shift; if($v1 == $v2){ print "fp_equal_method1: $v1 equal $v2\n"; } else{ print "fp_equal_method1: $v1 not equal $v2\n"; } } ############## # Knuth method # # ref. http://perldoc.perl.org/perlop.html (Floating-point Arithmetic) sub fp_equal_method2{ my $v1 = shift; my $v2 = shift; if(sprintf("%.8g",$v1) eq sprintf("%.8g",$v2)){ print "fp_equal_method2: $v1 equal $v2\n"; } else{ print "fp_equal_method2: $v1 not equal $v2\n"; } } ###################### # re-pack then compare sub fp_equal_method3{ my $v1 = shift; my $v2 = shift; if(pack('f',$v1) eq pack('f',$v2)){ print "fp_equal_method3: $v1 equal $v2\n"; } else{ print "fp_equal_method3: $v1 not equal $v2\n"; } } ※ 編輯: cutekid (210.61.233.210), 07/11/2016 17:21:45
1F:推 abliou: 有分享有推 07/11 17:43
2F:推 flu: 喔喔~解決了嗎 推分享 07/11 18:07
※ 編輯: cutekid (61.221.80.36), 07/12/2016 14:53:18
3F:→ cutekid: flu 大,我也不知道到底有沒有真的解決了。內文有更新 07/12 14:55
4F:推 LiloHuang: 我有個困惑為什麼一定得 unpack 再判斷 XD 07/16 10:28
5F:→ LiloHuang: 不能直接判斷變數的值是否等於 0x7F61B1E6 就好了嗎 @@ 07/16 10:28
6F:→ LiloHuang: 當然我講的不是一般比較浮點數的方法,是針對原先問題 07/16 10:30
哈哈,的確可以直接判斷是否等於 0x7F61B1E6 只是手冊上是這樣寫:「 If the register value is 3.0+E38, which value represents communication 」, 而不是寫:「 If the register value is 0x7F61B1E6, which value represents communication 」, 所以我刻意讓自己去碰觸這樣的問題 可以手冊寫是是什麼浮點數,程式碼就照寫 不用刻意將程式碼用 32bits hexadecimal 來比較 ※ 編輯: cutekid (61.221.80.36), 07/18/2016 14:17:42
7F:推 LiloHuang: 原來如此 :) 07/18 19:28







like.gif 您可能會有興趣的文章
icon.png[問題/行為] 貓晚上進房間會不會有憋尿問題
icon.pngRe: [閒聊] 選了錯誤的女孩成為魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一張
icon.png[心得] EMS高領長版毛衣.墨小樓MC1002
icon.png[分享] 丹龍隔熱紙GE55+33+22
icon.png[問題] 清洗洗衣機
icon.png[尋物] 窗台下的空間
icon.png[閒聊] 双極の女神1 木魔爵
icon.png[售車] 新竹 1997 march 1297cc 白色 四門
icon.png[討論] 能從照片感受到攝影者心情嗎
icon.png[狂賀] 賀賀賀賀 賀!島村卯月!總選舉NO.1
icon.png[難過] 羨慕白皮膚的女生
icon.png閱讀文章
icon.png[黑特]
icon.png[問題] SBK S1安裝於安全帽位置
icon.png[分享] 舊woo100絕版開箱!!
icon.pngRe: [無言] 關於小包衛生紙
icon.png[開箱] E5-2683V3 RX480Strix 快睿C1 簡單測試
icon.png[心得] 蒼の海賊龍 地獄 執行者16PT
icon.png[售車] 1999年Virage iO 1.8EXi
icon.png[心得] 挑戰33 LV10 獅子座pt solo
icon.png[閒聊] 手把手教你不被桶之新手主購教學
icon.png[分享] Civic Type R 量產版官方照無預警流出
icon.png[售車] Golf 4 2.0 銀色 自排
icon.png[出售] Graco提籃汽座(有底座)2000元誠可議
icon.png[問題] 請問補牙材質掉了還能再補嗎?(台中半年內
icon.png[問題] 44th 單曲 生寫竟然都給重複的啊啊!
icon.png[心得] 華南紅卡/icash 核卡
icon.png[問題] 拔牙矯正這樣正常嗎
icon.png[贈送] 老莫高業 初業 102年版
icon.png[情報] 三大行動支付 本季掀戰火
icon.png[寶寶] 博客來Amos水蠟筆5/1特價五折
icon.pngRe: [心得] 新鮮人一些面試分享
icon.png[心得] 蒼の海賊龍 地獄 麒麟25PT
icon.pngRe: [閒聊] (君の名は。雷慎入) 君名二創漫畫翻譯
icon.pngRe: [閒聊] OGN中場影片:失蹤人口局 (英文字幕)
icon.png[問題] 台灣大哥大4G訊號差
icon.png[出售] [全國]全新千尋侘草LED燈, 水草
伺服器連線錯誤,造成您的不便還請多多包涵!
「贊助商連結」






like.gif 您可能會有興趣的文章
icon.png[問題/行為] 貓晚上進房間會不會有憋尿問題
icon.pngRe: [閒聊] 選了錯誤的女孩成為魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一張
icon.png[心得] EMS高領長版毛衣.墨小樓MC1002
icon.png[分享] 丹龍隔熱紙GE55+33+22
icon.png[問題] 清洗洗衣機
icon.png[尋物] 窗台下的空間
icon.png[閒聊] 双極の女神1 木魔爵
icon.png[售車] 新竹 1997 march 1297cc 白色 四門
icon.png[討論] 能從照片感受到攝影者心情嗎
icon.png[狂賀] 賀賀賀賀 賀!島村卯月!總選舉NO.1
icon.png[難過] 羨慕白皮膚的女生
icon.png閱讀文章
icon.png[黑特]
icon.png[問題] SBK S1安裝於安全帽位置
icon.png[分享] 舊woo100絕版開箱!!
icon.pngRe: [無言] 關於小包衛生紙
icon.png[開箱] E5-2683V3 RX480Strix 快睿C1 簡單測試
icon.png[心得] 蒼の海賊龍 地獄 執行者16PT
icon.png[售車] 1999年Virage iO 1.8EXi
icon.png[心得] 挑戰33 LV10 獅子座pt solo
icon.png[閒聊] 手把手教你不被桶之新手主購教學
icon.png[分享] Civic Type R 量產版官方照無預警流出
icon.png[售車] Golf 4 2.0 銀色 自排
icon.png[出售] Graco提籃汽座(有底座)2000元誠可議
icon.png[問題] 請問補牙材質掉了還能再補嗎?(台中半年內
icon.png[問題] 44th 單曲 生寫竟然都給重複的啊啊!
icon.png[心得] 華南紅卡/icash 核卡
icon.png[問題] 拔牙矯正這樣正常嗎
icon.png[贈送] 老莫高業 初業 102年版
icon.png[情報] 三大行動支付 本季掀戰火
icon.png[寶寶] 博客來Amos水蠟筆5/1特價五折
icon.pngRe: [心得] 新鮮人一些面試分享
icon.png[心得] 蒼の海賊龍 地獄 麒麟25PT
icon.pngRe: [閒聊] (君の名は。雷慎入) 君名二創漫畫翻譯
icon.pngRe: [閒聊] OGN中場影片:失蹤人口局 (英文字幕)
icon.png[問題] 台灣大哥大4G訊號差
icon.png[出售] [全國]全新千尋侘草LED燈, 水草

請輸入看板名稱,例如:WOW站內搜尋

TOP