【问题标题】:Why did I get different answers in vscode?为什么我在 vscode 中得到不同的答案?
【发布时间】:2020-12-07 11:59:23
【问题描述】:

我的代码:

#include <stdio.h>
#include <math.h>

int main (void)
{
    int n = 0;
    int sum = 0;
    printf("Enter a number: ");
    scanf("%d", &n);
    for (int power = 1; power <= n; power++)
    {
        printf("%d %s ", (int)pow(10, power) - 1, power == n ? "=" : "+");
        sum += (int)pow(10, power) - 1;
    }
    printf ("%d", sum);
    return 0;    
}

使用 gcc 在 Vs 代码中输出:

Enter a number: 5
9 + 98 + 999 + 9998 + 99999 = 111103

在线编译器的输出:

Enter a number: 5
9 + 99 + 999 + 9999 + 99999 = 111105

我的问题:为什么?发生这种情况了吗?

【问题讨论】:

  • The classic answer 。此外,使用相同的编译器和不同的优化设置,您可能会得到不同的答案。
  • 对于这些类型的问题,当涉及到编译器版本时,请尽可能具体。 “在线编译器”不是一个很好的描述,“带有 gcc 的 VS 代码”也不够。什么版本?有哪些选择?
  • 几个问题:首先,代码总是向下舍入,如果 pow 结果略低于封闭整数,这可能是一个问题。其次,它不检查输入。它很容易溢出。第三:总和累加舍入误差。
  • 我现在用 gcc 9.3、onlinegdb.com/online_c++_compiler 和 Visual c 版本 19.16.27043 测试了上面的代码。他们都没有表现出上述行为。您是否使用了一些过时的编译器版本?您使用了哪个运行时/sdk 版本(如果您使用的是 vc)?

标签: c algorithm


【解决方案1】:

pow 及其实现可能存在问题,可能是由于平台或编译器不同。

为什么不使用依赖浮点运算并导致复合舍入错误(并且可能包含错误)的pow,为什么不使用简单的乘法呢?如果您以10 开始循环,那么您可以将其乘以10 每次迭代以获得您想要的结果。

大概是这样的:

unsigned sum = 0;
for (unsigned power = 0, value = 10; power < n; ++power, value *= 10)
{
    sum += value - 1;
}

[打印遗漏]

【讨论】:

  • @KonradRudolph:IEEE 754 没有完全约束pow 和其他例程的结果。所以这不是一致性问题。此外,C 实现通常不符合 IEEE 754。
  • @EricPostpischil 显然我错了,因为 GCC 和 clang 在如此基本的问题上存在分歧,但我看不出 pow 在 10 的整数幂上如何给出不同的答案,而不会成为一个明显的错误。仅仅因为 IEEE-754 没有“完全”约束这些功能,并没有给实现许可去做他们想做的任何事情。这给出错误结果的事实应该是非常出乎意料的。
  • @Someprogrammerdude:尽管如此,将其描述为浮点问题是不正确的。在这种情况下,浮点不会妨碍返回正确的结果。 Microsoft 的 pow 返回不正确的结果,即使在这种情况下可能出现正确的结果并且由其他实现返回。当整数例程返回不正确的结果时,我们不会将其描述为整数错误。
  • @KonradRudolph:请向我们展示您将如何实施 pow 以在所有可能获得准确结果的情况下返回正确结果。
  • @EricPostpischil 我说这是可能的。我是说即使这是不可能的,pow 不应该无条件犯错误。特别是基础类型范围内的 10 的整数幂应该可以工作(如果没有其他原因,它们在实际使用中相当频繁地出现,例如标记对数缩放图)。事实上,clang 在这里做了一些非常奇怪的事情:godbolt.org/z/reKM57
【解决方案2】:

我只是使用函数“round”返回最接近参数中指定值的整数舍入

#include <stdio.h>
#include <math.h>

int main (void)
{
    int n = 0;
    int sum=0;
    printf("Enter a number: ");
    scanf("%d", &n);
    for (int power = 1; power <= n; power++)
    {
        sum += (int)round (pow(10, power)) - 1;
    }
    printf ("%d", sum);
    return 0;
}

【讨论】:

  • 这并没有真正回答为什么会发生的问题,但是(匆忙)接受的答案也没有。然而,与提供完全不同代码的公认答案方法相比,这个答案更好地针对出现问题的地方。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-26
  • 1970-01-01
  • 2021-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多