1

I'm looking at some 3rd party code and am unsure exactly what one line is doing. I can't post the exact code but it's along the lines of:

bool function(float x)
{
float f = doCalculation(x);
return x > 0 ? f : std::numeric_limits<float>::infinity();
}

This obviously throws a warning from the compiler about converting float->bool, but what will the actual behaviour be? How does Visual C++ convert floats to bools? At the very least I should be able to replace that nasty infinity...

Drew Dormann
  • 59,987
  • 13
  • 123
  • 180
Mr. Boy
  • 60,845
  • 93
  • 320
  • 589
  • 4
    That looks like bad code to me. Why do the calculation if `x <= 0.0`? Why go to the trouble of writing out the expression for infinity rather than 1.0, since they both convert to `true`? Why calculate something from x and return false if `x > 0.0` and `f == 0.0`, rather than `abs(f) < epsilon`, since floating-point equality (in the conversion of `float` to `bool`) is uncertain? I think you've got some bad code there. – David Thornley Dec 28 '09 at 15:06
  • Can't post the "exact" code? What is the "exact" name of function(x)? – fupsduck Dec 28 '09 at 15:55
  • 1
    What difference does it make? I can't post the code due to license restrictions, this is similar enough to be equivalent. – Mr. Boy Dec 28 '09 at 23:34
  • Because the function name normally provides insight into what the programmer intended function() to do - which is what everyone here is guessing at. – fupsduck Dec 29 '09 at 07:26

6 Answers6

26

I think it is a mistake. That function should return a float. This seem logical to me.

The conversion float to bool is the same as float != 0. However, strict comparing two floating points is not always as you'd expect, due to precision.

Cătălin Pitiș
  • 14,123
  • 2
  • 39
  • 62
  • 1
    Not really helpful. This is in a working 3rd party library, I don't have time to trace into calling functions and figure it all out... I just want to know what the float conversion rules are, especially for infinity. – Mr. Boy Dec 28 '09 at 14:19
  • infinity *would* convert to `true`, as it's non-zero, but this smells strongly of a typo. – Drew Dormann Dec 28 '09 at 14:21
  • 12
    How is it not helpful? He answered your question: "The conversion float to bool is the same as float != 0". Is infinity equal to zero? If not, the float will convert to true. – jalf Dec 28 '09 at 14:22
  • 4
    I'd say you don't have time NOT to hunt down a few callers and see what's going on there. This is CLEARLY a mistake (although clearly it's one that isn't causing any trouble right now). If you need to understand, you need to figure out what the callers think is going on, to understand what was meant. – Michael Kohne Dec 28 '09 at 15:44
2

A float will be converted to false if its == 0.0f, but beware of the precision! Otherwise it will be converted to true -- it will be also true if its not exacly 0.0f! Inifinity will also be converted to true. As David Thornley mentioned, your example is very bad code.

WolfgangP
  • 3,195
  • 27
  • 37
1

I think it would be better to use isnan().

isnan() returns true if f is not-a-number. But it will return true for e.g. 0.0 ...

#include <cmath>
bool function(float x)
{
    float f = doCalculation(x);
    return isnan(f) ? false : true;
}

as mentioned that will not catch the case where f is 0.0 - or very close to it.

If you need this you could check with:

bool near0 = std::abs(f) > std::numeric_limits<float>::epsilon();

EDIT: here an improved example including a test driver:

#include <cmath>

#include <limits>
#include <iostream>
#include <vector>

// using namespace std;
bool fn(float f) {
    if (isnan(f)) return false; // it is not-a-number
    return std::abs(f) > std::numeric_limits<float>::epsilon();
}

// testdriver
int main(void) {
    std::vector<float> t;
    t.push_back(0.0);
    t.push_back(0.1);   
    t.push_back(-0.1);
    t.push_back( 0.0 + std::numeric_limits<float>::epsilon());  
    t.push_back( 0.0 - std::numeric_limits<float>::epsilon());
    t.push_back( 0.0 - 2*std::numeric_limits<float>::epsilon());
    t.push_back( 0.0 + 2*std::numeric_limits<float>::epsilon());
    t.push_back( 1.0 * std::numeric_limits<float>::epsilon());      
    t.push_back(-0.1 * std::numeric_limits<float>::epsilon());
    t.push_back( 0.1 * std::numeric_limits<float>::epsilon());
    for (unsigned int i=0; i<t.size(); i++) {
        std::cout << "fn(" << t[i] << ") returned " << fn(t[i]) << std::endl;
    }   
}

testresults:

fn(0) returned 0
fn(0.1) returned 1
fn(-0.1) returned 1
fn(1.19209e-07) returned 0
fn(-1.19209e-07) returned 0
fn(-2.38419e-07) returned 1
fn(2.38419e-07) returned 1
fn(1.19209e-07) returned 0
fn(-1.19209e-08) returned 0
fn(1.19209e-08) returned 0

0

i generally do

return x != 0;
ufukgun
  • 6,889
  • 8
  • 33
  • 55
0

Assuming DoCalculation(x) returns infinity() for non positive values of x then for positive values of x function(x) is true for non-zero values of DoCalculation() and false otherwise. So function(x) is to determine if DoCalculation(x) is zero or not. I would rename function(x) to IsDoCalculationNonzero(x).

fupsduck
  • 3,129
  • 1
  • 19
  • 18
0

This seems pretty straightforward. Remember that the only states recognized for bool is zero or non-zero. So this code:

return x > 0 ? f : std::numeric_limits<float>::infinity();

Would evaluate as follows:

if x > 0 : return f. If f == 0.0F then it will return false. Otherwise it will return true. As others have mentioned, precision issues may give a false true, but if it's working then I 'd say not...

If x <= 0 : return infinity() which is ... an odd case. However, infinity() != 0 -- therefor this will return true. (Reference: http://msdn.microsoft.com/en-us/library/85084kd6.aspx)

Marc Paradise
  • 1,939
  • 17
  • 16