C 复合分配和类型转换问题

C++ compound assignment and type conversion issue

本文关键字:类型转换 问题 分配 复合      更新时间:2023-10-16

我正在计算C 中的组合(15,7)

  1. 我首先使用以下代码并因类型促销错误而获得错误的答案。

    #include <iostream>
    int main()
    {
        int a = 15;
        double ans = 1;
        for(int i = 1; i <= 7; i++)
            ans *= (a + 1 - i) / i;
        std::cout << (int) ans;
        return 0;
    }
    

    输出: 2520

  2. 所以我将 ans *= (a + 1 - i) / i;更改为 ans *= (double)(a + 1 - i) / i;,但仍然得到错误的答案。

    #include <iostream>
    int main()
    {
        int a = 15;
        double ans = 1;
        for(int i = 1; i <= 7; i++)
            ans *= (double) (a + 1 - i) / i;
        std::cout << (int) ans;
        return 0;
    }
    

    输出: 6434

  3. 最后,我尝试了ans = ans * (a + 1 - i) / i,给出了正确的答案。

    #include <iostream>
    int main()
    {
        int a = 15;
        double ans = 1;
        for(int i = 1; i <= 7; i++)
            ans = ans * (a + 1 - i) / i;
        std::cout << (int) ans;
        return 0;
    }
    

    输出: 6435

有人可以告诉我为什么第二个不起作用?

如果未打印出ans而不将其扔给(int),则会看到第二个结果是6434.9999999999990905052982270717620849609375。这真是太近了6535的正确答案,因此显然不再是类型的促销错误。

不,这是经典的浮点不准确。当您编写ans *= (double) (a + 1 - i) / i时,您正在做:

ans = ans * ((double) (a + 1 - i) / i);

将此与第三版进行比较:

ans = ans * (a + 1 - i) / i;

前者首先执行划分,然后进行乘法。后者从左到右运行,因此乘法在划分之前。这种操作顺序的变化导致两者的结果略有不同。浮点计算对操作顺序非常敏感。

快速修复: truncate 结果;周围。

更好的修复:不要将浮点用于积分算术。保存划分,直到完成所有乘法后。使用longlong long,甚至是一个大数字库。

首先没有工作,因为您在那里有整数部门。

差异btw第二,第三个是:

ans = ans * (double(a + 1 - i) / i); // second is equal to this

vs:

ans = (ans * (a + 1 - i)) / i; // third is equal to this

因此,在乘法和除法顺序上差异。如果您将双重到整数而不是简单地掉落分数零件,您将获得相同的结果。

std::cout << int( ans + 0.5 ) << std::endl;