2015-09-23 13 views
10

Utilizzando std::exp per calcolare e^-infinity rendimenti -infinity quando si utilizza la rappresentazione galleggiante di infinito e di costruzione di un binario x64 utilizzando Visual C++ 2013. Vorrei invitare per restituisce 0, che è ciò che accade con build Win32 o la versione di std::exp che prende uno double.std :: exp del galleggiante infinito negativo torna infinito negativo per x64 costruisce in Visual C++ 2013

Il seguente codice, creato come x64, illustra il problema.

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

opzioni della riga di comando per la compilazione (presi da 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" 

uscita di cui sopra:

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

Perché accade questo?

+2

Questo è un bug; è stato risolto nelle librerie di runtime di Visual C++ 2015. –

+0

@JamesMcNellis - non è questa la risposta definitiva? –

risposta

8

Direi normalmente che si trattava di un bug di qualche descrizione, poiché C++ 11 riporta a C99 per la funzionalità cmath e C99 indica chiaramente in che exp(−∞) returns +0. Tuttavia, tenere a mente che è in un allegato dello standard in cui si afferma:

Un'implementazione che definisce __STDC_IEC_559__ deve essere conforme alle specifiche del presente allegato.

Quella macro non sembra essere definite in modalità a 32 o 64 bit in MSVC quindi è probabilmente non un bug e si può essere fuori di fortuna. Né la modifica della modalità a virgola mobile tra /fp:strict e /fp:precise migliora le cose.

In tutti i casi, il risultato sembra differire tra target a 32 bit e 64 bit e, in base allo standard che afferma solo che exp sarà compute the base-e exponential of x con apparentemente senza requisiti su come, sembra essere a posto.


Se siete alla ricerca di una soluzione rapida, utilizzando la funzione pow sembra generare i risultati corretti:

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

Questo genera zero per entrambe le linee indipendentemente dal fatto che si dispone di 64-bit/32-bit, debug/release o fp:precise/fp:strict ma, se questo è garantito, non potrei dire.

+1

L'allegato F non è tutto facoltativo? – hvd

+0

@hvd, dipende dal fatto che MSVC definisca '_ _STDC_IEC_559_ _'. Non l'ho installato localmente quindi non posso controllare. Aggiornerò la risposta – paxdiablo

+0

punteggio ++ questo potrebbe effettivamente essere un problema rigoroso/preciso. – imallett