3

I wanted to know what would be the fastest approach of comparing floats to three decimal places.Say I have something like this

float lhs = 2.567xxxx
float rhs = 2.566xxxx

The above should be different and if its something like this

float lhs = 2.566xxxx
float rhs = 2.566xxxx

They should be the same

Update:

I am trying the following

double trunc(double d)
{
    return (d>0) ? floor(d) : ceil(d) ; 
}


bool comparedigits(float a , float b)
{
    if (trunc(1000.0 * a) == trunc(1000.0 * b))
    {
        return true;
    }
    return false;
}

    float g = 2.346;
    float h= 2.34599;
    bool t = comparedigits(g,h) ; //Not the same and should return false;

However it is returning true.

MistyD
  • 16,373
  • 40
  • 138
  • 240
  • 3
    Do you understand that when you *think* you may have exactly 2.567, you may actually have 2.56699999...? –  Sep 08 '13 at 16:58
  • 6
    [What Every Computer Scientist Should Know About Floating-Point Arithmetic](http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) – Some programmer dude Sep 08 '13 at 16:59
  • Sorry fixed it - 3 decimal places – MistyD Sep 08 '13 at 17:01
  • 3
    Do you really want to report as different values that are only very slightly apart just because they differ in the first few digits, such as 2.566999999999999999999999 and 2.567000000000000000, even though values that are farther apart, such as 2.566 and 2.256699, are reported as the same? – Eric Postpischil Sep 08 '13 at 17:19
  • @MistyD About the values in your question, `g` is not exactly 2.346. 2.346 is not exactly representable, so `g` is really `2.345999...`, and returning true is correct. –  Sep 08 '13 at 20:23
  • @hvd thanks I did realize that. I have marked an answer – MistyD Sep 08 '13 at 20:31

5 Answers5

16

To put a stop to the onslaught of answers that are wrong because they allow rounding to alter the results, here is an answer that does not have the rounding problem, because it uses double for the arithmetic:

trunc(1000. * lhs) == trunc(1000. * rhs);

This works because 1000. has type double, so the other operand is converted from float to double, and the multiplication is performed in the double format. The product of 1000 with any float value is exactly representable in double, so there is no rounding error (assuming IEEE 754 32-bit and 64-bit binary floating-point). Then we use trunc to compare the numbers up to the (original) third digit after the decimal point.

I hesitated to provide this answer because I am not sure it is what the OP really wants. Often when people come to Stack Overflow with a request for comparing “to three decimal places”, they have not entirely thought through the problem. A complete correct answer may have to wait until we have clarification.

Also, the above is for positive numbers only. If the values may be negative, then a prior test should be performed on their signs, and false should be returned if they differ. (Otherwise, –.0009 would be reported as equal to +.0009.)

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • 1
    Not my downvote (I don't downvote), but doesn't your solution have the same problem for a float with a large enough integer part? – jxh Sep 08 '13 at 18:11
  • 1
    @jxh: No. The `float` significand is 24 bits. 1000 is 10 bits. Their product has at most 34 significant bits. The `double` significand is 53 bits. There is plenty of room. And the `double` range is much larger than the `float` range, so there is never any overflow. `trunc` returns its result in `double`, not `int`. – Eric Postpischil Sep 08 '13 at 18:13
  • I am getting trunc undefined. And I did include #include . I am using VS2010 – MistyD Sep 08 '13 at 18:24
  • @MistyD `trunc` is a standard library function defined in the current C++ standard, but not in the previous one, and not yet implemented in VS2010. It can be trivially implemented in terms of `floor` and `ceil` (calling the right one depending on the sign of the value), and both `floor` and `ceil` have existed for longer so *should* exist in VS2010 too. –  Sep 08 '13 at 18:34
  • Just updated my question , tried doing this but am getting wrong result – MistyD Sep 08 '13 at 18:45
  • **WRONG!** This test states that 3.399999999999999911182158029987476766109466552734375 is “near” 3.4000000000000003552713678800500929355621337890625. [_See here_](http://ideone.com/FZ3fcX). – masoud Sep 08 '13 at 19:02
  • @MM. Bad test. This answer is for comparing `float` values. Your test fails because you're testing `double` values. –  Sep 08 '13 at 20:12
  • @hvd: I refer you to your own comment under my answer: _"The same problem exists for floats, it just requires different values to expose the problem"_ ;-) – masoud Sep 08 '13 at 20:15
  • @MM. What this answer does differently from yours is take `float` values, and compare them in `double` arithmetic. Your answer takes `float` values and multiplies them by 1000 to a `float` value. You multiply by `1000`. This answer multiplies by `1000.`. Which is not the same thing. –  Sep 08 '13 at 20:18
  • @hvd: multiplying a `float` by a `int`, an implicit casting will be applied by compiler and the result is a `float`. No difference between `float * 1000` and `float * 1000.0f`. – masoud Sep 08 '13 at 20:24
  • @MM. `float * int == float`. `float * double == double`. `1000.0` is a value of type `double`. –  Sep 08 '13 at 20:25
  • It seems the above test fails for `0.2510f` and `0.2511f`, for example. If the original values are of type `double` different values would fail (the above pair of values succeeds if they are immediately `double`s). – Dietmar Kühl Sep 08 '13 at 20:36
  • @DietmarKühl `0.2510f` is less than 0.2510, it's really 0.250999987125396728515625. –  Sep 08 '13 at 20:50
  • @hvd: sure. This is why it doesn't work! ;-) The question really is: what is the original question about? If it is about decimal numbers, anything not converting the binary floating points to decimal first doesn't work and it seems to be about decimal numbers. If it is about binary numbers I think the question doesn't make any sense! – Dietmar Kühl Sep 08 '13 at 21:30
  • 1
    @DietmarKühl I think I agree with the point you're making, but I hope you do agree that what the code in this answer does is exactly what the question asks for. 0.250999987125396728515625 and 0.251100003719329833984375 (`0.2510f` and `0.2511f`) differ in the third decimal, so the question asks to count them as "not close enough", and that's exactly what this answer does. Whether that's something the OP has any use for (possibly not, perhaps even probably not) is for the OP to decide. :) –  Sep 08 '13 at 21:37
  • @DietmarKühl “If it is about decimal numbers, anything not converting the binary floating points to decimal first doesn't work” is a strange thing to write below an answer that **precisely** answers the question, assuming it is about the decimal representation of the `float`s `lhs` and `rhs`, without converting to decimal at any time. Eric should perhaps have written `bool compare(float lhs, float rhs) {…` to avoid misunderstandings. – Pascal Cuoq Sep 08 '13 at 21:40
  • @PascalCuoq: I'm using the string formatters to do the correct conversion to a decimal representation! The algorithms (e.g., [Dragon4](http://www.cs.washington.edu/education/courses/cse590p/590k_02au/print-fp.pdf)) to obtain a correct decimal representation from a binary floating point is non-trivial but it is implemented for the formatting. I'm not quite up to implementing this algorithm quickly for an answer although it would get rid of having to coerce the C++ formatting into doing exactly the right thing. ... and I perfectly understand what the answer above does. – Dietmar Kühl Sep 08 '13 at 21:47
  • @DietmarKühl If you understand what the answer above does, why are you going on about conversion to decimal? Nobody said it is not difficult. In the present case, it is also unnecessary, as shown above. – Pascal Cuoq Sep 08 '13 at 22:01
  • @PascalCuoq: For example because the original author stated that `2.346` and `2.34599` should not be considered equal although in a binary representation multiplied by 1000 and then truncated they will yield the same integer. Doing a conversion to decimal first, considers them unequal, however. That is, despite the above answer being accepted, it doesn't do what the original author asks for! – Dietmar Kühl Sep 08 '13 at 22:08
  • Note: 1000 takes ten bits to represent as an integer, but as a binary floating-point value it has the same significand as 125, which takes 7 bits. – Pascal Cuoq Sep 08 '13 at 22:09
  • @DietmarKühl I pointed that out in a comment on the question, and if I am not misinterpreting the response, the OP agrees that the expectation was wrong. –  Sep 08 '13 at 22:17
  • @DietmarKühl The OP wishes to compare two `float`s up to the third decimal. The answer `true` is the correct answer for `2.346f` and `2.34599f`, because these two numbers have the same first three decimals. If your function answers false, your function is wrong. http://ideone.com/eExRzj – Pascal Cuoq Sep 08 '13 at 22:18
  • @PascalCuoq: I think if the OP wishes these values to not compare equal it is pretty clear that he does not wish to compare the quirks of a binary representation but rather the result after properly converting the value to a decimal representation. Saying that it is wrong to request that they don't compare equal is ignoring the explicit specification given by the OP. It may better fit the approach you would like to use but that doesn't make it correct. ... and clearly, the three decimal places "346" and "345" are different. – Dietmar Kühl Sep 08 '13 at 22:23
  • @MM.: There is no `float` with value 3.399999999999999911182158029987476766109466552734375. The code in this answer takes `float` inputs, as requested in the question title and as shown in the code in the question. The code you link to at Ideone.com incorrectly uses `double` for operands. – Eric Postpischil Sep 08 '13 at 22:28
  • @DietmarKühl: You write about “properly converting the value to a decimal representation.” Once `2.346f` has been converted to a `float`, its exact value is 2.3459999561309814453125, and its proper decimal representation is “2.3459999561309814453125”. There is no way to tell from the `float` alone whether this was originally, or is desired to be, 2.346. If one wants to ask the question “If `float` values `lhs` and `rhs` are rounded to three decimal digits, are results the same?”, then that is a different question. – Eric Postpischil Sep 08 '13 at 22:35
  • @EricPostpischil: It seems, however, that the OP asks about processing decimal values. That is, assuming the value is decimal and converting it to the closest decimal value before applying rounding or truncation seems what is asked about (it seems the question decimal truncation). Decimal values, as long as they don't use more than `std::numeric_limits::digits10` digits can be recovered exactly from the binary representation, even though the binary value is different. This conversion ("Dragon4" and relatives) is what I refer to as "proper conversion". – Dietmar Kühl Sep 08 '13 at 22:42
6

For float values which can fit into an integer after x1000 you can try:

if (static_cast<int>(lhs*1000.0) == static_cast<int>(rhs*1000.0))
{
   // Values are near
}
else
{
   // They are not identical (maybe!)
}

Be careful of computer accuracy in representing float value.


IMPORTANT UPDATE

Always there're numbers which can fail a code, Eric Postpischil's code fails as same as this code.

Even converting to string doesn't help, we can find numbers which can not convert to strings correctly.

Well, what is the solution? It's easy, we must define scope and needed accuracy of our program. We can not have unlimited precision in computer world. What Every Computer Scientist Should Know About Floating-Point Arithmetic

masoud
  • 55,379
  • 16
  • 141
  • 208
  • 2
    +1 but note that this only works for floating point values that do not exceed the range of `int`. That may very well be a valid assumption for the OP. –  Sep 08 '13 at 17:03
  • 1
    This test states that 3.399999999999999911182158029987476766109466552734375 is “near” 3.4000000000000003552713678800500929355621337890625 (because they both produce 3400 when multiplied by 1000 with IEEE 754 64-bit binary arithmetic and then converted to an `int`), but the question indicates they should be reported as different since they differ in the first three digits after the decimal place. – Eric Postpischil Sep 08 '13 at 17:15
  • The question is how do you sure after assigning `3.399999999999999911182158029987476766109466552734375` to a variable, it assigns exactly? My answer is after that assignment `3.4...` will be stored. See [here](http://ideone.com/PvKDlB) – masoud Sep 08 '13 at 17:21
  • @MM. That's what I would have thought too, but Eric's comment is spot on for `double` values on at least my system. –  Sep 08 '13 at 17:23
  • @MM. The same problem exists for floats, it just requires different values to expose the problem. :) –  Sep 08 '13 at 17:25
  • @MM The same problem occurs with floats. Also, make sure to understand when your debugger rounds a value for display. – IInspectable Sep 08 '13 at 17:26
  • 1
    I incorrectly used `double` for my example above, but the problem occurs for `float` too, as with 3.599999904632568359375 and 3.6000001430511474609375. An easy workaround for `float` is to perform the multiplication with `double`. Then there will be no rounding error; the product of every `float` with 1000 is exactly representable in `double` (using 754 IEEE 32-bit and 64-bit binary). – Eric Postpischil Sep 08 '13 at 17:28
  • No difference, this is not the failure of my code, it's the limitation of computers to handle those values. – masoud Sep 08 '13 at 17:28
  • @MM No, it is your code's problem. Multiplying by 1000 is where things start to fall apart. – IInspectable Sep 08 '13 at 17:30
  • 1
    "Even converting to string doesn't help, we can find numbers which can not convert to strings correctly." -- No, every binary floating point value is exactly representable as a decimal value, and can be converted to a suitably long string without any data loss. Remember, if you have a decimal number with a finite number of digits, and divide it by 2, you still have a decimal number with a finite number of digits. –  Sep 08 '13 at 20:13
  • @hvd: No! Who says after every conversion from a float to string two variables represent exactly same value? it's expect-able to have some unintended rounding in process of this conversion... – masoud Sep 08 '13 at 20:20
  • "No! Who says after every conversion from a float to string two variables represent exactly same value?" I do, I just explained why in my previous comment. Just make sure you use enough precision so that there isn't any rounding. –  Sep 08 '13 at 20:24
  • @hvd: floats are base 2, the string representation is base 10. Do you really believe this conversion has not inaccuracy? See paragraph 2 of dwelch's answer. – masoud Sep 08 '13 at 20:35
  • 1
    @MM. Yes, a fixed-precision base 2 floating point value can be losslessly converted to a fixed-precision base 10 floating point value (possibly expressed as a string), because 10 is a multiple of 2. However, it may require (and often does require) more decimal places than you might expect. –  Sep 08 '13 at 20:52
  • @MM. No, it's only the other way around that it's correct. Try writing `0.1` in base 2. –  Sep 08 '13 at 20:57
2

If we assume that the xxxxs in your statement are true don't cares, that is you only care about 7 decimal places of precision, then the following scheme will work.

To deal with floating point representation effects due to the limited precision of float, you can promote the arguments to double, rounded to the 7th decimal place, and multiply by 1000. Then, you can use modf() to extract the integral part and compare them.

bool equals_by_3_decimal_places (float a, float b) {
    double ai, bi;

    modf((.00000005 + a) * 1000, &ai);
    modf((.00000005 + b) * 1000, &bi);
    return ai == bi;
}
jxh
  • 69,070
  • 8
  • 110
  • 193
  • 3
    This incorrectly reports that 1.198999881744384765625 and 1.19900000095367431640625 are equal to three decimal places. – Eric Postpischil Sep 08 '13 at 17:53
  • @EricPostpischil: Okay, looking at the GNU libc implementation, I see that it is actually using a small version of an arbitrary precision library to achieve accurate printing. I can fake this by promoting to double internally in the function. – jxh Sep 08 '13 at 18:07
  • Once you have promoted to `double`, why bother with iterations and fancy stuff? `1000.*a` is an exactly correct result, with no rounding. – Eric Postpischil Sep 08 '13 at 18:11
  • @EricPostpischil: Right, `modf()` can be an alternative to `trunc()` after conversion to `double`. – jxh Sep 08 '13 at 18:39
  • Tried this with `float g = 2.346;float h= 2.34599;` returns true and should have returned false. Since the third decimal place `5 != 6` – MistyD Sep 08 '13 at 18:56
  • @MistyD: Hmm... I can't solve your problem then. The issue you raise is because floating point values are binary representations of your decimal values, and not all decimal fractions can be represented exactly in binary fractions. – jxh Sep 08 '13 at 19:07
  • While not directly related to your problem, [this question](http://stackoverflow.com/q/16831464/315052) is an interesting case of the same number that can truncate to two different values. – jxh Sep 08 '13 at 19:17
1

Convert the float values to strings with the full number of places (std::numeric_limits<float>::dgits10), then truncate the string to 3 decimal places, and compare the resulting strings:

std::string convert(float value, int places) {
    if (value == 0) {
        return "0";
    }
    int digits(std::numeric_limits<float>::digits10 - std::log(value) / std::log(10));
    digits = std::max(0, digits);
    std::ostringstream out;
    out << std::fixed << std::setprecision(digits) << value;
    std::string rc(out.str());
    return places < digits? rc.substr(0, rc.size() - (digits - places)): rc;
}

bool compare(float f1, float f2) {
    return convert(f1, 3) == convert(f2, 3);
}

The various comparisons proposed multiplying by 100 or 1000 don't work because they will do binary rather than decimal rounding. You could try to add 0.5 after multiplying and before truncating to int but there are cases (although few) where this approach still fails. The conversion above, however, does the right thing as long as you don't end up with more than std::numeric_limits<float>::digit10 digits. Trying to deal with more decimal digits than this number will fail because the float can't represent as many decimal digits correctly anyway.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • 2
    How do you know converting a float to a string will not round the real value? – masoud Sep 08 '13 at 17:07
  • 3
    I don't think this answers the question: testing shows what M M.'s comment hints at: 2.3451 and 2.3459 do not compare as equal to three places. (You forgot the `places` parameter in the `compare` function, I added that when testing.) –  Sep 08 '13 at 17:12
  • @hvd: I do think the above answer the question (aside from the silly typo of forgetting the places). It certainly works with values you quoted. In which way does it not work in your opinion? – Dietmar Kühl Sep 08 '13 at 17:43
  • @DietmarKühl What does `std::cout << std::fixed << std::setprecision(3) << 2.3459` output on your system? I get `2.346`, which is not equal to `2.345`, so the values do not compare as equal. –  Sep 08 '13 at 17:46
  • @MM.: The conversion from `float` to a string as above will do the correct rounding! That's the whole point of doing this conversion. If the original question indeed intents not to do the rounding the correct approach is to format the value such that `digits10` digits are formatted and truncated after three digits. – Dietmar Kühl Sep 08 '13 at 17:49
  • This approach should work: if you print a floating point variable's exact value -- it's always exactly representable in decimal -- then truncate it, there is no rounding involved anywhere. Your calculation of `digits` is off, though, and values still get rounded. –  Sep 08 '13 at 18:22
  • @hvd: actually, the goal isn't to compute the exact floating point representation but the appropriate decimal value: as long as no more than `digit10` decimal places are used, the original decimal value can be obtained. That will involve some rounding compared to the binary value. The examples given in the original question a decimals and I think for these the above computation of decimals is correct (although I need to deal with the precision becoming negative...) – Dietmar Kühl Sep 08 '13 at 19:34
  • @DietmarKühl With sufficient precision, there will be no rounding, and the answer will be correct. With insufficient precision, there will be rounding, and some of Eric Postpischil's test values (in comments on other answers) fail with your current code. –  Sep 08 '13 at 20:17
  • Your function seems to return true when applied to `4766.8276f` and `4766.8281f`. I acknowledge that the question is unclear, but shouldn't they be considered different to three decimal places, if one follows the same reasoning that you seem to be applying to `2.346f` and `2.34599f`? (sorry, I don't know C++, but I wrote this: http://ideone.com/2wkVQX ) – Pascal Cuoq Sep 08 '13 at 23:18
  • @PascalCuoq: When using decimal digits in a `float`, it doesn't make sense to use more than `std::numeric_limits::digits10`. Assuming you are using IEEE floating points, `digits10` will be 6. The values you try to deal with use 8 digits which it can't right. Although the difference is in the 7th decimal digit, this is already a random value. The constraint that it is limited to `digits10` digits is mentioned in my answer. – Dietmar Kühl Sep 08 '13 at 23:23
  • They are respectively `4766.828125` and `4766.82763671875`. Why could I not use them? Am I supposed to limit myself to the floats that are the nearest to a 6-digit decimal representation? If I obtained some float values as the result of single-precision computations, do I have to check that they have this property before passing them to your function? – Pascal Cuoq Sep 08 '13 at 23:35
  • 1
    @PascalCuoq: You can pass arbitrary `float`s to the function. However, it will only distinguish the values based on the first 6 decimal digits this is as many decimal digits you can safely represent when using a `float`. If you use more decimal digits they'll be fairly random. – Dietmar Kühl Sep 08 '13 at 23:42
  • The idea of interpreting only 6 decimal digits vaguely reminds me of the Excel section of http://www.cs.berkeley.edu/~wkahan/Mindless.pdf (with 15 instead of 6 since it is double precision) – Pascal Cuoq Sep 08 '13 at 23:57
-1

1) you are trying to do equals comparisons with floating point. Some floating point formats that will work, but IEEE formats will not work. You cannot do equals comparisons. You need to convert that float to an int then do an int compare. With integers (not limiting myself to 32 bit or anything here) there is only one way to represent each number so you can do equals comparisons.

2) remember the floating point math is base 2 and you are asking to do base 10 stuff. so there are going to be conversion issues, truncation. Also I again assume you are using IEEE which means you have three rounding modes (base 2) so you have to deal with that as well. You will want to do some sort of double_to_integer((double*1000.0)+0.5) and compare those. I would not be surprised if you find corner cases that dont work.

More interesting information on this problem. Note that use of unions in this manner is not supported by the C standard, but often just happens to work...

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

double trunc(double d)
{
    return (d>0) ? floor(d) : ceil(d) ;
}
int comparedigits(float a , float b)
{
    if (trunc(1000.0 * a) == trunc(1000.0 * b))
    {
        return 1;
    }
    return 0;
}
union
{
    unsigned int ul;
    float f;
} fun;
union
{
    unsigned int ul[2];
    double d;
} dun;
int main ( void )
{
    float g;
    float h;
    int t;


    g = 2.346;
    h = 2.34599;
    t = comparedigits(g,h);

    printf("%u\n",t);
    printf("raw\n");
    fun.f=g; printf("0x%08X\n",fun.ul);
    fun.f=h; printf("0x%08X\n",fun.ul);
    dun.d=g; printf("0x%08X_%08X\n",dun.ul[1],dun.ul[0]);
    dun.d=h; printf("0x%08X_%08X\n",dun.ul[1],dun.ul[0]);
    printf("trunc\n");
    dun.d=trunc(1000.0 * g); printf("0x%08X_%08X\n",dun.ul[1],dun.ul[0]);
    dun.d=trunc(1000.0 * h); printf("0x%08X_%08X\n",dun.ul[1],dun.ul[0]);
    printf("trunc\n");
    dun.d=trunc(1000.0F * g); printf("0x%08X_%08X\n",dun.ul[1],dun.ul[0]);
    dun.d=trunc(1000.0F * h); printf("0x%08X_%08X\n",dun.ul[1],dun.ul[0]);
    printf("floor\n");
    dun.d=floor(1000.0 * g); printf("0x%08X_%08X\n",dun.ul[1],dun.ul[0]);
    dun.d=floor(1000.0 * h); printf("0x%08X_%08X\n",dun.ul[1],dun.ul[0]);
    printf("ceil\n");
    dun.d=ceil(1000.0 * g); printf("0x%08X_%08X\n",dun.ul[1],dun.ul[0]);
    dun.d=ceil(1000.0 * h); printf("0x%08X_%08X\n",dun.ul[1],dun.ul[0]);

    printf("%u\n",(unsigned int)(g*1000.0));
    printf("%u\n",(unsigned int)(h*1000.0));

    if (trunc(1000.0F * g) == trunc(1000.0F * h))
    {
        printf("true\n");
    }
    else
    {
        printf("false\n");
    }
    return(0);
}

compile and run

gcc test.c -o test -lm
./test 
1
raw
0x401624DD
0x401624B3
0x4002C49B_A0000000
0x4002C496_60000000
trunc
0x40A25200_00000000
0x40A25200_00000000
trunc
0x40A25400_00000000
0x40A25200_00000000
floor
0x40A25200_00000000
0x40A25200_00000000
ceil
0x40A25400_00000000
0x40A25400_00000000
2345
2345
false

So doing the 1000 * x in single math instead of double math appears to fix the problem

1000.0 * a is mixed mode. The 1000.0 is a double by the C standards unless specified to be a single. And a is a single, so a is converted to a double the math is done as double then it is fed to a double function. 1000.0F is a single, a is a single, so the multiply is done as single math, then it is converted to double. So perhaps the real issue is in the conversion and rounding of g and h to a double. Would have to dig more into the mantissa differences...

I think the key is this, the double times single 1000.0 * x results

trunc
0x40A25200_00000000
0x40A25200_00000000

If those are equal then anything you do the same number will come out the same. When it is a single times a single then converted to a double, they differ.

trunc
0x40A25400_00000000
0x40A25200_00000000

and that makes your code work (for those two specific values).

false
old_timer
  • 69,149
  • 8
  • 89
  • 168
  • 1
    Your first paragraph is nonsense from beginning to end. IEEE 754 floating-point equality works just fine, and for any given IEEE 754 binary format each finite floating-point value (apart from `+0.0` and `-0.0`) represents a rational that is not represented by any other other value of the same format. – Pascal Cuoq Sep 08 '13 at 21:51
  • And adding 0.5 to compute the nearest integer with truncation does not work very well: http://blog.frama-c.com/index.php?post/2013/05/02/nearbyintf1 (in double-precision, the constants are `0.999999999999999889` for the first problematic value and 2^52..2^53 for the range of values that are exactly one apart). – Pascal Cuoq Sep 08 '13 at 21:56