2013-11-23 11 views
6

Próbuję zaimplementować eps(x) funkcji MATLAB w C++osprzętem EPS MATLAB w (x) w C++

na przykład w Matlab:

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

Jednak gdy próbuję to zrobić w C++ Nie jestem w stanie uzyskać prawidłowej pojedynczej precyzji odpowiedzi.

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

} 

Uruchomienie programu pojawia się następujący komunikat:

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

Wydaje się, że z jakiegoś powodu, chociaż wartości EPS dla pojedynczej i podwójnej precyzji są poprawne, wyjście używając nextafter jedyna funkcja wyjścia wartość podwójnej precyzji. Moja wartość dla epsxf powinna wynosić 6.1035e-05, tak jak w Matlabie.

Jakieś myśli?

+0

"eps" firmy MATLAB zawsze daje pozytywne rezultaty. Powyższy kod dawałby negatywne wyniki, jeśli 'x' jest większe niż' epsf'. [Tutaj] (http://coliru.stacked-crooked.com/a/68546c8c401c0610) to stały kod: 'double eps (float x) {float xp = std :: abs (x); double x1 = std :: nextafter (xp, xp + 1,0f); return x1 - xp; } ' – legends2k

Odpowiedz

6

Dołącz <cmath> i zadzwoń pod numer std::nextafter, a twój kod będzie działał pod warunkiem, że masz kompilator C++ 11.

W tym <math.h> i wywołanie ::nextafter wywołuje wersję C funkcji. Implementacja C nextafter oczywiście nie obsługuje przeciążeń, więc C zapewnia nextafterf dla wyniku pojedynczej precyzji, jak również nextafterl dla czterokrotnej precyzji. (Po prostu wywołanie podwójnej precyzji nextafter z float nie powiedzie się, ponieważ argument zostanie przekonwertowany na double.) Jeśli nie masz kompilatora C++ 11, możesz naprawić swój kod, wywołując ::nextafterf.

+0

Wow, dziękuję bardzo! – kyle

1

Użyj bibliotek. Funkcja Matlaba o numerze eps w innych językach nazywa się ULP, dla jednostki na ostatnim miejscu. Według Wikipedii na ULP poniższa funkcja z boost C++ library mogą być wykorzystane do obliczenia zmiennoprzecinkowe odległość między dwoma deblu a i b:

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

Dokumentacja float_distance jest here.

+0

Tak, dziękuję, wiedziałem o wprowadzeniu doładowania, jednak dla naszej klasy nie jesteśmy w stanie używać ulepszeń. – kyle

+0

Naprawdę zastanawiam się, jak na świecie ta odpowiedź ocenia głosowanie w dół. Nie tylko wyjaśniłem pojęcie ULP, ale zasugerowałem solidne alternatywne rozwiązanie, które działa zarówno z precyzją pojedynczą, jak i podwójną. OP nie wskazał, że nie chce używać wzmocnienia. – horchler