2013-11-23 67 views
6

我試圖實現Matlab的eps(x)功能在C++實現Matlab的EPS(x)函數++

例如,在Matlab:

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

然而,當我嘗試做這在C++我無法得到正確的單精度答案。

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

} 

運行該程序將得到以下的輸出:

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

它好像出於某種原因,即使單精度和雙精度的EPS值是正確的,使用輸出nextafter功能只輸出雙精度值。我在epsxf的值應該是6.1035e-05,因爲它在Matlab中。

有什麼想法?

+0

MATLAB的'eps'總是給出肯定的結果。如果'x'大於'epsf',上面的代碼會給出否定的結果。 [這裏](http://coliru.stacked-crooked.com/a/68546c8c401c0610)是固定代碼:'double eps(float x){float xp = std :: abs(x); double x1 = std :: nextafter(xp,xp + 1.0f);返回x1 - xp; }' – legends2k

回答

6

包括<cmath>和調用std::nextafter,並且只要您有C++ 11編譯器,代碼就可以工作。

包括<math.h>和調用::nextafter調用函數的C版本。 C的實現nextafter顯然不支持過載,因此C爲單精度結果提供了nextafterf,爲四精度提供了nextafterl。 (只需調用雙精度nextafterfloat失敗,因爲參數轉換爲double。)如果您沒有C++ 11編譯器,則可以通過調用::nextafterf來修復代碼。

+0

非常感謝你! – kyle

1

使用庫。 Matlab的eps函數在其他語言中被稱爲ULP,單位在最後。據對ULP維基百科文章,從boost C++ library下面的函數可被用於計算兩個雙打ab之間的浮點距離:

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

的文檔float_distancehere

+0

是的,謝謝我意識到boost實現,但是對於我們的類,我們無法使用boost庫。 – kyle

+0

我真的很想知道在這個世界裏,這個答案是否會降低投票率。我不僅解釋了ULP的概念,而且還提出了一種適用於單精度和雙精度的強大替代解決方案。 OP沒有表明他希望不使用提升。 – horchler