提问人:Bemin Dawoud 提问时间:10/12/2023 最后编辑:chqrlieBemin Dawoud 更新时间:10/12/2023 访问量:124
为什么此代码的最后一次迭代无法正常工作?
Why is the last iteration of this code is not working properly?
问:
我正在编写一个程序,该程序打印前 50 个斐波那契数,从 1 和 2 开始。 数字必须用逗号分隔,后跟除最后一个数字以外的空格,应以换行符结尾。
我尝试过的代码:
int main(void)
{
int fib[50];
fib[0] = 1;
fib[1] = 2;
int i;
for (i = 0; i < 50; i++)
{
if (i == 0)
{
printf("%d ,", fib[0]);
}
else if (i == 1)
{
printf("%d ,", fib[1]);
}
else if (i == 49)
{
fib[i] = fib[i-1] + fib[i-2];
printf("%d", fib[i]);
}
else
{
fib[i] = fib[i-1] + fib[i-2];
printf("%d ,", fib[i]);
}
}
printf("\n");
return (0);
}
我得到的结果:
1 ,2 ,3 ,5 ,8 ,13 ,21 ,34 ,55 ,89 ,144 ,233 ,377 ,610 ,987 ,1597 ,2584 ,4181 ,6765 ,10946 ,17711 ,28657 ,46368 ,75025 ,121393 ,196418 ,317811 ,514229 ,832040 ,1346269 ,2178309 ,3524578 ,5702887 ,9227465 ,14930352 ,24157817 ,39088169 ,63245986 ,102334155 ,165580141 ,267914296 ,433494437 ,701408733 ,1134903170 ,1836311903 ,2971215073 ,512559680 ,3483774753 ,3996334433 ,3185141890 ,
答:
我只能假设你正在经历溢出。值有一个有限的(特定于平台的)范围。尝试 .此外,您可以在此处简化逻辑。例如,您可以在循环之前打印前两个值;之后,逻辑是规则的,不需要任何(s)。喜欢int
int
long long
if
int i;
long long fib[50];
fib[0] = 1;
fib[1] = 2;
printf("%lld, %lld", fib[0], fib[1]);
for (i = 2; i < 50; i++)
{
fib[i] = fib[i-1] + fib[i-2];
printf(", %lld", fib[i]);
}
printf("\n");
评论
int
值有一个有限的(特定于平台的)范围。超出了有效范围。一个是(大概在您的平台上)32 位。如果将两个较大的 32 位值相加,并且结果超过 32 位,则该值会溢出(并变为负数)。这是因为二进制值存储在 2 的补码表示中。 所有位都是真的。int
-1
除了关于整数溢出的注释外,还可以使用分隔符并在第一次迭代后更改逗号,而不是测试是否在最后一次迭代中,从而以简洁的方式处理逗号。
如果您只是输出斐波那契数列,也确实没有必要存储它们。相反,我们可以只跟踪两个数字,并在每次迭代时更新它们。 如果我们遵循这个算法,每次迭代的第一个数字就是下一个斐波那契数列:(0, 1) -> (1, 1) -> (1, 2) -> (2, 3) -> ...
0 -> 1 -> 1 -> 2 -> ...
#include <stdio.h>
#include <stdint.h>
int main(void) {
uint64_t a = 0, b = 1;
const char *sep = "";
for (int i = 0; i < 50; ++i) {
printf("%s%lu", sep, a);
sep = ", ";
uint64_t c = a;
a = b;
b += c;
}
printf("\n");
}
输出:
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155, 165580141, 267914296, 433494437, 701408733, 1134903170, 1836311903, 2971215073, 4807526976, 7778742049
评论
'long long'占用更多的字节来存储值,可以避免在这种情况下溢出。
代码中存在多个问题:
您必须包括才能正确使用。您可能忘记了问题代码中的那一行,但正如发布的那样,代码具有未定义的行为。
<stdio.h>
printf
#include
在当前绝大多数系统上,该类型不够大,无法容纳高达 49 的斐波那契数值。您应该使用保证处理最多 263-1(或 2 64-1)的数字的类型或类型。
int
long long int
unsigned long long int
格式字符串不正确:空格应出现在逗号之后,而不是之前。
"%d ,"
发布的输出与代码不一致:某些数字大于 231-1。这是我用你的代码得到的输出:
1 ,2 ,3 ,5 ,8 ,13 ,21 ,34 ,55 ,89 ,144 ,233 ,377 ,610 ,987 ,1597 ,2584 ,4181 ,6765 ,10946 ,17711 ,28657 ,46368 ,75025 ,121393 ,196418 ,317811 ,514229 ,832040 ,1346269 ,2178309 ,3524578 ,5702887 ,9227465 ,14930352 ,24157817 ,39088169 ,63245986 ,102334155 ,165580141 ,267914296 ,433494437 ,701408733 ,1134903170 ,1836311903 ,-1323752223 ,512559680 ,-811192543 ,-298632863 ,-1109825406
但请注意,有符号整数溢出的行为是未定义的,因此其他行为是可能的,尽管可能性不大。
不需要数组,您可以只使用 3 个变量并循环它们。
更容易将前 2 个数字设为特例,并在每个下一个数字之前输出一个空格。
,
是否要打印以 or 或 开头的斐波那契数列,甚至是一个约定俗成的问题。意大利数学家斐波那契本人在他的时代(公元 1202 年)在他的 Liber Abaci 中讨论兔子种群增长时使用了它。事实上,斐波那契因在欧洲引入以 10 为基数的符号和从他长大的阿拉伯世界进口的零概念而受到赞誉。手稿图片中的数字显示了使用印度-阿拉伯数字变体的序列号。在现代,更传统的是将序列从开始并将它们命名为 F 0 和 F1。
1, 2
0, 1
1, 1
1, 2
0, 1
这是修改后的版本:
#include <stdio.h>
int main(void) {
unsigned long long a = 1, b = 2;
printf("%llu, %llu", a, b);
for (int i = 2; i < 50; ++i) {
unsigned long long c = a + b;
printf(", %llu", c);
a = b;
b = c;
}
printf("\n");
return 0;
}
评论
int
uint64_t