簡體   English   中英

類似浮點函數的結果不同

[英]Different results from similar floating-point functions

所以我有2個功能應該做同樣的事情

float ver1(float a0, float a1) {
    float r0 = a0 - a1;
    if (abs(r0) > PI) {
        if (r0 > 0) {
            r0 -= PI2;
        } else {
            r0 += PI2;
            }
    }
    return r0;
}

float ver2(float a0, float a1) {
    float a2 = a1 - PI2;

    float r0 = a0 - a1;
    float r1 = a0 - a2;

    if (abs(r0) < abs(r1)) {
        return r0;
    }
    if (abs(r0) > abs(r1)) {
        return r1;
    }

    return 0;
}

注意:PI和PI2是pi和2 * pi的浮點常量

奇怪的是,有時它們會產生不同的結果,例如,如果喂入它們0.28605145和5.9433694,則第一個結果為0.62586737,第二個結果為0.62586755,我無法弄清楚是什么原因引起的。

如果您手動計算結果應該是什么,您會發現第二個答案是正確的。 我在2d物理模擬中使用了此功能,真正奇怪的是,第一個答案(錯誤的答案)在那里起作用,而第二個答案(正確的答案)使它表現得很瘋狂。 與未知來源的微小差異和如此深遠的影響:|

此時我還是會切換到矩陣,但是這種奇怪的情況讓我感到好奇,有人知道發生了什么嗎?

float通常具有約24位或約7個小數位的精度。

您要減去兩個幅度相似的數字(第一個為r0+PI2 ,第二個為a1-PI2 ),因此正經歷有效度損失 -結果的幾個最高有效位為零,因此剩下的位更少代表差異。 這就是為什么答案僅匹配約6個小數位的原因。

如果需要更高的精度,則double精度或32位或更大的定點表示可能比float更合適。 還有一些可用的任意精度庫,例如GMP ,它可以用您需要的所有精度來表示數字,盡管算術比內置類型慢得多。

您應該使用fabs()函數而不是abs()因為abs()僅適用於整數。 當使用帶有浮點數的abs()時,會得到奇怪和錯誤的結果。

浮點數的行為不像數學實數。 每加2可能會導致“錯誤”。 所以我不會僅僅因為一個例子就稱第一個正確和第二個不正確。 如果要使錯誤保持較小,則需要注意對float進行的每個操作。

如果數字的絕對值在相同范圍內,則誤差通常較小。 如果范圍不同,則誤差會更大。

例如10000000.0 + 0.1 - 10000000.0幾乎不會是0.1

如果知道輸入范圍,則可以調整代碼以減少錯誤。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM