我正在尝试实现一个简单的程序来递归计算数字的力量。代码会测试超过INT_MAX
或INT_MIN
的值,并应指定power = -1
。但是,即使在一定数量的递归调用之后,当结果变量超过最大值时,它也不会像我希望的那样打印错误消息。
#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
#include <errno.h>
void power(int x, int n, int* result);
int main(int argc, char* argv[])
{
int x, n, result = 1;
x = 10;
n = 20;
if (n < INT_MIN || x < INT_MIN)
{
fprintf(stderr, "Argument(s) out of range\n");
return 0;
}
if (n > INT_MAX || x > INT_MAX)
{
fprintf(stderr, "Argument(s) out of range\n");
return 0;
}
if (x != 0)
{
power(x, n, &result);
if (result == -1)
{
fprintf(stderr, "Result is out of range\n");
return 0;
}
}
printf("%d to the power %d = %d\n", x, n, result);
return 0;
}
void power(int x, int n, int *result)
{
if (n == 0)
{
return;
}
if (*result > INT_MAX)
{
*result = -1;
return;
}
if (*result < INT_MAX)
{
*result = (*result) * x;
power(x, n - 1, result);
}
}
答案 0 :(得分:2)
(你的倒数第二行代码:)当*result = (*result) * x;
返回超过INT_MAX时,它会失败,也许*结果将包含结果%INT_MAX的剩余部分,但也许是一些狂野的东西 - 你永远不会有机会在下一次迭代中测试它是否更大。
如果您想测试结果仍然是好的,您需要在实际计算之前检查产品是否超出范围,例如使用:if (*result < INT_MAX/x)
。如果这是真的,那么 仍然可以再次繁殖。
答案 1 :(得分:1)
完成乘法后检查溢出为时已晚,但您可以在执行之前进行测试。
*result = (*result) * x;
可以这样做
if(INT_MAX / x < *result) {
*result = -1;
}
else {
*result *= x;
}
您的代码必须是正数,因为您使用-1
表示溢出(本身是-1
的强项)。在这种情况下,使用unsigned int
甚至更大的类型可以获得更多的范围。
修改强>:
我已经改变了你的程序,返回结果而不是使用指针参数。它适用于正数。
#include <stdio.h>
int power(int x, int n)
// calculate x power n
{
int res;
if (n == 0) {
return 1;
}
res = power(x, n-1); // recurse
if(INT_MAX / res < x) { // check for overflow
return -1;
}
return x * res;
}
int main(void)
{
int i, n;
n = 10;
for(i=0; i<11; i++) {
printf("%d power %d = %d\n", n, i, power(n, i));
}
return 0;
}
节目输出
10 power 0 = 1
10 power 1 = 10
10 power 2 = 100
10 power 3 = 1000
10 power 4 = 10000
10 power 5 = 100000
10 power 6 = 1000000
10 power 7 = 10000000
10 power 8 = 100000000
10 power 9 = 1000000000
10 power 10 = -1
答案 2 :(得分:0)
您只能阻止超过INT_MAX,因为实际上升会导致溢出。除非你能捕获溢出(C不提供任何东西,遗憾的是),你将不得不预防它们。
在乘法之前划分的另一个答案实际上允许你做这种预防。
答案 3 :(得分:0)
第1步改进算法
OP的当前方法需要n
次迭代/递归。而不是n
使用power(x, n-1);
来电,使用log2(n)
次来电并每次减半n
,
递归并不是真的需要。一个简单的循环就可以了。
第2步:测试乘法
在乘法之前,测试潜在的溢出。 Ref
int is_undefined_mult1(int a, int b) {
if (a > 0) {
if (b > 0) {
return a > INT_MAX / b; // a positive, b positive
}
return b < INT_MIN / a; // a positive, b not positive
}
if (b > 0) {
return a < INT_MIN / b; // a not positive, b positive
}
return a != 0 && b < INT_MAX / a; // a not positive, b not positive
}
第3步测试特殊输入
示例:提高负功率。
#include <stdbool.h>
// return true on overflow
bool power(int x, int y, int *zp) {
// Handle negative exponent cases
if (y < 0) {
switch (x) {
case 1:
*zp = 1;
return false;
case -1:
*zp = y % 2 ? -1 : 1;
return false;
}
return true;
}
int z = 1;
int base = x;
for (;;) {
if (y % 2) {
if (is_undefined_mult1(z, base)) return true;
z *= base;
}
y /= 2;
if (y == 0) break;
if (is_undefined_mult1(base, base)) return true;
base *= base;
}
*zp = z;
return false;
}