2013-05-01 147 views
1

我有一個輸入浮點值是0.0f < =值< 1.0f(注意不到一個)。在C++中找到最接近的小於特定整數值的浮點值?

將此值乘以較大範圍時,浮點精度自然會下降,這意味着該值可能會超出等效範圍。

例如,如果我開始了與一個值,如:

0.99999983534521f

然後乘以100,我得到:

100.000000000000f

這很好,但然後如何將浮點表示降低到最接近的浮點值仍小於100?

我發現這個小手冊招:

union test 
{ 
    int integer; 
    float floating; 
}; 

test value; 

value.floating = 1.0f; 

printf("%x\n", value.integer); 

然後我採取的十六進制值,並通過一個十六進制數字減少它,然後將其設置明確的,像這樣:

unsigned int almost_one = 0x3f7fffff; 

float value = 1.0f; 

if (value >= 1.0f)  std::memcpy(&value, &almost_one, sizeof(float)); 

,對於運作良好這個具體的價值,但是我可以使用更通用的方法嗎?

我希望有一個神奇的指令,我不知道,我可以用它來實現這一點!

編輯:偉大的答案在這裏,std :: nextafter看起來像我以後。不幸的是我還不能使用C++ 11數學庫,所以這對我不起作用。爲了節省複雜的事情,我將用C++ 11標記這個問題並接受Mike的答案。

我已經開始爲C++ 03的新問題:Alternative to C++11's std::nextafter and std::nexttoward for C++03?

+1

這看起來像未定義的行爲... – Sebivor 2013-05-01 16:44:42

+1

你想要達到什麼目的?如果你的結果恰好是100.0f那麼這是最接近實際結果的數字。將尾數減1只會讓你的結果不那麼敏感。 – typ1232 2013-05-01 16:46:11

+0

另一個至關重要的問題......你如何印刷這些價值觀? – Sebivor 2013-05-01 16:50:36

回答

6

我希望有一個神奇的指令,我不知道的,我可以用它來實現這一目標!

如果你已經有了一個C++ 11(或C99)標準庫,然後從<cmath>(或nextafter<math.h>std::nextafter(value, 0.0f)會給你最大的表示值比value小。

它給出了第一個參數後面的「下一個」不同的值,在第二個方向上;所以在這裏,下一個不同的值接近零。

+1

如果'value'爲正,它會給出比'value'更小的最大可表示值。在問題描述的情況下,這是令人滿意的。然而,如果你想要所有情況下的下一個最大表示值,它應該是'std :: nextafter(value,-std :: numeric_limits ().infinity())'。 – 2013-05-01 17:04:00

+0

@EricPostpischil:事實上,我認爲「更小」意味着「幅度更小」,並增加了第二段來澄清我的意思是「趨於零」。除非我需要,否則我會有點緊張地混淆無窮無盡,所以我沒有提到與這個問題有關的問題,即「趨於零」足夠好。 – 2013-05-01 17:08:12

+0

很好的答案,謝謝。 – Dan 2013-05-02 10:44:51

0

對不起,我第一次錯過了這個觀點。你在找什麼當然是unit in the last place (ULP),這是密切相關的machine epsilon。以下是演示:

#include <iostream> 
#include <cmath> 
#include <cassert> 

float compute_eps() { 
    float eps = 1.0f; 

    // Explicit cast to `float` is needed to 
    // avoid possible extra precision pitfalls. 
    while (float(1.0f + eps) != 1.0f) 
    eps /= 2.0f; 

    return eps; 
} 

float ulp(float x) { 
    int exp; 

    frexp(x, &exp); 

    static float eps = compute_eps(); 

    return eps * (1 << exp); 
} 

main() { 
    float x = 100.0f; 
    float y = x - ulp(x); 
    float z = nextafterf(x, 0.0f); 

    assert(y == z); 

    std::cout.precision(20); 
    std::cout << y << std::endl; 
    std::cout << z << std::endl; 
} 

請明白,這答案更多用於教育,而不是實際的。我想要顯示哪些數量(來自理論)必須涉及以確定相鄰的浮點數。例如,當然可以使用std::numeric_limits<T>::epsilon()來確定機器的epsilon。或者繼續使用防彈nextafterf(這可能會比我的演示更高效地實現)來直接獲取相鄰的浮點數。總而言之,不要認真對待這個答案。

注:指數的特殊情況(如NaN的無窮低於正常,等)在本演示中沒有處理。但是如何擴展這個演示來支持它們是非常簡單的。

+0

您從'value'中減去以獲得下一個較低的可表示數量的數量稱爲ULP,而不是ε。 – 2013-05-01 17:05:21

+0

@Pascal Cuoq:看看[這裏](https://en.wikipedia.org/wiki/Unit_in_the_last_place)ULP如何與機器epsilon相關。 – 2013-05-01 17:10:00

+0

我知道ULP如何與epsilon相關,我只是說OP想要獲得最接近的較低的浮點數值到100附近的值,並且減去一個機器epsilon不會讓他到達那裏。 – 2013-05-01 17:11:25

相關問題