Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do I get platform-specific result for std::exp? [duplicate]

I have a program that were giving slithly different results under Android and Windows. As I validate the output data against a binary file containign expected result, the difference, even if very small (rounding issue) is annoying and I must find a way to fix it.

Here is a sample program:

#include <iostream>
#include <iomanip>
#include <bitset>

int main( int argc, char* argv[] )
{
    // this value was identified as producing different result when used as parameter to std::exp function
    unsigned char val[] = {158, 141, 250, 206, 70, 125, 31, 192};

    double var = *((double*)val);

    std::cout << std::setprecision(30);

    std::cout << "var is " << var << std::endl;
    double exp_var = std::exp(var);
    std::cout << "std::exp(var) is " << exp_var << std::endl;
}

Under Windows, compiled with Visual 2015, I get the output:

var is -7.87234042553191493141184764681
std::exp(var) is 0.00038114128472300899284561093161

Under Android/armv7, compiled with g++ NDK r11b, I get the output:

var is -7.87234042553191493141184764681
std::exp(var) is 0.000381141284723008938635502307335

So the results are different starting e-20:

PC:      0.00038114128472300899284561093161
Android: 0.000381141284723008938635502307335

Note that my program does a lot of math operations and I only noticed std::exp producing different results for the same input...and only for some specific input values (did not investigate if those values are having a similar property), for most of them, results are identical.

  • Is this behaviour kind of "expected", is there no guarantee to have the same result in some situations?
  • Is there some compiler flag that could fix that?
  • Or do I need to round my result to end with the same on both platformas? Then what would be the good strategy for rounding? Because rounding abritrary at e-20 would loose too many information if input var in very small?

Edit: I consider my question not being a duplicate of Is floating point math broken?. I get exactly the same result on both platforms, only std::exp for some specific values produces different results.

like image 559
jpo38 Avatar asked Jan 18 '19 08:01

jpo38


1 Answers

The standard does not define how the exp function (or any other math library function1) should be implemented, thus each library implementation may use a different computing method.

For instance, the Android C library (bionic) uses an approximation of exp(r) by a special rational function on the interval [0,0.34658] and scales back the result.

Probably the Microsoft library is using a different computing method (cannot find info about it), thus resulting in different results.

Also the libraries could take a dynamic load strategy (i.e. load a .dll containing the actual implementation) in order to leverage the different hardware specific features, making it even more unpredictable the result, even when using the same compiler.

In order to get the same implementation in both (all) platforms, you could use your own implementation of the exp function, thus not relying on the different implementations of the different libraries.

Take into account that maybe the processors are taking different rounding approaches, which would yield also to a different result.

1There are some exceptions to these, for isntance the sqrt function or std::fma and some rounding functions and basic arithmetic operations

like image 83
LoPiTaL Avatar answered Nov 05 '22 00:11

LoPiTaL