1

If I type 0.01 or 0.02 the the program just exits immediately. What do I do?

#include <stdio.h>

char line[100];
float amount;

int main()
{
printf("Enter the amount of money: ");
fgets(line, sizeof(line), stdin);
sscanf(line, "%f", &amount);

if (amount == 0.0)
    printf("Quarters: 0\nDimes: 0\nNickels: 0\nPennies: 0");

if (amount == 0.01)
   printf("Quarters: 0\nDimes: 0\nNickels: 0\nPennies: 1");


if (amount == 0.02)
   printf("Quarters: 0\nDimes: 0\nNickels: 0\nPennies: 2");

return (0);
}
Cœur
  • 37,241
  • 25
  • 195
  • 267
Dan Knott
  • 127
  • 1
  • 1
  • 3
  • 1
    http://floating-point-gui.de/ – BlackBear Mar 02 '14 at 10:33
  • 3
    @YuHao You absolutely can, it's just that results are not what you expect :) – jrok Mar 02 '14 at 10:34
  • 0.01 is a double, but 0.01f is a float. That comparison would work. – Aki Suihkonen Mar 02 '14 at 10:34
  • 4
    Suggested Reading : [What Every Computer Scientist Should Know About Floating-Point Arithmetic](http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) – P0W Mar 02 '14 at 10:35
  • Apart from reading up on floating point arithmetic, you should learn how to debug. For a quick start, you should have printed `amount` after reading it, to see if the value you get is the one you expect. – stefan Mar 02 '14 at 10:44
  • 1
    You should specify what the target of this question is, do you want to experiment floats? than use a better comparison. Do you want to work on currencies, than forget about floating point, convert into int and use as @abligh suggests. – Jekyll Mar 02 '14 at 11:04
  • 1
    Possible duplicate of [Why not use Double or Float to represent currency?](http://stackoverflow.com/questions/3730019/why-not-use-double-or-float-to-represent-currency) – Toby Speight Nov 23 '16 at 13:27

4 Answers4

3

What is the most effective way for float and double comparison?

You should use something like this

bool isEqual(double a, double b)
{
    return fabs(a - b) < EPSILON;
}

or this

#define ISEQUAL(a,b) ( fabs((a) - (b)) < EPSILON)

and define EPSILON

#define EPSILON (0.000001)
Community
  • 1
  • 1
Avt
  • 16,927
  • 4
  • 52
  • 72
  • That is better but you should scale for a factor, you cannot use same EPSILON for small (decimals) and big data (thousands) or you will start to have again problems, so it is ok until his program is contained in decimals values. – Jekyll Mar 02 '14 at 10:45
  • relative comparison is better – phuclv Mar 02 '14 at 10:48
  • Note that he should also convert from using `float` to `double` in the body of his code if he uses this method (rather than the one I suggest) - or use `fabsf` and `float` parameters. – abligh Mar 02 '14 at 11:19
3

Firstly, do not attempt to compare doubles, or to compare floats, or to compare doubles to floats (exception: comparing against 0 is OK, and arguably all integers). Other answers have given good links as to why, but I especially liked: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

Secondly, if you are dealing with an amount of money, don't use doubles, or get out of double as quickly as possible. Either use a fixed point library (a bit complex for what you want), or simply do:

int cents = (int)round(amount * 100);

then work with cents instead. You can compare these to your heart's content.

Thirdly, if the idea here is to work out change in quarters, dimes, nickels and pennies, a collection of if statements is not the way to go, unless you like long and inefficient programs. You will need to do that programatically. And that will be far easier if you have the integer number of cents above (hint: look at the % operator).

abligh
  • 24,573
  • 4
  • 47
  • 84
  • I am not sure if the target of that exercise is working with doubles and float or it is a real problem, in case I perfectly agree with you. – Jekyll Mar 02 '14 at 10:57
2

I think we could scale for a factor and make a relative comparison like this:

#define EPSILON (0.000001)

if (fabs(a - b) <= EPSILON * fmax(fabs(a), fabs(b))) {
}

which is more robust than an absolute comparison:

if (fabs(a - b) <= EPSILON ) {
    // ...
}

which maybe scale dependent. By the way having the optimum scale depends also from the function, we shouldn't use the same formula for a log and for a sin.

Jekyll
  • 1,434
  • 11
  • 13
  • Whilst fine in the general case, given the user is attempting to compare cents, this seems unnecessarily complicated. Far better I think to convert to an integer number of cents. – abligh Mar 02 '14 at 10:53
  • Oh yes that's true. @abligh do you think this will confuse him? I can remove the post in case. – Jekyll Mar 02 '14 at 10:54
  • I suspect he's been set a 'write a program to work out how to give change' question, in which case he's stumbled upon a comparing floats issue that he should learn about, though comparing floats is actually not what he should be doing. I'd therefore leave your answer (as it's relevant to how you solve this problem in general), but I suspect mine is a better answer to the specific question he has (i.e. in context). IE they are complementary. – abligh Mar 02 '14 at 11:01
  • Yes that's true, I think in case he has to work with currency yours is the **only** answer, working with floats is just crazy in that case – Jekyll Mar 02 '14 at 11:03
-6

The downvotes on this answer are well deserved, it was wrongly advocating for a simple equality test. While this is undefined behaviour and should not be encouraged, even so it happens to work sometimes.

You should never test a floating value for equality. Instead use an epsilon value to test your variable against a range as this answer is suggesting it.

For instance take this example:

#include <stdio.h>
#include <math.h>

#define  EPSILON 0.00001f

int main() {
    float a = 3.234324333f;
    float b = a;
    b += 1;
    b -= 1;
    
    printf("a value is %f\n", a);
    printf("b value is %f\n", b);

    printf("\na == b ?\n");
    if (a == b) {
        printf("true\n");
    } else {
        printf("false\n");
    }

    printf("a ~= b with epsilon = %f ?\n", EPSILON);
    if (fabs(a - b) <= EPSILON) {
        printf("true\n");
    } else {
        printf("false\n");
    }
    return 0;
}

When running it:

a value is 3.234324
b value is 3.234324

a == b ?
false
a ~= b with epsilon = 0.000010 ?
true
Jean
  • 368
  • 2
  • 13
  • Read the other answer, to see how to compare `double` and `float` variables correctly. – πάντα ῥεῖ Mar 02 '14 at 10:43
  • This is essentially the same as comparing `(amount == 0.01f)` Both of these methods work. – Aki Suihkonen Mar 02 '14 at 10:43
  • I disagree that adding a random EPSILON is _the_ correct method. – Aki Suihkonen Mar 02 '14 at 10:43
  • 1
    This answer is _so_ wrong: First, use `0.01f` instead of `(float)0.01`, the conversion is useless and bloated. Second, comparing floats for equality is evil. Use a trust region (as in Avts answer) or whatever you name it and enable warning `-Wfloat-equal` (or equivalent for your compiler). – stefan Mar 02 '14 at 10:49
  • There's nothing evil in float comparison, when you know what you are doing. This is a great example. It would be most likely wrong to compare floating point values after expression ((0.01f + 0.02f) == 0.03f), but not literals (0.01f == 0.01f). – Aki Suihkonen Mar 02 '14 at 10:54
  • Are you sure a compiler is not able to optimize (float)0.01 ? – Aki Suihkonen Mar 02 '14 at 10:55
  • @AkiSuihkonen Why would you compare literals? Compilers may optimize `float(0.01)`, i.e. performing the conversion at compile time, but afaik you cannot rely on that. But why write five additional characters? It's just not necessary. – stefan Mar 02 '14 at 10:57
  • 3
    Amounts of money are decimal fractions which will not in the general case be represented as terminating binary fractions. Hence if you compare them you are relying on a number of assumptions which will not necessarily be true (e.g. that the compiler and CPU executing the code use the exact same binary representation of a decimal fraction, that no arithmetic operations on the input value have caused it to have a different representation etc. etc.). It's just a very bad idea. – abligh Mar 02 '14 at 11:16
  • I compared literals, because I was afraid to write it as abstraction ((a+b) == c) vs (a == a), which is true for everything else but NaN. – Aki Suihkonen Mar 02 '14 at 11:47
  • @AkiSuihkonen you are not comparing literals. You are comparing literals to a variable. – abligh Mar 02 '14 at 12:04
  • You are missing the point. `float a=0.01f; a==0.01f;` is true. `float a=0.01f,b=0.02f,c=a+b; c==0.03f;` is not necessarily true. Because no calculation and no conversions from double->float is done in this chain, the comparison is as safe, as comparing two literals. – Aki Suihkonen Mar 02 '14 at 12:12