0

I think there is a problem in G++ compiler about double operation.

I was trying to test some program, and found bugs in comparing(==) double. So, I read some articles and found out that double comparison should work with comparing EPSILON(really small number) https://stackoverflow.com/a/17341/7105963

I wrote code as below, but It doesn't work as I expected.

As you see in main code, I sent double parameter A and A + EPSILON to function is_same(). Because of if condition, obviously(mathematically) std::abs(A - (A + EPSILON)) = std::abs(EPSILON), this should return false. but, it returns true(1) in G++ (9.3.0).

And also, A + EPSILON doesn't calculate. It just returns A in std::cout. Is there any function to calculate double variables more precisely?

Code

#include <iostream>
#include <cmath>

bool is_same(double __x, double __y) {
    if(std::abs(__x - __y) < __DBL_EPSILON__) {
        std::cout << std::fixed << "IN Function __x\t\t" << __x << "\n";
        std::cout << std::fixed << "IN Function __y\t\t" << __y << "\n";
        std::cout << std::fixed << "std::abs(__x - __y)\t" << std::abs(__x - __y) << "\n";
        return true;
    } else {
        return false;
    }
}

double distance(double x1, double y1, double x2, double y2) {
    return std::sqrt(std::pow((x2 - x1), 2) + std::pow((y2 - y1), 2));
}

int main() {
    std::cout.precision(17);        // maximum precision : https://stackoverflow.com/a/554134/7105963
    std::cout << std::fixed << "dist (0, 0) ~ (3, 4)\t" << distance(0, 0, 3, 4) << "\n";
    std::cout << std::fixed << "EPSILON(small)\t\t" << __DBL_EPSILON__ << "\n";
    std::cout << std::fixed << "distance + EPSILON\t" << (distance(0, 0, 3, 4) + __DBL_EPSILON__) << "\n";
    std::cout << std::fixed << "distance - EPSILON\t" << (distance(0, 0, 3, 4) - __DBL_EPSILON__) << "\n";
    // std::cout << is_same(distance(0, 0, 3, 4), (distance(0, 0, 3, 4) + __DBL_EPSILON__)) << "\n";
    std::cout << is_same(distance(0, 0, 3, 4), (distance(0, 0, 3, 4) + __DBL_EPSILON__)) << "\n";
}

Output

dist (0, 0) ~ (3, 4)    5.00000000000000000
EPSILON(small)          0.00000000000000022
distance + EPSILON      5.00000000000000000
distance - EPSILON      5.00000000000000000
IN Function __x         5.00000000000000000
IN Function __y         5.00000000000000000
std::abs(__x - __y)     0.00000000000000000
1

Environment

  • Docker GCC(9.3.0) (precisely G++ 9.3.0)
TyeolRik
  • 466
  • 2
  • 25
  • `__DBL_EPSILON__` does not seem to be what you think it is. The stackoverflow.com question you cited references `EPSILON`, and not `__DBL_EPSILON__`. Generally as is with other things related to C++, it is necessary to fully understand all the underlying concepts. Stiching together different bits of code, that appear to be relevant to the task at hand, from different programs together is unlikely to produce the desired results. – Sam Varshavchik Sep 15 '20 at 02:06
  • @SamVarshavchik Thank you for answering. I understand what you talking about ```EPSILON``` and ```__DBL_EPSILON__``` is different and also should not combine many other codes without understanding concepts. But, I can't understand why ```distance + EPSILON``` and ```distance - EPSILON``` not working as I expected. As I know, ```__DBL_EPSILON__``` is just defined double number which is ```(double)2.22044604925031308084726333618164062e-16L```. This means, just double operation is not working precisely. Please let me know why :( – TyeolRik Sep 15 '20 at 02:13
  • Please read the definition of what `__DBL_EPSILON__` means. It is the ***smallest*** increment that produces a distinct number, when added to `1.0`. Which means that there ***cannot*** be any smaller differences, when comparing floating point numbers, ***by definition***. Trying to ascertain smaller differences than `__DBL_EPSILON__` will always be doomed to a failure because, by definition, it is mathematically impossible for them to exist. – Sam Varshavchik Sep 15 '20 at 02:17
  • Does this answer your question? [Is floating point math broken?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) – Jeffrey Sep 15 '20 at 02:27
  • @Jeffrey I already know this problem which is based on floating point data structure. I think I found the answer. As @Sam Varshavchik, I had bad concept about ```__DBL_EPSILON__``` – TyeolRik Sep 15 '20 at 02:42
  • What is the point of this question? You've already established that you know floating point math is broken (regardless of precision), one consequence of which is that `A + EPSILON` could evaluate to `A`, in which case `is_same(A, A + EPSILON)` evaluates to `is_same(A, A)`, which evaluates to `true`. Increasing the precision only changes how small `EPSILON` needs to be for this phenomenon to occur. This is expected. Your code is working as expected. What is it you are after? – JaMiT Sep 15 '20 at 05:15
  • @SamVarshavchik: "There cannot be smaller differences". Oh yes there can. In fact, `EPSILON-(EPSILON/2)` is a trivial example of such a difference. It's floating point, not fixed point. – MSalters Sep 17 '20 at 07:14

0 Answers0