User1246594 @ 2024-01-14 13:43:34
这是一份代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
int a,b,ans=0;
cin>>a>>b;
while(a--)ans++;
while(b--)ans++;
cout<<ans;
return 0;
}
不难发现,数据大了会T,有负数也会T。
问题是,我加了O2之后竟然神奇的过了,甚至只用了3ms。
有负数的数据O2是怎么做到AC的?建议优化O2。
by 2huk @ 2024-01-14 13:45:41
@dingjunwei666
O2 会自动把 while(a--)ans++;
理解成:
ans
这个变量自增了 a
次。所以它会执行 ans += a
。但实际上是错误的。b
同理。
by cff_0102 @ 2024-01-14 13:50:37
@dingjunwei666 被O2优化了,编译器把这个语句优化成了a+b
by Pink_Cut_Tree @ 2024-01-14 14:00:54
@dingjunwei666
-O2
是一个很神奇的东西。
具体地,
while(a--)ans++;
会被优化成
ans+=a;
没开 -O2
则没有这个效果
by only_a_speaker @ 2024-01-14 14:35:57
您好,楼上已经解释了优化的效果。至于为什么优化效果是这样的,可能需要学习补码知识之后才能更好地理解。
by kexiye @ 2024-01-29 16:56:08
废物们
by yinjiayu @ 2024-01-31 20:28:02
氧化了(确信)
by LionBlaze @ 2024-10-14 22:37:22
@only_a_speaker 这个知识和补码相关内容没有任何关系。
您好,在不懂的情况下,请勿胡乱做答,误导别人。
by only_a_speaker @ 2024-10-16 12:28:22
@LionBlaze
你好,我一般是不给人免费上课的,但是由于你连续追着我几个帖子咬,看在你诚心求教的面子上我就给你上个课。
首先,有符号整数运算溢出是 UB
。如果不懂的话可以自己去查。所以传递负数写的 while(a--)
是 UB
。
其次,编译器会在假定程序员不是二傻子写的,进而在不存在 UB
的基础上进行优化。所以如果编译器看到你写的 while(a--)
,出于礼貌起见(不把你当成二傻子),会做出 a
非负的假定。
最后,帮你科普一下补码的一个优势:
补码的优点在于它统一了加法和减法运算,无论正数还是负数,加法和减法都可以通过相同的算法实现。
这就是为什么“最后的答案是对的”,尽管编译器高估了你的水平,只想进行正数加法。但是对于负数的输入同样有效。
下次来请教问题记得讲点礼貌哦。
by LionBlaze @ 2024-10-16 16:56:50
@only_a_speaker 你其他的说得都对,但是这和补码有什么关系。
by only_a_speaker @ 2024-10-16 21:29:54
@LionBlaze
您好,请看清楚帖主的问题是
为什么能过
你传了负数,编译器当正数来做加法,就一定能过吗?错误的。
在补码里,正数和负数加法,统一使用简单的进位加法。
但如果是反码呢?我们都知道 1+1=2
0b00...001+0b00...001=0b00...010
但是如果是 (-1)+(-1)
,还使用简单的进位加法会怎么样?
0b11...110+0b11...110=0b11...100
发现使用简单的进位加法, (-1)+(-1)=(-3)
。也就是说反码的负数加法更复杂,不能用简单的进位加法实现。
接前文,编译器为了不把你看成二傻子,所以已经认定数字是正数了。那么当编译器基于优化的目的,使用简单的进位加法操作两个负数的时候,自然就会算错了,就不会让帖主过了。
懂了吗?