/ b == ka / kb上是否没有浮点错误?

时间:2019-05-10 07:06:28

标签: c++ floating-point

这是我的简单代码。

int num1, num2;
cin >> num1 >> num2;

int num3, num4;
cin >> num3 >> num4;

double result1 = static_cast<double>(num1) / num2;
double result2 = static_cast<double>(num3) / num4;

cout.setf(ios::boolalpha);
cout << (result1 == result2) << endl;

输入:

1 3
2 6

输出:

true

所以我想知道

static_cast<double>(a) / b == static_cast<double>(k * a) / (k * b)

总是真的吗?

如果没有,

int num1, num2;
cin >> num1 >> num2;

int num3, num4;
cin >> num3 >> num4;

int gcd1 = gcd(num1, num2);
int gcd2 = gcd(num3, num4);

double result1 = static_cast<double>(num1 / gcd1) / (num2 / gcd1);
double result2 = static_cast<double>(num3 / gcd2) / (num4 / gcd2);

cout.setf(ios::boolalpha);
cout << (result1 == result2) << endl;

总是在输入trueabk * a上将k * b打印到num1,num2,num3,num4吗?

3 个答案:

答案 0 :(得分:7)

假设将IEEE-754二进制浮点算法与舍入到最近的关系到偶数规则一起使用,除以下情况外,该比较为真。

给出int num1num2num3num4,其中num3 = k •{ {1}}和num1 = k num4对于某个实数 k ,在以下情况下,num2可能评估为假:

  • static_cast<double>(num1) / num2 == static_cast<double>(num3) / num4num3均为零,或者是因为num4num1为零,或者是因为 k 为零。然后num2得出一个NaN,一个NaN绝不等于任何东西,甚至不等于相同的NaN。
  • static_cast<double>(num3) / num4为零,但num2不是零, k 为负。然后,num1根据static_cast<double>(num1) / num2是正还是负来求值为+∞或-∞,而num1则求出相反的值,分别为-∞或+∞,因此比较的结果为false 。
  • static_cast<double>(num3) / num4(不包括符号位)宽于int的有效位数时,由于转换为double时舍入的原因不同,商可能会不同。例如,double可以为64位,而int的有效位数为53位。假设double是2 53 +1,num1是1, k 是3,所以num2是2 54 +2 53 + 2 + 1且num3为3。然后,由于舍入,num4产生2 53 static_cast<double>(num1)产生2 54 +2 53 +4,除法产生2 53 和2 53 +2,不相等。
  • 如果 k static_cast<double>(num3) k num1溢出num2类型,则比较结果可能为false 。

除上述情况外,到int的转换是精确的,并且商是数学定义的(不具有零除数)且相等。在这种情况下,四舍五入规则要求两个除法必须产生相同的结果,因此比较结果为true。

答案 1 :(得分:2)

是的,您可以获得不同的答案;即使没有NaN / Infinity等值,也仍然存在。有关详细信息,请照常查看Eric出色的解答。这是一个具体的反例来说明:

#include <stdint.h>
#include <stdio.h>

int main()
{
    int32_t k = 1097303040;
    int32_t a = 536913409;
    int32_t b = 2097152;

    double  lhs = static_cast<double>(a)   / b;
    double  rhs = static_cast<double>(k*a) / (k*b);

    printf ("k    = %d\n", k);
    printf ("a    = %d\n", a);
    printf ("b    = %d\n", b);
    printf ("lhs  = %f\n", lhs);
    printf ("rhs  = %f\n", rhs);
    printf ("equal: %d\n", lhs == rhs);
    return 0;
}

运行时,此程序将产生:

k    = 1097303040
a    = 536913409
b    = 2097152
lhs  = 256.020264
rhs  = -0.757798
equal: 0

请注意,结果不仅不相等,甚至有不同的符号!

答案 2 :(得分:0)

让我们假设当今通常的实现方式:

  • IEEE-754算术
  • int是32位
  • double是64位二进制浮点数

对于这些,两者始终都是正确的,因为:

  • int可以转换为double而不会造成任何精度损失。
  • IEEE-754要求除法应给出最佳结果,并正确舍入。因此,两个除法必须返回相同的值,比较无法返回false

请注意,仅当您的程序不包含未定义行为时,这才是正确的。例如,如果您的程序包含零除,可能会发生这种情况。在这种情况下,您的比较可能会导致错误。否则会生成系统异常(因此根本不会执行比较)。