簡體   English   中英

整數除以零的平台會觸發浮點異常?

[英]On which platforms does integer divide by zero trigger a floating point exception?

在另一個問題中,有人想知道他們為什么會得到一個“浮點錯誤”,實際上他們的C ++程序中有一個整數除零。 圍繞這一點進行了討論,有些人聲稱浮點異常實際上從未因浮點除以零而增加,而只是在整數除以零時出現。

這聽起來很奇怪,因為我知道:

  1. 所有Windows平台上x86和x64上的MSVC編譯代碼報告int除以零為“0xc0000094:整數除以零”,浮點除以零為0xC000008E“浮點除以零”(啟用時)

  2. IA-32和AMD64 ISA將#DE (整數除法異常)指定為中斷0.浮點異常觸發中斷16(x87浮點)或中斷19(SIMD浮點)。

  3. 其他硬件具有類似的不同中斷( 例如, PPC在float-div-by上引發0x7000並且根本不捕獲int / 0)。

  4. 我們的應用程序使用_controlfp_s內部函數(最終是stmxcsr op)取消屏蔽零除零的浮點異常,然后捕獲它們以進行調試。 所以我在實踐中肯定會看到IEEE754被零除的異常。

因此,我得出結論,有些平台將異常作為浮點異常報告,例如x64 Linux(無論ALU管道如何,都會針對所有算術錯誤提升SIGFPE)

其他操作系統(如果您操作系統,還是C / C ++運行時)報告整數除零作為浮點異常?

我不確定目前的情況如何,但目前的情況是FP異常檢測支持與整數非常不同。 陷阱的整數除法很常見。 POSIX要求它在引發異常時引發SIGFPE

但是,你可以理清它是什么類型的SIGFPE,看它實際上是一個除法異常。 (但不一定是被0除以:2的補碼INT_MIN / -1除法陷阱,當64b / 32b除法的商不適合32b輸出寄存器時, x86的dividiv也陷阱。但事實並非如此在AArch64上使用sdiv 。)

glibc手冊解釋了BSD和GNU系統為SIGFPE的信號處理程序提供了額外的arg,它將被FPE_INTDIV_TRAP除以零。 siginfo_t包含該成員的系統上,POSIX將FPE_INTDIV_TRAP記錄為siginfo_tint si_code字段的可能值。

IDK,如果Windows首先提供不同的異常,或者它將事物捆綁到與Unix相同的算術異常的不同風格中。 如果是這樣,默認處理程序會對額外信息進行解碼,以告訴您它是什么類型的異常。

POSIX和Windows都使用短語“除以零”來涵蓋所有整數除法異常,所以顯然這是常見的簡寫。 對於知道關於INT_MIN / -1(帶有2的補碼)的人來說是一個問題,短語“除以零”可以被視為除法異常的同義詞。 這句話立即指出了那些不知道為什么整數除法可能成為問題的人的常見情況。


FP異常語義

對於大多數操作系統/ C ABI中的用戶空間進程,FP異常在默認情況下被屏蔽。

這是有道理的,因為IEEE浮點可以表示無窮大,並且有NaN將錯誤傳播到使用該值的所有未來計算。

  • 0.0/0.0 => NaN
  • 如果x是有限的: x/0.0 => +/-Inf ,符號為x

這甚至允許這樣的事情在掩蓋異常時產生合理的結果:

double x = 0.0;
double y = 1.0/x;   // y = +Inf
double z = 1.0/y;   // z = 1/Inf = 0.0, no FP exception

FP與整數錯誤檢測

FP檢測錯誤的方法非常好:當屏蔽異常時,它們在FP狀態寄存器中設置一個標志而不是陷阱。 (例如x86的MXCSR用於SSE指令)。 標志保持設置直到手動清除,因此您可以檢查一次(例如循環之后)以查看發生了哪些異常,但不是它們發生的位置。

已經提出了具有類似“粘性”整數溢出標志的建議,以記錄在計算序列期間的任何點處是否發生溢出。 允許屏蔽整數除法異常在某些情況下會很好,但在其他情況下會很危險(例如,在地址計算中,您應該陷阱而不是潛在地存儲到虛假位置)。

但是,在x86上,檢測在計算序列期間是否發生整數溢出需要在每一個之后放置一個條件分支,因為標志只是被覆蓋。 MIPS有一個add指令,它將捕獲有符號溢出,以及一個永不陷阱的無符號指令。 因此,整數異常檢測和處理的標准化程度要低得多。


整數除法不能選擇產生NaN或Inf結果, 因此以這種方式工作是有意義的

整數除法產生的任何整數位模式都是錯誤的,因為它將代表一個特定的有限值。

但是,在x86上,如果屏蔽了“浮點無效”異常,則使用cvtsd2si或任何類似的轉換指令將超出范圍的浮點值轉換為整數會產生“整數不定”值。 除符號位外,該值為全零。 INT_MIN

(參見英特爾手冊, 標簽wiki中的鏈接。

其他操作系統(如果您是操作系統,還是C / C ++運行時)報告整數除零作為浮點異常?

答案取決於您是在內核空間還是用戶空間 如果你在內核空間,你可以將“i / 0”放在kernel_main() ,讓你的中斷處理程序調用異常處理程序並暫停你的內核。 如果您在用戶空間中,答案取決於您的操作系統和編譯器設置。

AMD64硬件指定整數除零作為中斷0,不同於中斷16(x87浮點異常)和中斷19(SIMD浮點異常)。

“除零”例外是用div指令除以零。 討論x87 FPU超出了本問題的范圍。

其他硬件具有類似的不同中斷(例如,PPC在float-div-by上引發0x7000並且根本不捕獲int / 0)。

更具體地說, 00700映射到異常類型“Program”,其中包括一個啟用浮點的異常。 如果嘗試使用浮點指令進行除零,則會引發此類異常。

另一方面,整數除法是每個PPC PEM的未定義行為:

8-53分

如果嘗試執行任一分區-0x8000_0000÷-1或÷0,則rD的內容未定義,CR0字段的LT,GT和EQ位的內容也是如此(如果Rc = 1 )。 在這種情況下,如果OE = 1則設置OV。

我們的應用程序使用_controlfp_s內部函數(最終是stmxcsr op)取消屏蔽零除零的浮點異常,然后捕獲它們以進行調試。 所以我在實踐中肯定會看到IEEE754被零除的異常。

我認為你的時間最好花在編譯時而不是在運行時除以零。

對於用戶空間,這發生在運行在POWER上的AIX上,在PA-RISC上運行的HP-UX,在x86-64上運行的Linux,在x86-64上運行的macOS,在Alpha上運行的Tru64和在SPARC上運行的Solaris上。

在編譯時避免除零會好得多。

暫無
暫無

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

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