Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

is there no floating point error on a / b == ka / kb?

Here is my simple code.

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;

Input:

1 3
2 6

Output:

true

So I want to know that

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

is always true?

if not,

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;

is always print true on input a, b, k * a, k * b to num1, num2, num3, num4?

like image 782
TaeSang Cho Avatar asked May 10 '19 07:05

TaeSang Cho


2 Answers

Assuming IEEE-754 binary floating-point arithmetic is used with the round-to-nearest-ties-to-even rule, the comparison is true except in the cases below.

Given int num1, num2, num3, and num4 where num3 = knum1 and num4 = knum2 for some real number k, there are the following situations where static_cast<double>(num1) / num2 == static_cast<double>(num3) / num4 may evaluate to false:

  • num3 and num4 are both zero, either because num1 and num2 are zero or because k is zero. Then static_cast<double>(num3) / num4 evaluates to a NaN, and a NaN never compares equal to anything, not even to the same NaN.
  • num2 is zero but num1 is not and k is negative. Then static_cast<double>(num1) / num2 evaluates to +∞ or −∞ according to whether num1 is positive or negative, while static_cast<double>(num3) / num4 evaluates to the opposite, −∞ or +∞ respectively, so the comparison evaluates to false.
  • When int, excluding the sign bit, is wider than the significand of double, the quotients may differ due to different roundings in the conversion to double. For example, int may be 64 bits while double has a 53-bit significand. Suppose num1 is 253+1, num2 is 1, and k is 3, so num3 is 254+253+2+1 and num4 is 3. Then, due to rounding, static_cast<double>(num1) produces 253, static_cast<double>(num3) produces 254+253+4, and the divisions produce 253 and 253+2, which are not equal.
  • In cases where knum1 or knum2 overflows the int type, the comparison may evaluate to false.

Other than in the cases above, the conversions to double are exact, and the quotients are mathematically defined (do not have zero divisors) and are equal. In these cases, the rounding rule necessitates that the two divisions produce the same result, so the comparison evaluates to true.

like image 68
Eric Postpischil Avatar answered Oct 03 '22 00:10

Eric Postpischil


Yes, you can get different answers; even when there are no NaN/Infinity etc. values are around. See Eric's fantastic answer as usual for the details. Here's a concrete counter-example to illustrate:

#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;
}

When run, this program produces:

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

Note that the results are not only not equal, they even have different signs!

like image 26
alias Avatar answered Oct 02 '22 22:10

alias