C++ Comparison of Two Double Values Not Working Properly

c++ comparison of two double values not working properly

Comparing floating point values using the == operator is very error prone; two values that should be equal may not be due to arithmetic rounding errors. The common way to compare these is to use an epsilon:

bool double_equals(double a, double b, double epsilon = 0.001)
{
return std::abs(a - b) < epsilon;
}

C Double comparison in if statement not working as expected

I think the problem is with your logic..
You need to update the minimum difference whenever you update the index.

Try this:

if(isless((fabs(array[i])-fabs(average)),difference))
{
index=i;
difference=fabs(fabs(array[i])-fabs(average));
}

comparing double values in C

No, this will not work.

The type cast operator has higher precedence than the multiplication operator. This means that A[i] and B[i] will be cast to integers (and be truncated) before being multiplied by 1e7. 2.25 and 2.5 will end up being equal to your code. You can fix that by putting the multiplication in parentheses: (int)(A[i]*k)

Also, since you're relying on truncation instead of rounding, you may end up with incorrect results (depending on what you're expecting). 1.0e-7 and 1.9e-7 will be equal (1 == 1), while 1.9e-7 and 2.1e-7 will not (1 != 2). I suggest finding a function that will round properly with the behavior you desire.

Also, your comparison does not deal with significant digits, it simply changes the value of the exponent. In the above examples, there are only 2 significant digits, however your code would only compare one of those digits because the value of the exponent is -7.

Here is some code that does what you want:

//create integer value that contains 7 significant digits of input number
int adjust_num(double num) {
double low_bound = 1e7;
double high_bound = low_bound*10;
double adjusted = num;
int is_negative = (num < 0);
if(num == 0) {
return 0;
}
if(is_negative) {
adjusted *= -1;
}
while(adjusted < low_bound) {
adjusted *= 10;
}
while(adjusted >= high_bound) {
adjusted /= 10;
}
if(is_negative) {
adjusted *= -1;
}
//define int round(double) to be a function which rounds
//correctly for your domain application.
return round(adjusted);
}

...

if(adjust_num(A[i]) == adjust_num(B[i])) {
...
}

Why double comparison not working with if condition?

Because actual result value of operation (1.6 + 1.6 + 1.6) / 3.0 is 1.6000000000000003.

You need to use like:

if(Math.Abs(1.6d - value) < TOLERANCE)
{
Console.WriteLine("True");
}
else
{
Console.WriteLine("False");
}

And define acceptable tolerance.

Have a look at 0.30000000000000004.com

What should I do when relative comparison of two equal doubles doesn't work?

First, that is the closest value to .0009 that can be represented as a double precision IEEE floating point number.

Every floating point operation can result in a rounding operation. Epsilon based strategies are not reliable to determine if two floating point calculations represent the "same" real number.

Determining if two calculations result in, or do not result in, the same real number in the general case is actually incomputable; you can reduce Halt to it.

The "best" most expensive general purpose way to determine if they could be equal is interval mathematics. Replace your doubles with a pair of doubles representing an interval. In each calculation ensure that the result of the upper double is rounded up, and the lower double is rounded down (and when dividing/subtracting, ensure you don't flip the interval, as division/subtraction is monotonically decreasing; same for multiplying by negatives). If you divide an interval containing 0 by an interval containing 0, ensure both values become NaN, and if dividing by an interval containing 0 the result is +inf to -inf.

There are a few problems with interval mathematics; it is expensive (significantly more than 2x), requires replacing every primitive operation with ones that control rounding up/down, and you will find that the interval ends up being shockingly large after a non-trivial amount of math.

Traditional IEEE rounding produces values that are usually closer to what you want because it in effect randomly rounds each iteration. If you flip a coin 10,000 times, you'll get a random value with mean 5000 and variance 2500 and standard deviation 50; so 97% of the time you'll be in 4900 to 5100, 99%+ in 4850 to 5150. Each rounding operation is in effect a coin adding + or - eplsion/2 (actually better; it adds a value between +/- epsilon/2 chosen as the smallest one), so after 10k ops the likely error is less than +/- 75*epsilon. Interval math, meanwhile, will state that the certain error is +/-10000 epsilon.

TL;DR

You need a bigger epsilon.

What is correct way to compare 2 doubles values?

So the question will be is there a generic solution/workaround for this

There will not be a universal solution for finite precision floating point that would apply to all use cases. There cannot be, because the correct threshold is specific to each calculation, and cannot generally be known automatically.

You have to know what you are comparing and what you are expecting from the comparison. Full explanation won't fit in this answer, but you can find most information from this blog: https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ (not mine).


There is however a generic solution/workaround that side-steps the issue: Use infinite precision arithmetic. The C++ standard library does not provide an implementation of infinite precision arithmetic.

Double precision comparison in c fails

int nsteps = (int)((y-x)/step);
for(int i=0; nsteps; ++i){
double v = x + (i*step); // use v in your calculations
}

Comparing double values in C#

It's a standard problem due to how the computer stores floating point values. Search here for "floating point problem" and you'll find tons of information.

In short – a float/double can't store 0.1 precisely. It will always be a little off.

You can try using the decimal type which stores numbers in decimal notation. Thus 0.1 will be representable precisely.


You wanted to know the reason:

Float/double are stored as binary fractions, not decimal fractions. To illustrate:

12.34 in decimal notation (what we use) means

1 * 101 + 2 * 100 + 3 * 10-1 + 4 * 10-2

The computer stores floating point numbers in the same way, except it uses base 2: 10.01 means

1 * 21 + 0 * 20 + 0 * 2-1 + 1 * 2-2

Now, you probably know that there are some numbers that cannot be represented fully with our decimal notation. For example, 1/3 in decimal notation is 0.3333333…. The same thing happens in binary notation, except that the numbers that cannot be represented precisely are different. Among them is the number 1/10. In binary notation that is 0.000110011001100….

Since the binary notation cannot store it precisely, it is stored in a rounded-off way. Hence your problem.



Related Topics



Leave a reply



Submit