long long reverse(long long x) {
long long reversednum=0;
int sign=1;
if(x<0)
sign=-1;
x=abs(x);
while(x)
{
reversednum=reversednum*10;
reversednum=reversednum+(x%10);
x=x/10;
}
return (reversednum<INT_MAX || reversednum>INT_MIN)?reversednum*sign:0;
}
我的大多数测试用例都满意,除了这个返回输出1056389759的1534236469.我看到很多建议并将其改为long long。但仍然会产生相同的结果。希望有人会帮助我。提前致谢!! 假设输入是32位有符号整数。当反向整数溢出时,我的函数应返回0
答案 0 :(得分:1)
在反转之前检查数字非常复杂,所以:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <limits.h>
long long reverse(long long x)
{
long long reversednum = 0;
// just in case
// please be aware that the minimum size for "int" is 16-bit!
// you might think about changing it to an actual number if you
// really need 32-bit
long long int_max = INT_MAX;
long long int_min = INT_MIN;
int sign = 1;
// abs() would have been wrong for "long long", it should have been "llabs()"
// also: you already checked if x is negative, no need for "abs()" here
if (x < 0){
sign = -1;
x = -x;
}
while (x) {
reversednum = reversednum * 10;
reversednum = reversednum + (x % 10);
x = x / 10;
}
// you want "reversednum" to be in the range {int_min < reversednum < int_max}
// hence the need to check both limits
return (reversednum < int_max
&& reversednum > int_min) ? reversednum * sign : 0;
}
int main(int argc, char **argv)
{
long long x;
if (argc != 2) {
fprintf(stderr, "Usage: %s integer\n", argv[0]);
exit(EXIT_FAILURE);
}
errno = 0;
x = strtoll(argv[1], NULL, 10);
if ((errno == ERANGE && (x == LLONG_MAX || x == LLONG_MIN))
|| (errno != 0 && x == 0)) {
fprintf(stderr, "Input %s caused an error in converting: %s\n", argv[1],
strerror(errno));
exit(EXIT_FAILURE);
}
printf("IN : %lld\n", x);
x = reverse(x);
printf("OUT : %lld\n", x);
exit(EXIT_SUCCESS);
}
正如评论中所述,但值得在此重复:限制int_*
保证最低只有16位(ISO / IEC 9899:2011 5.2.4.2.1)!
答案 1 :(得分:1)
我相信你必须在printf中使用%ld ...使用%lld!简单的错误:)
分析发生的事情:
当你进入 1534236469 结果应该是9646324351,这是由函数正确生成的(是的!)。
在二进制中,9646324351被写为00000010 00111110 11110111 00111010 01111111。现在,您的编译器为long分配4个字节,为long long分配8个字节。所以当你打印很长时间(它本来应该很长)时,编译器将简单地从二进制文件中取出前4个字节并丢弃其余部分。这意味着您的编译器只需要使用00111110 11110111 00111010 01111111,相当于十进制的1056389759。因此输出......所以它意味着你的功能和逻辑是正确的(phewwww .... !!!!)但是你犯了一个愚蠢的错误。
答案 2 :(得分:0)
您的问题的问题在于您假设问题出在符号位(并且您不能溢出有效位),并且它不存在,您在接近符号之前就会出错位。在分析了你的代码之后,在最后一次乘法中有一个最终的无符号32位整数溢出10(你乘以10而不是2,所以你可以在每次乘法中得到最多4个新位,使溢出更容易) ,即使你进行了unsigned
算术运算(推荐使用,因此你不需要使用符号)
只需修改一些代码即可使用unsigned
算术,并在reverse
函数中为此程序版本发布一些跟踪:
#include <stdio.h>
#include <stdlib.h>
unsigned reverse(unsigned x, unsigned base)
{
unsigned reversednum=0;
while(x) {
unsigned digit = x % base;
reversednum *= base;
reversednum += digit;
x /= base;
printf("reverse: digit=%u, reversednum=%u, x=%u, base=%u\n",
digit, reversednum, x, base);
}
return reversednum;
}
int main()
{
char buffer[100];
while ( fgets(buffer, sizeof buffer, stdin) ) {
unsigned x = (unsigned) atol(buffer);
printf("reverse(%u) => %u\n", x, reverse(x, 10));
} /* while */
} /* main */
使用您的输入执行:
$ reversed
23
reverse: digit=3, reversednum=3, x=2, base=10
reverse: digit=2, reversednum=32, x=0, base=10
reverse(23) => 32
1534236469
reverse: digit=9, reversednum=9, x=153423646, base=10
reverse: digit=6, reversednum=96, x=15342364, base=10
reverse: digit=4, reversednum=964, x=1534236, base=10
reverse: digit=6, reversednum=9646, x=153423, base=10
reverse: digit=3, reversednum=96463, x=15342, base=10
reverse: digit=2, reversednum=964632, x=1534, base=10
reverse: digit=4, reversednum=9646324, x=153, base=10
reverse: digit=3, reversednum=96463243, x=15, base=10
reverse: digit=5, reversednum=964632435, x=1, base=10 <-- after multipliying
by base, unsigned
overflows here to
9,646,324,350 -
2*4,294,967,296 ==
1,056,389,758
reverse: digit=1, reversednum=1056389759, x=0, base=10
reverse(1534236469) => 1056389759
您的代码的主要问题是您的号码中的最后一位数字(十位数字)可以是0..9
而十位数字中的第一位数字不能超过{{1} } (如果是4
,那么第二个不能超过4
...或溢出,给出的数字大于无符号的最大可能值例如,所有大于1,000,000,000的数字在5或更多中完成,将从4中完成的数字组中溢出,所有以2或更多结束的数字将溢出,从24中完成的数字溢出,那些
在2
中完成前一个数字大于924
,所有内容都会溢出,......所以直到在基数中形成数字4
进行计算。
这也适用于带符号的数字,因此您必须将函数的域限制为不溢出。由于最后一位数为MAX_UINT
的所有十位数字都会溢出,因此对于第一个溢出的数字,我建议最大值5
。对于不同的基础,你有不同的限制,所以你必须小心(我不应该允许大于或等于1,000,000,005
的数字,因为你将开始得到数字的窗口溢出,穿插数字,不包括在32位未签名的情况下,第一个失败的数字是base^(floor(log(MAX_UINT)/log(base))) ==> 1,000,000,000
,而对于有符号的数字则是1,000,000,005
)
对于64位1,000,000,003
,限制应为unsigned
(1.0E19
),因为== 10^((int)(log((double)MAX_ULONG_LONG)/log(10.0)))
是第一个失败的数字。对于10,000,000,000,000,000,002
s,限制应为signed
,因为1.0E18
应该是第一个失败的数字。
考虑一个与一组32位整数一起正常工作的函数,你应该像你那样做一个断言,但不是使用1,000,000,000,000,000,039
或INT_MAX
,而是必须使用实际的边界您的号码限制。像
INT_MIN
甚至允许在运行时禁用生产代码的范围检查。 #include <stdint.h>
#include <assert.h>
int32_t reverse(int32_t x)
{
assert(x > -1000000000 && x < 1000000000);
int32_t reversednum = 0;
while(x) {
int digit = x % 10;
reversednum *= 10;
reversednum += digit;
x /= 10;
} /* while */
return reversednum;
} /* reverse */
已固定为base
,因为这是您的功能,10
限制取决于编号基础的选举。
答案 3 :(得分:-1)
当您应该使用LLONG_MAX和LLONG_MIN时,您正在使用INT_MAX和INT_MIN
long long reverse(long long x) {
long long reversednum = 0;
int sign = 1;
if (x<0)
sign = -1;
x = abs(x);
while (x)
{
reversednum = reversednum * 10;
reversednum = reversednum + (x % 10);
x = x / 10;
}
return (reversednum<LLONG_MAX || reversednum>LLONG_MIN) ? reversednum*sign :
0;
}
int main(){
long long int i;
scanf_s("%lld", &i);
printf("%lld",reverse(i));
scanf_s("%d", &i);
}
已经在值1232和您给定的值上测试了显示不良结果(1534236469)。