技术论坛

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

返回主题列表
作者 主题
伊默
至圣

经验值:18578
发帖数:4264
精华帖:118
楼主    2019-12-10 19:31:20
主题:BUG? BUG? 我觉得应该算是BUG 精编帖 

现场一台机器出现了个问题,我是按照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
yming
至圣

经验值:127285
发帖数:21992
精华帖:824
1楼    2019-12-10 21:26:20
精华帖  精编帖  主题:回复:BUG? BUG? 我觉得应该算是BUG

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

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


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


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

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

学而时习之,不亦说乎?温故而知新,不亦乐乎?
Zane
版主

经验值:76091
发帖数:19115
精华帖:378
3楼    2019-12-10 21:55:50
精编帖  主题:回复:BUG? BUG? 我觉得应该算是BUG


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


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

Zane 注册自动化系统工程师 Always save before download
伊默
至圣

经验值:18578
发帖数:4264
精华帖:118
5楼    2019-12-11 08:01:07
精编帖  主题:回复:BUG? BUG? 我觉得应该算是BUG
ROUND,FLOOR当然都试过,你试试? 再一个我这应用原则上只能用TRUNC,截尾取整,因为我要的是最高位。 另外,这和隐式转换没关系吧? 我都是显示转换,只不过转成REAL有问题,而转成LREAL说没问题罢了。
I can do it
master_mb
侠圣

经验值:4030
发帖数:1259
精华帖:6
9楼    2019-12-13 08:52:01
精编帖  主题:回复:BUG? BUG? 我觉得应该算是BUG

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

说到底还是数据精度问题

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

9.0109125/0.6931474=12.99999466203004


QQ 402550360 TEL 17606539722
伊默
至圣

经验值:18578
发帖数:4264
精华帖:118
11楼    2019-12-13 11:04:13
精华帖  精编帖  主题:回复:BUG? BUG? 我觉得应该算是BUG

不是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
Zane
版主

经验值:76091
发帖数:19115
精华帖:378
14楼    2019-12-14 08:59:20
精华帖  精编帖  主题:回复:BUG? BUG? 我觉得应该算是BUG
数据取进来,取最高位字节,与0或运算,结果为零,则跳过取下一字节,不为零,则左移取第一位移出值为1的位数,根据字节数与移位次数,(n字节+1)*8-n移位,即得最高位1的位数。
一个双字,最多比较3次移位7次。这种算法也适合长型数据。
Zane 注册自动化系统工程师 Always save before download
yming
至圣

经验值:127285
发帖数:21992
精华帖:824
15楼    2019-12-14 09:56:52
精编帖  主题:回复:BUG? BUG? 我觉得应该算是BUG

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

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

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


学而时习之,不亦说乎?温故而知新,不亦乐乎?
yming
至圣

经验值:127285
发帖数:21992
精华帖:824
16楼    2019-12-14 11:00:41
精华帖  精编帖  主题:回复:BUG? BUG? 我觉得应该算是BUG

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

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

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


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

学而时习之,不亦说乎?温故而知新,不亦乐乎?
'Razor
至圣

经验值:20114
发帖数:2773
精华帖:23
20楼    2019-12-15 18:08:03
精编帖  主题:回复:BUG? BUG? 我觉得应该算是BUG

浮点数的运算有好大的坑,如:

a+b+c != a+(b+c);

a*b*c != a*(b*c);


Less is more……
我家牛
奇侠

经验值:9086
发帖数:2334
精华帖:30
21楼    2019-12-16 10:16:25
精编帖  主题:回复:BUG? BUG? 我觉得应该算是BUG

你这是有的数吧?

1.0+1.0+1.0 != 1.0+(1.0+1.0)???;

1.0*0.1*10.0 != 1.0*(0.1*10.0)???;

不过记得哪位大侠说过,浮点数忌讳用等于,应该用区间。


学习ing!学习!
您收到0封站内信:
×
×
信息提示
很抱歉!您所访问的页面不存在,或网址发生了变化,请稍后再试。