西门子(中国)有限公司(SLC)

注册 登录

  签到     订阅   每日登录:+1西币 +1经验值我的支持中心

信息提示
很抱歉!您所访问的页面不存在,或网址发生了变化,请稍后再试。

技术论坛


BUG? BUG? 我觉得应该算是BUG

作者 主题
至圣

经验值: 16236
发帖数: 4139
精华帖: 113
主题:【探讨】BUG? BUG? 我觉得应该算是BUG
精编帖 推荐帖


只看楼主 只看精华 只看精编 楼主 2019-12-10 19:31:20

现场一台机器出现了个问题,我是按照FOR-NEXT循环写的程序, 总共有15节烘箱加热,可是现场反映就第13节动作异常!  我是打死不信啊!  原因无它,用循环语句循环15遍,要出问题就都有问题啊,怎么可能单单第13节有问题呢?   今天到现场监控了一下,别说,还真是第13节有问题!   问题出在那儿呢?   程序中有如下一句:(为了求当前字总共16位当中那个位为1的最高值,比如第10位为1,则返回10)

iNum := DINT_TO_INT(TRUNC(LN(UINT_TO_REAL(SWAP(#iTemp)))/LN(Real#2.0)));

就这么简单的一句,可是当iTemp=32时,得到的结果iNum却还是12! 按照计算应该是13才对呀! 

10#32= 16#20 , Swap后即为16#2000=10#8192

LN(8192)=9.010913...

LN(2.0)=0.693147... 

两者相除,结果等于13.000028854,截尾取整,按理说应该是13吧? 可是PLC运算的结果就是12 !

其他的条件,比如iTemp=16则iNum=12,   iTemp=64则iNum=14都是正常的!


我没招了! 只能人为地改啊!  把语句改成: iNum := DINT_TO_INT(TRUNC(LN(UINT_TO_REAL(SWAP(#iTemp)))/LN(Real#2.0) + 1.0E-6));

人为地加个极小的数,则正常工作了!


后来再玩一把,改成: iNum := DINT_TO_INT(TRUNC(LN(UINT_TO_LREAL(SWAP(#iTemp)))/LN(LReal#2.0)));

各位看官,注意到区别没?  将原程序的REAL改成了LREAL, 则也正常工作了!


大家觉得这算BUG吗?  有兴趣的朋友测试一下,就量iTemp=32时才有问题。


I can do it
以下网友喜欢您的帖子:

  
重要声明:

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

帖子链接:http://www.ad.siemens.com.cn/club/bbs/post.aspx?b_id=66&a_id=1598002

至圣

经验值: 75279
发帖数: 16737
精华帖: 588
回复:BUG? BUG? 我觉得应该算是BUG
精华帖精华帖星级3级 精编帖 推荐帖


只看楼主 只看精华 只看精编 1楼 2019-12-10 21:26:20

嘿嘿。用到浮点就会有这种问题。更别说变换了。浮点数十进制有效位数是很少的。

当年16位的电脑更出错了。初代8位电脑计算才麻烦呢。


浮点计算不能反复用,越多误差越大、精度越差。


你这种需求应该有专门的函数吧?

我记得这种标准算法不是用左位移;减循环么?


 
以下网友喜欢您的帖子:

  
奇侠

经验值: 7333
发帖数: 2176
精华帖: 26
回复:BUG? BUG? 我觉得应该算是BUG
推荐帖


只看楼主 只看精华 只看精编 2楼 2019-12-10 21:55:44

伊侠,real是七位有效数字,试试LREAL呢?


学习ing!
以下网友喜欢您的帖子:

  
版主

经验值: 46332
发帖数: 15450
精华帖: 266
回复:BUG? BUG? 我觉得应该算是BUG
精编帖 推荐帖


只看楼主 只看精华 只看精编 3楼 2019-12-10 21:55:50


没错,就是这样的,隐式转换的弊端。


另外,浮点转整数有好几个指令呢,只会用TRUNC吗?


Zane 注册自动化系统工程师 Always save before download
以下网友喜欢您的帖子:

  
游士

经验值: 295
发帖数: 16
精华帖: 0
回复:BUG? BUG? 我觉得应该算是BUG
推荐帖


只看楼主 只看精华 只看精编 4楼 2019-12-10 23:34:09

我能想到的是循环地除二取模,但是想到这不是int而是word应该只能将word分成两个byte解;

或者一共就16位,列表也没多少,但是又要建一个子函数了


 
以下网友喜欢您的帖子:

  
至圣

经验值: 16236
发帖数: 4139
精华帖: 113
回复:BUG? BUG? 我觉得应该算是BUG
精编帖 推荐帖


只看楼主 只看精华 只看精编 楼主 5楼 2019-12-11 08:01:07
ROUND,FLOOR当然都试过,你试试? 再一个我这应用原则上只能用TRUNC,截尾取整,因为我要的是最高位。 另外,这和隐式转换没关系吧? 我都是显示转换,只不过转成REAL有问题,而转成LREAL说没问题罢了。
I can do it
以下网友喜欢您的帖子:

  
奇侠

经验值: 6725
发帖数: 507
精华帖: 1
回复:BUG? BUG? 我觉得应该算是BUG
推荐帖


只看楼主 只看精华 只看精编 6楼 2019-12-11 08:01:48

大神们  佩服啊 


 
以下网友喜欢您的帖子:

  
侠客

经验值: 834
发帖数: 103
精华帖: 0
回复:BUG? BUG? 我觉得应该算是BUG
推荐帖


只看楼主 只看精华 只看精编 7楼 2019-12-12 09:14:55

 转换的时候弄浮点数很容易出问题,上次弄一个定量称通讯的时候就出现这个问题,不容易发现。


低头做事,抬头做人!!
以下网友喜欢您的帖子:

  
奇侠

经验值: 7819
发帖数: 884
精华帖: 1
回复:BUG? BUG? 我觉得应该算是BUG
推荐帖


只看楼主 只看精华 只看精编 8楼 2019-12-13 08:24:44

看着大神们的讨论,一头雾水。


我回来了!
以下网友喜欢您的帖子:

  
侠圣

经验值: 2932
发帖数: 1151
精华帖: 4
回复:BUG? BUG? 我觉得应该算是BUG
精编帖 推荐帖


只看楼主 只看精华 只看精编 9楼 2019-12-13 08:52:01

9.010913和0.693147是你看到的四舍五入后的结果

说到底还是数据精度问题

最碰巧的可能值分别是:9.01091245和0.6931474

9.0109125/0.6931474=12.99999466203004



QQ 402550360
以下网友喜欢您的帖子:

  
侠圣

经验值: 2932
发帖数: 1151
精华帖: 4
回复:BUG? BUG? 我觉得应该算是BUG
推荐帖


只看楼主 只看精华 只看精编 10楼 2019-12-13 08:53:22

9.0109125


QQ 402550360
以下网友喜欢您的帖子:

  
至圣

经验值: 16236
发帖数: 4139
精华帖: 113
回复:BUG? BUG? 我觉得应该算是BUG
精华帖精华帖星级3级 精编帖 推荐帖


只看楼主 只看精华 只看精编 楼主 11楼 2019-12-13 11:04:13

不是BUG,的确是我的编程不够严谨。

考虑到浮点数的精度问题,即使后来我改成LREAL类型,也只是把问题掩盖了!


改成DINT_TO_INT(TRUNC(LN(UINT_TO_LREAL(SWAP(#iTemp)))/LN(LReal#2.0) +1.0E-9 )); 可能更能满足实际的应用需要。  这个可以涵盖32位双字的应用。


其实我的应用是求一个字或者双字内 某一个位为1的最高位数。  比如某个数为63,它的二进制为11 1111,通过该指令返回值为 5 (按照ZANE的想法使用ROUND则得到6, 我需要的是截尾取整,而不是简单地四舍五入)。


当然,最靠谱的办法就是用移位判断,但是程序啰嗦,16位字需要移16次,32位字需要移32次, 或者用二分位法。  但是都没有我这个指令来得简洁, 只是简洁过头了没有考虑到精度问题。


I can do it
以下网友喜欢您的帖子:

  
至圣

经验值: 10114
发帖数: 5091
精华帖: 45
回复:BUG? BUG? 我觉得应该算是BUG
推荐帖


只看楼主 只看精华 只看精编 12楼 2019-12-13 11:23:16

 伊默,算你运气好,既不是你的问题,也不是系统bug。这种问题,难得一遇。我的理解可以算为数字计算机的系统误差。你的视野又扩展了,应该是痛并快乐着。


知其道,用其妙!
以下网友喜欢您的帖子:

  
奇侠

经验值: 6256
发帖数: 835
精华帖: 7
回复:BUG? BUG? 我觉得应该算是BUG
推荐帖


只看楼主 只看精华 只看精编 13楼 2019-12-13 12:07:48

感谢分享,德国大数学家说上帝创造了自然数,其余都是人做的工作。



 
以下网友喜欢您的帖子:

  
版主

经验值: 46332
发帖数: 15450
精华帖: 266
回复:BUG? BUG? 我觉得应该算是BUG
精华帖精华帖星级5级 精编帖 推荐帖


只看楼主 只看精华 只看精编 14楼 2019-12-14 08:59:20
数据取进来,取最高位字节,与0或运算,结果为零,则跳过取下一字节,不为零,则左移取第一位移出值为1的位数,根据字节数与移位次数,(n字节+1)*8-n移位,即得最高位1的位数。
一个双字,最多比较3次移位7次。这种算法也适合长型数据。
Zane 注册自动化系统工程师 Always save before download
精华帖版主置评: 快速找出最高位的方法。-yming
以下网友喜欢您的帖子:

  
至圣

经验值: 75279
发帖数: 16737
精华帖: 588
回复:BUG? BUG? 我觉得应该算是BUG
精编帖 推荐帖


只看楼主 只看精华 只看精编 15楼 2019-12-14 09:56:52
以下是引用伊默在2019-12-13 11:04:13的发言 >11楼

不是BUG,的确是我的编程不够严谨。

考虑到浮点数的精度问题,即使后来我改成LREAL类型,也只是把问题掩盖了!


改成DINT_TO_INT(TRUNC(LN(UINT_TO_LREAL(SWAP(#iTemp)))/LN(LReal#2.0) +1.0E-9 )); 可能更能满足实际的应用需要。  这个可以涵盖32位双字的应用。


其实我的应用是求一个字或者双字内 某一个位为1的最高位数。  比如某个数为63,它的二进制为11 1111,通过该指令返回值为 5 (按照ZANE的想法使用ROUND则得到6, 我需要的是截尾取整,而不是简单地四舍五入)。


当然,最靠谱的办法就是用移位判断,但是程序啰嗦,16位字需要移16次,32位字需要移32次, 或者用二分位法。  但是都没有我这个指令来得简洁, 只是简洁过头了没有考虑到精度问题。

其实浮点运算是最慢的,布尔运算是很快的。而使用M区变量布尔运算是最快的。

看似程序啰嗦,其实处理起来是速度并不慢。这是PLC中布尔运算器的强项。

这种通用函数功能,真应该写成个FC。



 
以下网友喜欢您的帖子:

  
至圣

经验值: 75279
发帖数: 16737
精华帖: 588
回复:BUG? BUG? 我觉得应该算是BUG
精华帖精华帖星级3级 精编帖 推荐帖


只看楼主 只看精华 只看精编 16楼 2019-12-14 11:00:41
以下是引用东方红一红在2019-12-13 11:23:16的发言 >12楼

 伊默,算你运气好,既不是你的问题,也不是系统bug。这种问题,难得一遇。我的理解可以算为数字计算机的系统误差。你的视野又扩展了,应该是痛并快乐着。

我其实是早年在EXCEL中遇到的。处理财务数据(小数点后两位)时,金额较少时,你看不出来,当处理金额很大时,就会出现错误。和会计手工记账对不上了。这才理解浮点的数据格式和有效位数的问题。

后来在工程计算上,也会使用EXCEL来计算;如计算连续轧制压下量、每道的减径量等计算。理论上当然是使用上道次的结果作为本次计算的初值,计算本道次压下量;实际上不行的!虽然显示的永远是一长串数字,但是有效位数越来越少,计算结果离真值的误差会越来越大。

这主要表现在浮点数据的乘除运算上,改变数据处理方式,浮点乘除运算只用一次,保持可信有效数据长度不至于减少太多。


我记得,早年有个报道,好像是伦敦金融中心的程序员。就是利用这个浮点计算的问题,将银行每天成千上万笔交换中,汇率计算的舍去误差,在程序中偷偷存到自己户头上,居然累计了大量财富。


 
以下网友喜欢您的帖子:

  
侠圣

经验值: 2990
发帖数: 622
精华帖: 2
回复:BUG? BUG? 我觉得应该算是BUG
推荐帖


只看楼主 只看精华 只看精编 17楼 2019-12-14 13:31:23

PLC 此类使用浮点数标准  ( 32bit ,64bit 128bit ) 来表示实数,总觉得不踏实。



开始行动,停止唉声叹气 ^_^ Tel:一三四三四零九八 后 面 三个零
以下网友喜欢您的帖子:

  
奇侠

经验值: 6267
发帖数: 1765
精华帖: 0
回复:BUG? BUG? 我觉得应该算是BUG
推荐帖


只看楼主 只看精华 只看精编 18楼 2019-12-14 15:35:49
双精度浮点数就可以了,单精度的123456789+1,这个就算不准了。
 
以下网友喜欢您的帖子:

  
游士

经验值: 154
发帖数: 9
精华帖: 0
回复:BUG? BUG? 我觉得应该算是BUG


只看楼主 只看精华 只看精编 19楼 2019-12-14 20:49:26

看着大神们的讨论,一头雾水。


 
以下网友喜欢您的帖子:

  
  • 上一页
  • 1
  • 下一页
×
扫描打开手机版
您收到0封站内信:
×
×