簡體   English   中英

C/C++ 中的整數除法會遇到精度問題嗎?

[英]Can integer division in C/C++ run into loss of precision issues?

假設我們有三個整數(int、long、long long、unsigned int 等)變量a, b, c 通常,執行

c = a / b;

將導致截斷分數。 但是,c 是否有可能以不正確的值結束?

我不是在談論 a / b 可能超出c's type.的范圍c's type. 而是說C中是如何實現整數除法的,執行a / b是不是先生a / b一個浮點型的中間結果,然后中間值被截斷?

如果是這樣,我想知道中間值的精度損失是否會導致 c 的值不正確。 例如,假設 a / b 的精確值是 2,但不知何故中間結果是1.9999... ,因此 c 最終會得到不正確的值 1。這種情況會發生嗎,或者整數除法總是導致 a如果預期值在 c 的類型范圍內,則值是否正確?

執行 a/b 是否先生成浮點型中間結果

就語言而言,沒有中間結果。

如果預期值在 c 類型的范圍內,整數除法是否總是產生正確的值?

是的。

C11 標准的第 6.5.5 節規定

當整數被除時, /運算符的結果是代數商,其中任何小數部分都被丟棄。 如果商a/b是可表示的,則表達式(a/b)*b + a%b應等於a;

這意味着從數學上講,您不可能得到錯誤的結果。

假設我們有三個整數(int、long、long long、unsigned int 等)變量 a、b、c。 通常,執行

c = a / b;

將導致截斷分數。 但是, c是否有可能以不正確的值結束? 我不是在談論 a / b 可能超出 c 類型的范圍。

例如,除法的最后一位數字不應該是錯誤的,如果其他所有規則都被遵守的話。 C11 6.5.5p6

當整數被除時, /運算符的結果是代數商,其中任何小數部分都被丟棄。

即結果不是“接近”但與 a / b 在代數上完全相同,只是丟棄該點之后的任何內容。

這並不意味着不會有任何問題: a / b的除法可能在數學上沒有超出c類型的范圍,但超出除法本身使用的類型的范圍,這可能會導致錯誤值在 c 中設置。

考慮這個例子:

#include <stdio.h>
#include <inttypes.h>   

int main(void) {
    int32_t a = INT32_MIN;
    int32_t b = -1;
    int64_t c = a / b;
    printf("%" PRId64, c);
}

INT32_MIN / -1的除法結果用c表示, INT32_MAX + 1 然而,在 32 位平台上,算術以 32 位進行,並且這種除法會產生整數溢出,從而導致行為未定義。 在我的計算機上發生的情況是,如果我在沒有優化的情況下進行編譯,它會中止程序。 如果我在啟用優化 ( -O3 ) 的情況下進行編譯,編譯器將在編譯時解析此計算,並以特殊方式處理溢出並生成結果-2147483648負值

同樣,如果你這樣做:

uint16_t a = 16;
int16_t b = -1;
int32_t result = a / b;
printf("%" PRId32 "\n", result);

在 32 位 int 機器上的結果是 -16。 如果更改的類型auint32_t數學發生在無符號:

uint32_t a = 16;
int16_t b = -1;
int32_t result = a / b;
printf("%" PRId32 "\n", result);

結果當然是0 在 16 位機器上,你也會從前面的計算中得到0

暫無
暫無

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

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