【问题标题】:C multiplication error [duplicate]C乘法错误[重复]
【发布时间】:2014-05-05 19:11:02
【问题描述】:

为什么在我运行C代码的时候会这样

float x = 4.2
int y = 0
y = x*100
printf("%i\n", y);

我得到 419 回来?不应该是420吗? 这让我很难过。

【问题讨论】:

标签: c math floating-point


【解决方案1】:

为了说明,看一下中间值:

int main()
{
    float x = 4.2;
    int y;

    printf("x = %f\n", x);
    printf("x * 100 = %f\n", x * 100);
    y = x * 100;

    printf("y = %i\n", y);

    return 0;
}

x = 4.200000            // Original x
x * 100 = 419.999981    // Floating point multiplication precision
y = 419                 // Assign to int truncates

根据@Lutzi 的出色建议,如果我们以高于它们所代表的精度打印所有浮点值,则可以更清楚地说明这一点:

...
printf("x = %.20f\n", x);
printf("x * 100 = %.20f\n", x * 100);
...

然后您可以看到分配给x 的值一开始并不完全精确:

x = 4.19999980926513671875
x * 100 = 419.99998092651367187500
y = 419

【讨论】:

  • 您可以在输出中使用极高的精度来更好地展示您的观点,例如“x = %.36f\n”。
  • @Lutzi 是的,确实如此。感谢您的建议。
【解决方案2】:

浮点数存储为近似值,而不是精确的浮点值。它有一个表示,因此当您将其转换为整数时,结果会被截断。您可以查看有关here的更多信息。

这是单精度浮点数的示例表示:

【讨论】:

    【解决方案3】:

    float 不够大,无法精确存储 4.2。如果您以足够的精度打印 x,您可能会看到它显示为 4.19999995 左右。乘以 100 得到 419.999995 并且整数赋值截断(向下舍入)。如果您将 x 设为双倍,它应该可以工作。

    【讨论】:

    • double 不能完全代表 4.2,就像 float 可以一样。如果最接近 4.2 的 double 高于 4.2 而不是低于 4.2,则它可以通过 double 类型的“运气”工作,但不看,它的第一个近似值是 50-50。
    • 更准确地说,4.2 的存储值的十进制表示是4.19999980926513671875。是的,你的猜测是正确的,在双精度下,代表4.2的存储值是4.20000000000000017763568394002504646778106689453125
    【解决方案4】:

    4.2 不在浮点数的有限数空间中,因此系统使用最接近的可能近似值,略低于4.2。如果现在将此乘以 100(这是一个精确的浮点数),您将得到 419.99somethingprintf()%i 一起执行的不是舍入,而是截断 - 所以你得到 419。

    【讨论】:

    • 这个答案的“printf() 用 %i 执行不是舍入,而是截断”部分是错误的。函数printf 是可变参数。在第一个参数之后,它不对其参数执行任何转换。 assignment y=419.99something 转换为 419。将浮点数传递给 printf("%i 将是未定义的行为。
    • @PascalCuoq - 这正是我所说的:你拿 419.99something 并 printf('%i') 它......这当然意味着演员。英语不是我的第一语言,但我会认为这是没有野心的
    猜你喜欢
    • 1970-01-01
    • 2015-03-10
    • 2012-06-06
    • 1970-01-01
    • 2013-12-18
    • 1970-01-01
    • 2013-08-17
    • 2020-09-03
    • 2012-09-18
    相关资源
    最近更新 更多