为什么我会得到std :: exp特定于平台的结果? [英] Why do I get platform-specific result for std::exp?

查看:147
本文介绍了为什么我会得到std :: exp特定于平台的结果?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个程序在Android和Windows下给出了截然不同的结果.当我针对包含预期结果的二进制文件验证输出数据时,即使很小(四舍五入的问题),差异也很烦人,我必须找到一种解决方法.

这是一个示例程序:

#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;
}

在Windows中,使用Visual 2015编译,得到输出:

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

在使用g ++ NDK r11b编译的Android/armv7下,我得到了输出:

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

因此从e-20开始,结果是不同的:

PC:      0.00038114128472300899284561093161
Android: 0.000381141284723008938635502307335

请注意,我的程序执行了大量数学运算,并且我只注意到std::exp对于相同的输入产生了不同的结果...并且仅对于某些特定的输入值(未调查这些值是否具有相似的属性) ,对于大多数人来说,结果是相同的.

  • 这种行为是预期的"吗,在某些情况下不能保证得到相同的结果吗?
  • 是否存在一些可以解决该问题的编译器标志?
  • 还是我需要对结果进行取整以在两个平台上都以相同的结尾?那么什么是四舍五入的好策略?因为如果var输入很小,在e-20处舍入舍入会丢失太多信息?

我认为我的问题不是重复的浮点数学运算符吗?.我在两个平台上都得到完全相同的结果,只有std::exp的某些特定值会产生不同的结果.

该标准未定义应如何实现exp函数(或任何其他数学库函数 1 ),因此每个库实现可能使用其他计算方法.

例如,Android C库( sqrt 函数或 std :: fma 以及一些舍入函数和基本算术运算

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.

解决方案

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.

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

这篇关于为什么我会得到std :: exp特定于平台的结果?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆