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灯, 水草

请输入看板名称,例如:BuyTogether站内搜寻

TOP