打印

99.99%可能性,KEIL BUG

[复制链接]
楼主: ayb_ice
手机看帖
扫描二维码
随时随地手机跟帖
41
ayb_ice|  楼主 | 2011-9-27 09:08 | 只看该作者 回帖奖励 |倒序浏览
本帖最后由 ayb_ice 于 2011-9-27 09:10 编辑
t.jm:
这是优化所产生的问题, y = x/4 与 y = x/a 的结果不同并不出乎意料。很多编译器对 /2, /4, /8 等常数分母都是直接使用移位而不是除法,这也不是超出预期,反而是在预期之内。
对于分子分母都是变量,keil 中 ...
highgear 发表于 2011-9-27 09:00

你说的也很对,但其它编译器都是正确的,一致的,我至少试过4~5种不同的编译器
优化都不能保证结果正确,还谈什么优化,还是BUG

使用特权

评论回复
42
highgear| | 2011-9-27 09:12 | 只看该作者
呵呵,这么说吧,我在不同的编译器下做过大量的数**算,除了vc++, 嵌入式中基本上都是使用整数运算,但我从不使用 /2, /4, /8等等,都是直接使用 >>1, >>2, >>3等,了解编译器的行为是一个嵌入式程序员基本功课。

使用特权

评论回复
43
t.jm| | 2011-9-27 09:15 | 只看该作者
t.jm:
这是优化所产生的问题, y = x/4 与 y = x/a 的结果不同并不出乎意料。很多编译器对 /2, /4, /8 等常数分母都是直接使用移位而不是除法,这也不是超出预期,反而是在预期之内。
对于分子分母都是变量,keil 中 ...
highgear 发表于 2011-9-27 09:00

晕!这根本不关优化的事,优化也是好的行为,肯定的!
只要它能保证:(-5/4) == (-5/3),它就不是BUG了,也就没有什么危害至多是计算精度问题,
然而:(-5/4) != (-5/3),而且|(-5/4)| > |(-5/3)|这才是致命的危害!
再讨论这个问题前,舍入问题我是有考虑的,你应该多多考虑:
(-5/4) != (-5/3),而且|(-5/4)| > |(-5/3)|的严重性!

使用特权

评论回复
44
highgear| | 2011-9-27 09:18 | 只看该作者
ayb_ice: 你不能说“优化都不能保证结果正确”, 只能说结果不是你所预期的。因为,-5/4为-1或是 -2 都是正确的。

使用特权

评论回复
45
t.jm| | 2011-9-27 09:20 | 只看该作者
呵呵,这么说吧,我在不同的编译器下做过大量的数**算,除了vc++, 嵌入式中基本上都是使用整数运算,但我从不使用 /2, /4, /8等等,都是直接使用 >>1, >>2, >>3等,了解编译器的行为是一个嵌入式程序员基本功课。 ...
highgear 发表于 2011-9-27 09:12

恕我直言,你这点技巧什么都不算,甚至你都搞错方向了,
是除法(/)能代替移位(>>),而不是移位(>>)代替除法(/),我要/3怎么办?

使用特权

评论回复
46
ayb_ice|  楼主 | 2011-9-27 09:33 | 只看该作者
ayb_ice: 你不能说“优化都不能保证结果正确”, 只能说结果不是你所预期的。因为,-5/4为-1或是 -2 都是正确的。
highgear 发表于 2011-9-27 09:18

如果只考虑结果这个确实没有错,但起码必须保持一致吧
不要一会=-1,一会又等于-2吧
从数学上讲难道
x = -5/4;

y = -5;
z = 4
x = y/z;
是不一样的

使用特权

评论回复
47
computer00| | 2011-9-27 09:42 | 只看该作者
改成int型就对了。

使用特权

评论回复
48
highgear| | 2011-9-27 21:02 | 只看该作者
t.jm: 其实全整数运算需要很多技巧,而且必须对cpu以及编译器有足够的了解,否则就会出现什么 “诡异”,“bug"之类的困惑。
除数是变量时,我想不会有问题,因为编译器一般会使用除法器。对于除数是常数,那么"什么都不算的技巧"相当有用,坦白的说,除了vc++, 我几乎不用常数除法,而是用乘法代替,例如: x /3 可为 x * (65536/3) >> 16 (cpu 具有16x16的乘法器) 或是 x * (256/3) >> 8。

再解释一次:
楼主的情况仅仅是在除数是常数2,4, 8 等而且被除数为负值的情况下出现,是因为编译器优化使用了因为而不是使用除法器,这其实是有经验的程序员所预期的。同时,除非不关注效率,最好不要直接使用常数除法,可以使用 >> 以及乘法代替。

使用特权

评论回复
49
highgear| | 2011-9-27 21:03 | 只看该作者
是因为编译器优化使用了移位而不是除法器

使用特权

评论回复
50
aceice| | 2011-9-27 23:10 | 只看该作者
e...很少用到除法,2,4,8这些一般都是移位代替,效率要高一些。

使用特权

评论回复
51
Dan_| | 2011-9-27 23:54 | 只看该作者
不懂,求高手解答

使用特权

评论回复
52
ayb_ice|  楼主 | 2011-9-28 08:09 | 只看该作者
t.jm: 其实全整数运算需要很多技巧,而且必须对cpu以及编译器有足够的了解,否则就会出现什么 “诡异”,“bug"之类的困惑。
除数是变量时,我想不会有问题,因为编译器一般会使用除法器。对于除数是常数,那么"什么 ...
highgear 发表于 2011-9-27 21:02

问题的焦点就不同的写法要结果一致,程序怎么写,只要合法就行了,何况这是常见写法呢

使用特权

评论回复
53
t.jm| | 2011-9-28 08:13 | 只看该作者
t.jm: 其实全整数运算需要很多技巧,而且必须对cpu以及编译器有足够的了解,否则就会出现什么 “诡异”,“bug"之类的困惑。
除数是变量时,我想不会有问题,因为编译器一般会使用除法器。对于除数是常数,那么"什么 ...
highgear 发表于 2011-9-27 21:02

我只能告诉你,你刚才说的这些“技巧”我全知道!
用>>代替除法,你以为(-5)/ 4  != (-5) >> 2 ???
你说的这个“技巧”根本就无助与解决这个BUG!不管你是用/还是用>>:
1)|(-5)/ 4 | > |(-5) / 3|;

2)|(-5)>> 2 | > |(-5) / 3|; 你会选这种结构吧(>>)??

使用特权

评论回复
54
highgear| | 2011-9-28 09:59 | 只看该作者
t.jm: 其实争论这个情况是不是个 bug, 没有什么结果,因为判据不一致。对于我来说,我预期 x/4 为 x >> 2, 所以我不会认为 x/4 = -2是一个 bug,这也是我即使在 vc++下也不使用 x/4而是用 x>>2 的原因,因为vc++下的 x/4 会+3做调整,即 x/4底层为 (x+(x<0?3:0))>>2, 这会导致vc++ 下的算法程序直接移植后,结果可能不一致。

是不是个 bug, 痣者见痣,忍者见忍。

使用特权

评论回复
55
t.jm| | 2011-9-28 10:20 | 只看该作者
t.jm: 其实争论这个情况是不是个 bug, 没有什么结果,因为判据不一致。对于我来说,我预期 x/4 为 x >> 2, 所以我不会认为 x/4 = -2是一个 bug,这也是我即使在 vc++下也不使用 x/4而是用 x>>2 的原因,因为vc++下的 ...
highgear 发表于 2011-9-28 09:59

你这样的考虑还怎么: 痣者见痣,忍者见忍???
/,>>这些技巧在IAR面前都是浮云,IAR会做出正确而高效的优化!
1)是不是BUG | -5 / 4| > |-5>>2|是铁证!
2)是不是优化,明显地IAR的对比可以让keil无地自容,两个常数的运算居然没有让编译器去完成还谈什么优化?
x = -5/4,应该直接优化为 x = -1,
x = -5 >> 2 应该直接优化为 x = -2!

使用特权

评论回复
56
ayb_ice|  楼主 | 2011-9-28 10:36 | 只看该作者
=-1,=-2确实都是正确的,因为C语言也是这样规定的
但同一个版本的编译器,不同的写法,不同的结果这就不对了,因为不同的写法本质是一样的,根本不可能有其它的解释

使用特权

评论回复
57
t.jm| | 2011-9-28 10:44 | 只看该作者
=-1,=-2确实都是正确的,因为C语言也是这样规定的
但同一个版本的编译器,不同的写法,不同的结果这就不对了,因为不同的写法本质是一样的,根本不可能有其它的解释 ...
ayb_ice 发表于 2011-9-28 10:36

这个意思我早就表达了,
不管编译器(keil.IAR)它采用什么策略去计算 -5/4,-5/3,一致性它必须要遵守的,舍入的方向必须一致,-5/4 = -2,或=-1无非是精度问题,这不致命!
|-5/4|>|-5/3|在同一个软件中出现就是致命问题,藐视它,它就有可能是导致动车追尾的因素!

使用特权

评论回复
58
highgear| | 2011-9-28 10:57 | 只看该作者
IAR 我不知道,楼主的情况是不是bug尚有争议;但 t.jm 说keil“两个常数的运算居然没有让编译器去完成还谈什么优化”,显然是臆想。

使用特权

评论回复
59
MicroMMU| | 2011-9-28 13:19 | 只看该作者
这个应该是在意料之中的事情,编译器为了高效使用了 RLC 指令
这个经常导致算法不稳定,有时甚至无法收敛.

使用特权

评论回复
60
刘前辈| | 2011-9-28 18:44 | 只看该作者
其实不是keil的错。
以8086为例:你用DIV,还是IDIV,同样的 -5/4,将会得到2个结果。关键是。2个结果都是对的: 注意商不一样,余数就不一样!

-5/4= -1……-1;
-5/4= -2……+3;

LZ的题目应写成下面,告诉编译器你要进行有符号除法而不是无符号除法运算
main(void )
{
signed  char  x,y,z;

z=-5;;
x=z/(signed)4;   // 或者x=(signed) z/4;
y=z%4;

while(1);
}

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则