Boost logo

Boost :

From: Ed Brey (edbrey_at_[hidden])
Date: 2001-11-07 09:00:55


From: "Peter Dimov" <pdimov_at_[hidden]>
>
> No, std::sqrt fails for ints. boost::sqrt(float/double/etc) would simply
> call std::sqrt (since equality comparisons on FP numbers are unreliable.)
> boost::sqrt(int) would check for 'magic' numbers (i.e. argument is in [0,
> 512).)

Oh, I see. Yes, that would seem to work. So the boost implementation might be like this:

namespace boost {
  inline double sqrt(int x) {
    switch (x) {
        case 2: return 1.41;
        case 3: return 1.73;
    }
    return std::sqrt(double(x));
  }
  inline double sqrt(double x) {return std::sqrt(x);}
}

It seems like a pretty good heuristic. In many cases, it would do exactly what is desired. It will still lead to a pessimisation for some uses, however. For example:

double rectangle_diagonal(int x, int y) { // size in pixels; therefore using int
  return sqrt(x*x + y*y);
}

This example leads us to the issue that predicates this approach: The Boost optimization aside, should the standard sqrt have an int overload? In my opinion it should, just as a matter of consistency and convenience. The convenience argument is made by the above example and examples such as sqrt(2). For consistency, consider the other functions that return double results: operator*(double,double) and operator/(double,double). In both cases, there are overloads to accept a single argument as an integer. One could argue that sqrt(int) should be like operator*(int,int) and return a truncated integer, but I don't see this being very useful, so the closest useful parallel to follow is operator*(double,int).

If the sqrt(int) becomes standard, the special case checks for 2, etc., would be undesireable, since you would be paying for those checks every time you aren't using them. I think its better just to keep the optimization out until the compiler can simply do a compile-time check to see if it has a constant, and if so, perform the square root at compile time and substitute the results at compile-time for the sqrt expression.

For the record, regarding the earlier approach of comparing x == 2.0, in this case, an equality comparison is reliable for cases of a literal used for the argument, e.g. sqrt(2). If the argument has a calculated, inprecise value of two, then the equality check would not pick it up, but such is beyond the scope of the intended optimization anyway.

> The check will usually be faster than the int -> double conversion.

The assumption with the earlier approach is that the int -> double conversion as well as the matching of the double to the constant within the sqrt function would all be done at compile time, so speed is not an issue.

> Of course now we have the problem with the return type of boost::sqrt(int).

This problem I don't see, so long as only the boost version is used.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk