C2x(以及之前的):
NAN當且僅當實作支持該float型別的安靜 NaN 時,才定義宏。它擴展為表示安靜 NaN 的 float 型別的常量運算式。
示例代碼 (t0a.c)
#include <stdio.h>
#include <math.h>
#include <fenv.h>
#if _MSC_VER && ! __clang__ && ! __INTEL_COMPILER
#pragma fenv_access (on)
#else
#pragma STDC FENV_ACCESS ON
#endif
void print_fe_excepts_raised(void)
{
printf("exceptions raised ");
if (fetestexcept(FE_DIVBYZERO)) printf(" FE_DIVBYZERO");
if (fetestexcept(FE_INEXACT)) printf(" FE_INEXACT");
if (fetestexcept(FE_INVALID)) printf(" FE_INVALID");
if (fetestexcept(FE_OVERFLOW)) printf(" FE_OVERFLOW");
if (fetestexcept(FE_UNDERFLOW)) printf(" FE_UNDERFLOW");
if (fetestexcept(FE_ALL_EXCEPT)==0) printf(" none");
printf("\n");
}
int main(void)
{
float f;
feclearexcept(FE_ALL_EXCEPT);
f = NAN;
print_fe_excepts_raised();
(void)f;
return 0;
}
呼叫:
# msvc (version 19.29.30133 for x64)
$ cl t0a.c /std:c11 /Za /fp:strict && t0a.exe
exceptions raised FE_INEXACT FE_INVALID FE_OVERFLOW
# clang on Windows (version 13.0.0)
$ clang t0a.c -std=c11 -pedantic -Wall -Wextra -ffp-model=strict && ./a.exe
exceptions raised FE_INEXACT FE_INVALID FE_OVERFLOW
# gcc on Windows (version 11.2.0)
$ gcc t0a.c -std=c11 -pedantic -Wall -Wextra && ./a.exe
exceptions raised none
# gcc on Linux (version 11.2.0)
$ gcc t0a.c -std=c11 -pedantic -Wall -Wextra && ./a.out
exceptions raised none
# clang on Linux (version 13.0.0)
$ clang t0a.c -std=c11 -pedantic -Wall -Wextra -ffp-model=strict && ./a.out
exceptions raised none
對于 Windows 上的 msvc 和 clang:這是因為:
C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\ucrt\corecrt_math.h:94:9
#define NAN ((float)(INFINITY * 0.0F))
C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\ucrt\corecrt_math.h:90:9
#define INFINITY ((float)(_HUGE_ENUF * _HUGE_ENUF))
C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\ucrt\corecrt_math.h:87:13
#define _HUGE_ENUF 1e 300 // _HUGE_ENUF*_HUGE_ENUF must overflow
在這里,我們看到NAN“擴展為表示安靜 NaN 的 float 型別的常量運算式”。這意味著f = NAN可能會導致浮點例外。但是,f = NAN通常被視為“寫入記憶體”。因此,人們可能想知道:“如何寫入記憶體會導致引發浮點例外?”。
uj5u.com熱心網友回復:
為了記錄,這...
NAN當且僅當實作支持該float型別的安靜 NaN 時,才定義宏。它擴展為表示安靜 NaN 的 float 型別的常量運算式。
... 是 C17 7.12/5,它可能在 C2x 中具有相同或相似的編號。
更新
在 Windows 上與 MSVC 或 Clang 一起使用時,您的測驗程式會導致引發FE_INVALIDFP 例外這一事實表明
- Microsoft 的 C 標準庫和運行時環境
- MSVC 和 Clang 編譯器和
- 您指定的選項
導致生成信號 NaN 并將其用作算術運算元。我同意這是一個意想不到的結果,可能表明這些組合未能完全符合該領域的 C 語言規范。
與生成的 NaN 是安靜的還是信號的無關。那里的誤解是,FE_INVALID只有在生成或操作信號 NaN 時才會引發標志。事實并非如此。
一方面,IEEE-754 沒有定義生成信號 NaN 的任何情況。所有定義的產生 NaN 的操作都會產生一個安靜的 NaN,包括一個運算元是一個信號 NaN 的操作(所以 Windows 上的 MSVC 和 Clang 幾乎肯定會產生一個安靜的 NaN 作為NAN宏的值)。默認情況下,大多數使用至少一個信號 NaN 作為運算元的操作都會導致 FE_INVALID 標志被引發,但這不是引發該標志的通常原因。
相反,在默認例外處理下,該FE_INVALID標志僅僅因為計算一個沒有定義結果的操作的請求而引發,例如無窮大乘以 0。結果將是一個安靜的 NaN。請注意,這不包括具有至少一個 NaN 運算元的操作,這些運算元確實具有定義的結果:在許多情況下為安靜的 NaN,在比較中為無序/假,以及在少數情況下為其他結果。
對于背景關系,重要的是要認識到,僅僅因為NAN擴展為常量運算式(在符合 C 的實作中)并不意味著該運算式的值是在編譯時計算的。實際上,考慮到 MSVC 和 Clang 的嚴格 fp 模式的規范,我希望這些模式能夠禁用大多數(如果不是全部)FP 運算式的編譯時計算(或者至少傳播 FP 狀態標志,就像計算是在運行時執行的一樣)時間)。
因此,提高FE_INVALID不一定是 中賦值的效果f = NAN。如果(如在 Microsoft 的 C 標準庫中)NAN擴展為涉及算術運算的運算式,則該例外應作為評估該運算式的結果引發,盡管結果 NaN 是安靜的。至少在通過定義__STDC_IEC_559__功能測驗宏宣告完全符合 IEC 60559 的實作中。
因此,雖然我不會反駁
人們可能想知道:“如何寫入記憶體會導致引發浮點例外?”。
, 沒有令人信服的證據表明已經觀察到這種因果關系。
然而,NAN被評估的運算式中的特定外觀所代表的值具有某種物理表現形式。將其放在 FPU 暫存器中是合理的,并且將來自 FPU 暫存器的信號 NaN 存盤到記憶體確實可能導致在某些體系結構上引發 FP 例外。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/356321.html
上一篇:有人可以向我解釋為什么c=1嗎?
