[英]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。 如果更改的類型a
到uint32_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.