# Floating point comparison [duplicate]

``````int main()
{
float a = 0.7;
float b = 0.5;
if (a < 0.7)
{
if (b < 0.5) printf("2 are right");
else         printf("1 is right");
}
else printf("0 are right");
}
``````

I would have expected the output of this code to be `0 are right`. But to my dismay the output is `1 is right` why?

84
``````int main()
{
float a = 0.7, b = 0.5; // These are FLOATS
if(a < .7)              // This is a DOUBLE
{
if(b < .5)            // This is a DOUBLE
printf("2 are right");
else
printf("1 is right");
}
else
printf("0 are right");
}
``````

Floats get promoted to doubles during comparison, and since floats are less precise than doubles, 0.7 as float is not the same as 0.7 as double. In this case, 0.7 as float becomes inferior to 0.7 as double when it gets promoted. And as Christian said, 0.5 being a power of 2 is always represented exactly, so the test works as expected: `0.5 < 0.5` is false.

So either:

• Change `float` to `double`, or:
• Change `.7` and `.5` to `.7f` and `.5f`,

and you will get the expected behavior.

Tuesday, June 1, 2021

85

Writing a useful general-purpose floating point `IsEqual` is very, very hard, if not outright impossible. Your current code will fail badly for `a==0`. How the method should behave for such cases is really a matter of definition, and arguably the code would best be tailored for the specific domain use case.

For this kind of thing, you really, really need a good test suite. That's how I did it for The Floating-Point Guide, this is what I came up with in the end (Java code, should be easy enough to translate):

``````public static boolean nearlyEqual(float a, float b, float epsilon) {
final float absA = Math.abs(a);
final float absB = Math.abs(b);
final float diff = Math.abs(a - b);

if (a == b) { // shortcut, handles infinities
return true;
} else if (a == 0 || b == 0 || absA + absB < Float.MIN_NORMAL) {
// a or b is zero or both are extremely close to it
// relative error is less meaningful here
return diff < (epsilon * Float.MIN_NORMAL);
} else { // use relative error
return diff / (absA + absB) < epsilon;
}
}
``````

You can also find the test suite on the site.

Appendix: Same code in c# for doubles (as asked in questions)

``````public static bool NearlyEqual(double a, double b, double epsilon)
{
const double MinNormal = 2.2250738585072014E-308d;
double absA = Math.Abs(a);
double absB = Math.Abs(b);
double diff = Math.Abs(a - b);

if (a.Equals(b))
{ // shortcut, handles infinities
return true;
}
else if (a == 0 || b == 0 || absA + absB < MinNormal)
{
// a or b is zero or both are extremely close to it
// relative error is less meaningful here
return diff < (epsilon * MinNormal);
}
else
{ // use relative error
return diff / (absA + absB) < epsilon;
}
}
``````
Tuesday, June 1, 2021

39

bash doesn't do floats, use awk

``````key1=12.3
result=12.5
var=\$(awk 'BEGIN{ print "'\$key1'"<"'\$result'" }')
# or var=\$(awk -v key=\$key1 -v result=\$result 'BEGIN{print result<key?1:0}')
# or var=\$(awk 'BEGIN{print "'\$result'"<"'\$key1'"?1:0}')
# or
if [ "\$var" -eq 1 ];then
echo "do something"
else
echo "result more than key"
fi
``````

there are other shells that can do floats, like zsh or ksh, you might like to try using them as well

Sunday, June 13, 2021