Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it safe to use == on FP in this example

I stumbled onto this code here.

Generators doubleSquares(int value)
{
    Generators result;
    for (int i = 0; i <= std::sqrt(value / 2); i++) // 1
    {
        double j = std::sqrt(value - std::pow(i, 2)); // 2
        if (std::floor(j) == j) // 3
            result.push_back( { i, static_cast<int>(j) } ); // 4
    }
    return result;
}

Am I wrong to think that //3 is dangerous ?

like image 414
NoSenseEtAl Avatar asked Jan 21 '14 01:01

NoSenseEtAl


People also ask

Why do computers mess up floating point math?

Because JavaScript uses the IEEE 754 standard for Math, it makes use of 64-bit floating numbers. This causes precision errors when doing floating point (decimal) calculations, in short, due to computers working in Base 2 while decimal is Base 10.

Is true positive rate same as recall?

Recall and True Positive Rate (TPR) are exactly the same. So the difference is in the precision and the false positive rate. The main difference between these two types of metrics is that precision denominator contains the False positives while false positive rate denominator contains the true negatives.

Why are floating points not precise?

Floating-point decimal values generally do not have an exact binary representation. This is a side effect of how the CPU represents floating point data. For this reason, you may experience some loss of precision, and some floating-point operations may produce unexpected results.


1 Answers

This code is not guaranteed by the C++ standard to work as desired.

Some low-quality math libraries do not return correctly rounded values for pow, even when the inputs have integer values and the mathematical result can be exactly represented. sqrt may also return an inaccurate value, although this function is easier to implement and so less commonly suffers from defects.

Thus, it is not guaranteed that j is exactly an integer when you might expect it to be.

In a good-quality math library, pow and sqrt will always return correct results (zero error) when the mathematical result is exactly representable. If you have a good-quality C++ implementation, this code should work as desired, up to the limits of the integer and floating-point types used.


Improving the Code

This code has no reason to use pow; std::pow(i, 2) should be i*i. This results in exact arithmetic (up to the point of integer overflow) and completely avoids the question of whether pow is correct.

Eliminating pow leaves just sqrt. If we know the implementation returns correct values, we can accept the use of sqrt. If not, we can use this instead:

for (int i = 0; i*i <= value/2; ++i)
{
    int j = std::round(std::sqrt(value - i*i));
    if (j*j + i*i == value)
        result.push_back( { i, j } );
}

This code only relies on sqrt to return a result accurate within .5, which even a low-quality sqrt implementation should provide for reasonable input values.

like image 78
Eric Postpischil Avatar answered Sep 27 '22 16:09

Eric Postpischil