![](/img/trans.png)
[英]Replacing the SIGUSR1 signal handler works differently in standards C11 and GNU11
[英]Machine epsilon calculation is different using C11 and GNU11 compiler flags
當使用Python和Julia時,我可以使用一種巧妙的技巧來研究機器epsilon的特定浮點表示形式。
例如,在Julia 1.1.1中:
julia> 7.0/3 - 4/3 - 1
2.220446049250313e-16
julia> 7.0f0/3f0 - 4f0/3f0 - 1f0
-1.1920929f-7
我目前正在學習C,並編寫了此程序來嘗試實現相同的目的:
#include <stdio.h>
int main(void)
{
float foo;
double bar;
foo = 7.0f/3.0f - 4.0f/3.0f - 1.0f;
bar = 7.0/3.0 - 4.0/3.0 - 1.0;
printf("\nM.E. for float: %e \n\n", foo);
printf("M.E. for double: %e \n\n", bar);
return 0;
}
奇怪的是,我得到的答案取決於我使用的是C11還是GNU11編譯器標准。 我的編譯器是GCC 5.3.0,可在Windows 7上運行並通過MinGW安裝。
簡而言之,當我編譯時: gcc -std=gnu11 -pedantic begin.c
我得到:
M.E. for float: -1.192093e-007
M.E. for double: 2.220446e-016
如我所料,並且與Python和Julia相匹配。 但是當我編譯時: gcc -std=c11 -pedantic begin.c
我得到:
M.E. for float: -1.084202e-019
M.E. for double: -1.084202e-019
這是意外的。 我認為可能是因為GNU的特定功能,這就是為什么我添加-pedantic
標志的原因。 我一直在Google上搜索,發現以下內容: https : //gcc.gnu.org/onlinedocs/gcc/C-Extensions.html,但我仍然無法解釋行為上的差異。
明確地說,我的問題是: 為什么使用不同的標准會導致結果不同?
更新:相同的區別適用於C99和GNU99標准。
在C語言中,獲取float
或double
epsilon的最佳方法是包含<float.h>
並使用FLT_MIN
或DBL_MIN
。
值7.0/3.0 - 4.0/3.0 - 1.0;
C標准沒有完全指定它,因為它允許實現比標稱類型更精確地評估浮點表達式。 在某種程度上,這可以通過使用強制轉換或分配來解決。 C標准要求強制轉換或分配以“放棄”多余的精度。 通常,這不是一個合適的解決方案,因為可以用初始的多余精度和“舍棄”多余精度的操作進行舍入。 與完全以標稱精度進行計算相比,這種兩次舍入可能會產生不同的結果。
將強制轉換方法與問題中的代碼一起使用將產生:
_Static_assert(FLT_RADIX == 2, "Floating-point radix must be two.");
float FloatEpsilon = (float) ((float) (7.f/3) - (float) (4.f/3)) - 1;
double DoubleEpsilon = (double) ((double) (7./3) - (double) (4./3)) - 1;
請注意,需要靜態聲明來確保浮點基數符合此kudge操作的預期。 該代碼還應包括說明此錯誤主意的文檔:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.