2013-11-23 21 views
6

Sto cercando di implementare la funzione di Matlab eps(x) in C++Implementare eps di Matlab (x) la funzione in C++

Per esempio, in Matlab:

>> eps(587.3888) 
ans = 1.1369e-13 
>> eps(single(587.3888)) 
ans = 6.1035e-05 

Tuttavia, quando provo a fare questo in C++ Non sono in grado di ottenere la risposta corretta a precisione singola.

#include <limits> 
#include <iostream> 
#include <math.h> 

#define DEBUG(x) do { std::cerr << x << std::endl; } while (0) 
#define DEBUG2(x) do { std::cerr << #x << ": " << x << std::endl; } while (0) 

int main() { 

    float epsf = std::numeric_limits<float>::epsilon(); 
    DEBUG2(epsf); 
    double epsd = std::numeric_limits<double>::epsilon(); 
    DEBUG2(epsd); 

    float espxf = nextafter(float(587.3888), epsf) - float(587.3888); 
    double espxd = nextafter(double(587.3888), epsd) - double(587.3888); 
    DEBUG2(espxf); 
    DEBUG2(espxd); 

} 

esecuzione del programma ottengo il seguente output:

$ ./a.out 
epsf: 1.19209e-07 
epsd: 2.22045e-16 
espxf: -1.13687e-13 
espxd: -1.13687e-13 

sembra come se per qualche motivo, anche se i valori eps per singola e doppia precisione sono corretti, l'output utilizzando nextafter funzione soltanto uscite il doppio valore di precisione. Il mio valore per epsxf dovrebbe essere 6.1035e-05 come in Matlab.

Qualche idea?

+0

L''eps' di MATLAB dà sempre risultati positivi. Il codice sopra darebbe risultati negativi se 'x' è maggiore di' epsf'. [Qui] (http://coliru.stacked-crooked.com/a/68546c8c401c0610) è il codice fisso: 'double eps (float x) {float xp = std :: abs (x); double x1 = std :: nextafter (xp, xp + 1.0f); restituisce x1 - xp; } ' – legends2k

risposta

6

Includere <cmath> e chiamare std::nextafter e il codice funzionerà, a condizione che si disponga di un compilatore C++ 11.

Compreso <math.h> e chiamando ::nextafter richiama la versione C della funzione. L'implementazione C di nextafter non supporta ovviamente sovraccarichi, pertanto C fornisce uno nextafterf per risultati a precisione singola, nonché nextafterl per quad-precision. (È sufficiente chiamare la doppia precisione nextafter con float perché l'argomento viene convertito in double.) Se non si dispone di un compilatore C++ 11, è possibile correggere il codice richiamando ::nextafterf.

+0

wow grazie mille! – kyle

1

Utilizzare librerie. La funzione eps di Matlab in altre lingue è denominata ULP, per unità nell'ultimo posto. Secondo l'articolo di Wikipedia sul ULP, la seguente funzione dal boost C++ library può essere usata per calcolare la distanza in virgola mobile tra due doppie a e b:

boost::math::float_distance(a, b) 

La documentazione per float_distance è here.

+0

sì, grazie, ero a conoscenza dell'implementazione boost, tuttavia per la nostra classe non siamo in grado di utilizzare le librerie boost. – kyle

+0

Mi chiedo davvero come nel mondo questa risposta voti al ribasso. Non solo ho spiegato il concetto di ULP, ma ho suggerito una soluzione alternativa robusta che funziona sia per precisione singola che doppia. Il PO non aveva indicato il suo desiderio di non usare boost. – horchler

Problemi correlati