-1

I'm calculating a real numeric value of the form N + fraction. Say, For example, N + fraction = 7.10987623, then N = 7 and fraction = 0.10987623 Next, I need to check to see if fraction is greater than or equal to the ratio 23269/25920.

The following, in C/C++, appears to give correct results; however, I'm not sure if it is the correct way to do the comparison:

// EPSILON is defined to be the error tolerance
// and `ratio' is defined as 23269.0/25920.0 
if(fabs(fraction - ratio) > EPSILON)
 // `fraction' is greater or equal to `ratio'

I also tried to do the other way, but it appears to give incorrect results.

if(fabs(fraction - ratio) < EPSILON)
JCM
  • 197
  • 1
  • 1
  • 10
  • The result of `fabs(fraction - ratio)` says nothing about whether `fraction` is greater or less than `ratio`. When testing what you think is a correct approach, there are five relevant values of `fraction` to test: one much smaller than `ratio`, one just a tiny bit smaller than `ratio`, one exactly equal to `ratio` (even if `ratio` is not exactly 23269/25920), one just a tiny bit larger than `ratio`, and one much larger than `ratio`. If you test your two approaches like that, you'll find that neither works. If you write out your expected results for those five cases, you'll find the answer. –  Dec 24 '14 at 12:21
  • 1
    Voted for reopen, this question certainly has a lot of duplicates but the duplicate here was wrong. – ouah Dec 24 '14 at 12:22
  • How about comparing `fraction * 25920` and `23269`? – Kerrek SB Dec 24 '14 at 12:24
  • You have to define which way the error tolerance should go. What do you want to do if the ratio is very slightly greater than 23269/25920? What do you want to do if it's very slightly less? – David Schwartz Dec 24 '14 at 12:25
  • 1
    @2501 Absolutely not a duplicate. That question is talking about equality `==`, this one is about ordering `<`. They may seem similar but in fact are totally different. – n. m. could be an AI Dec 24 '14 at 12:44
  • 1
    It doesn't look like you understand what David Schwartz is saying. Let me try to reformulate. The mathematical comparison tells you which of the two cases takes place, `(1) x < y` or `(2) x >= y`. You have two actions to perform, `do stuff when x < y` and `do other stuff when x >= y`. The decision is easy. The machine floating-point comparison, when implemented correctly, says which of the **three** cases takes place: `(1) x < y`, `(2) x > y` and `(3) x and y are too close to tell`. You need to either invent **three** corresponding actions, or lump two of the cases together. – n. m. could be an AI Dec 24 '14 at 12:55
  • Why use fabs? You know that both N and your ratio are positive? What are you trying to accomplish with EPSILON? Are you trying to guarentee that N > MAGIC_RATIO by at least EPSILON? – bpeikes Dec 24 '14 at 13:01
  • @n.m. Why don't you just write an answer? – Barry Dec 24 '14 at 13:11
  • @Barry Because I don't think it's the right thing to do in this case. – n. m. could be an AI Dec 24 '14 at 13:16

3 Answers3

4

You have the right way to compare equality:

fabs(fraction - ratio) < EPSILON

which establishes an equality band around ratio of widthEPSILON. Anything above that band, is strictly greater. Thus, the > check is:

fraction > ratio + EPSILON

Since we want >=, we just take the union of those two sections:

fraction > ratio - EPSILON
Barry
  • 286,269
  • 29
  • 621
  • 977
0

Rather than specifying an EPSILON, which will need to vary depending on the magnitude of N, an alternative is to add N to ratio, as then both it and fraction will incur the same rounding:

x <= floor(x) + ratio
Simon Byrne
  • 7,694
  • 1
  • 26
  • 50
0

Break a number into its whole number and fractional parts via modf().
With a good FP library, no loss of precision would be expected.

#include <math.h>
int foo(double N_plus_fraction) {
  double ipart;
  double fraction = modf(N_plus_fraction, &ipart);
  fraction = fabs(fraction);  // lets use the absolution fraction.

Break the threshold into numerator/denominator parts and scale the fraction.

  double f = fraction*25920.0;
  return f >= 23269.0;
}

As the product f may not be an exact mathematical product of fraction and 25920.0, but the closest rounded one, code could use an f just slightly larger (or smaller) with nextafter() depending on which way one wants to bias the result.

  double f = fraction*25920.0;
  f = nextafter(f, 2*f);  // make f the next greater FP value.
  return f >= 23269.0;
}

The only inexactness expected occurs in the fraction*25920.0 step.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256