Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::exp of float negative infinity returns negative infinity for x64 builds in Visual C++ 2013

Tags:

c++

visual-c++

Using std::exp to calculate e^-infinity returns -infinity when using the float representation of infinity and building an x64 binary using Visual C++ 2013. I would expect it to return 0, which is what happens with Win32 builds, or the version of std::exp that takes a double.

The following code, built as x64, demonstrates the issue.

#include <limits>
#include <iostream>

int main(const int argc, const char** argv) {
    std::cout << "exp of float -infinity: " << std::exp(-std::numeric_limits<float>::infinity()) << std::endl;
    std::cout << "exp of double -infinity: " << std::exp(-std::numeric_limits<double>::infinity()) << std::endl;
}

Command line options for compile (taken from Visual Studio):

/GS /Wall /Gy /Zc:wchar_t /Zi /Gm- /Od /sdl /Fd"x64\Release\vc120.pdb" /fp:precise /D "_MBCS" /errorReport:prompt /WX /Zc:forScope /Gd /Oi /MD /Fa"x64\Release\" /EHsc /nologo /Fo"x64\Release\" /Fp"x64\Release\NumericLimitsTest.pch" 

Output of above:

exp of float -infinity: -1.#INF
exp of double -infinity: 0

Why does this happen?

like image 760
ajmccluskey Avatar asked Sep 23 '15 05:09

ajmccluskey


1 Answers

I would normally say that was a bug of some description, since C++11 defers to C99 for cmath functionality and C99 clearly states in F.9.3.1 that exp(−∞) returns +0. However, keep in mind that's in an annex of the standard which states:

An implementation that defines __STDC_IEC_559__ shall conform to the specifications in this annex.

That macro doesn't appear to be defined in either 32- or 64-bit mode in MSVC so it's probably not a bug and you may be out of luck. Nor does changing the floating point mode between /fp:strict and /fp:precise make things any better.

In all cases, the result seems to differ between 32-bit and 64-bit target and, based on the standard which only states that exp will compute the base-e exponential of x with seemingly no requirement on how, it seems to be okay.


If you're after a quick fix, using the pow function seems to generate the correct results:

#define DBL_E 2.71828182845904523536
#define FLT_E 2.71828182845904523536f
std::cout
    << "exp of float -infinity: "
    << std::pow(FLT_E, -std::numeric_limits<float>::infinity())
    << std::endl;
std::cout
    << "exp of double -infinity: "
    << std::pow(DBL_E,-std::numeric_limits<double>::infinity())
    << std::endl;

This generates zero for both lines regardless of whether you have 64-bit/32-bit, debug/release or fp:precise/fp:strict but, whether that's guaranteed, I couldn't say.

like image 97
paxdiablo Avatar answered Oct 20 '22 10:10

paxdiablo