有时解题中需要将变量n
转为正数处理,而在变量n
取值范围很大时,如32位有符号整数[−231, 231 − 1] ,需要注意转换时越界问题。
int取值范围 | Value |
---|---|
二进制 | [−231, 231 − 1] |
十进制 | [-2147483648, 2147483647] |
十六进制 | [0x80000000, 0x7fffffff] |
1、越界现象:
以下函数,当传入参数n
为-2147483648
,转换为正数时会发生越界问题。
void myFunc(double x, int n) { // 输出|n|次x
int abs_n = abs(n); // n为-2147483648时越界,abs_n 仍为-2147483648
for(int i = 0; i!=abs_n; i++){
cout<<x<<end;
}
}
以上代码陷入死循环,因为对INT_MIN
取绝对值仍为INT_MIN
,(0x80000000按照补码取负规则还是0x80000000)。
2、解决方法:
2.1、先扩大值类型,再取绝对值:
void myFunc(double x, int n) { // 输出|n|次x
long long n_ = n; // n_在 long long范围内,不越界
方式一:
n_ = abs(n_); // n_为2147483648
方式二:
n_ = -n_; // 直接取负号更好
for(int i = 0; i!=abs_n; i++){
cout<<x<<end;
}
}
将int
类型扩大至long long
类型,这样就不会溢出了。因为有的编译器int与long长度相同,因此必须扩大至long long
。
2.2、求绝对值函数abs()源码:
int abs(int number)
{
return( number>=0 ? number : -number );
}
由abs()
函数源码可知,负数求绝对值为直接取负号,因此直接使用方式二:n_ = -n_;
更好,省区了函数调用过程。
3、实验测试:
abs函数(取绝对值)返回值可以是负数。
参考资料:
1、建议浏览:牛客网选择题:math.h的abs返回值()
2、那个您经常用的abs函数(取绝对值)真的总是返回非负数吗
3、C标准库函数abs的一个错误
总结:
1、负数取绝对值小心越界问题,因此先将值范围扩大如int->long long
,再取绝对值。
2、取绝对值函数为直接加负号,因此直接用n_ = -n_;
,省区函数调用过程。
3、对INT_MIN
取绝对值仍为INT_MIN
,(0x80000000按照补码取负规则还是0x80000000)。