下溢何时发生? [英] When does underflow occur?
问题描述
我进入计算 换句话说,如果我们计算 为了编译程序,我使用了 我已经通过这个在线IDE 。 7.12.1错误条件的处理 我发现这个更容易用十六进制表示来演示。请注意,除以2除以最小值之外总是精确的。 I get into a situation where calculating Underflow occurs when the true result of a floating point
operation is smaller in magnitude (that is, closer to zero) than the
smallest value representable as a normal floating point number in the
target datatype (from Arithmetic Underflow, Wikipedia) In other words, if we calculate To compile the program, I used [Edits] I have shared the code above via this online IDE. Underflow is not only a question of range, but also of precision/rounding. 7.12.1 Treatment of error conditions 1.777e-308, converted to the nearest binary64 0x1.98e566222bcfcp-1023, happens to have a significand (0x198E566222BCFC, 7193376082541820) that is a multiple of 10. So dividing by 10 is exact. No roundoff error. I find this easier to demo with hex notation. Note that dividing by 2 is always exact, except for the smallest value. Output
这篇关于下溢何时发生?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋! 1.77e-308/10
触发下溢异常,但计算 1.777e-308/10
不。这很奇怪,因为:
lockquote
当浮点
操作的真实结果幅度较小时(即,更接近于零)
最小值可以作为
目标数据类型(来自算术下溢,维基百科)的正常浮点数表示
x / y
,其中 x
和 y
是 double
,那么如果 0 < | X / Y | < 2.2251e-308
(标准化的最小正数 double
是 2.2251e-308
)。因此理论上, 1.77e-308/10
和 1.777e-308/10
应该触发一个下溢异常。这个理论与我用下面的C程序测试过的东西是矛盾的。
#include< stdio.h>
#include< fenv.h>
#include< math.h>
int main(){
double x,y;
// x = 1.77e-308 =>下溢
// x = 1.777e-308给出==>没有下溢
x = 1.77e-308;
feclearexcept(FE_ALL_EXCEPT);
y = x / 10.0;
if(fetestexcept(FE_UNDERFLOW)){
puts(Underflow \\\
);
}
else puts(No underflow \\\
);
}
gcc程序。 c -lm
;我也试过Clang,这给了我相同的结果。任何解释?
$下溢不仅是一个范围的问题,而且还是精度/四舍五入。 b $ b
如果数学结果的数值太小,在指定类型的对象中,结果不能被表示,而没有非常的舍入误差。 C11§7.12.16
<1.777e-308,转换为最近的 binary64 0x1.98e566222bcfcp-1023,恰好有一个有效数字(0x198E566222BCFC,7193376082541820),它是10的倍数。所以除以10是确切的。没有舍入错误。
#include< float.h>
#include< stdio.h>
#include< fenv.h>
#include< math.h>
$ b $ int uf_test(double x,double denominator){
printf(%。17e%24a,x,x);
feclearexcept(FE_ALL_EXCEPT);
double y = x / denominator;
int uf = !! fetestexcept(FE_UNDERFLOW);
printf(% - 24a%s \\\
,y,uf?Underflow:);
返回uf;
int main(void){
uf_test(DBL_MIN,2.0);
uf_test(1.777e-308,2.0);
uf_test(1.77e-308,2.0);
uf_test(DBL_TRUE_MIN,2.0);
uf_test(pow(2.0,-1000),10.0);
uf_test(DBL_MIN,10.0);
uf_test(1.777e-308,10.0);
uf_test(1.77e-308,10.0);
uf_test(DBL_TRUE_MIN,10.0);
返回0;
$ b $ pre> 2.22507385850720138e-308 0x1p-1022 0x1p-1023
1.77700000000000015e-308 0x1.98e566222bcfcp-1023 0x1.98e566222bcfcp-1024
1.77000000000000003e-308 0x1.97490d21e478cp-1023 0x1.97490d21e478cp-1024
4.94065645841246544e-324 0x1p-1074 0x0p + 0下溢
//不下溢,因为不精确的结果不是太小
9.33263618503218879e-302 0x1p-1000 0x1.999999999999ap-1004
//由于结果太小而且不精确,导致下溢
2.22507385850720138e-308 0x1p-1022 0x1.99999999999ap-1026下溢
//没有下溢,因为结果是精确
1.77700000000000015e-308 0x1.98e566222bcfcp-1023 0x1.471deb4e8973p-1026
1.77000000000000003e-308 0x1.97490d21e478cp-1023 0x1.45d40a818394p-1026下溢
4.94065645841246544e-324 0x1p-1074 0x0p + 0下溢
1.77e-308/10
triggers an underflow exception, but calculating 1.777e-308/10
does not. This is strange because:
x/y
where both x
and y
are double
, then underflow should occur if 0 < |x/y| < 2.2251e-308
(the smallest positive normalized double
is 2.2251e-308
). In theory, therefore, both 1.77e-308/10
and 1.777e-308/10
should trigger an underflow exception. The theory contradicts with what I have tested with the C program below.#include <stdio.h>
#include <fenv.h>
#include <math.h>
int main(){
double x,y;
// x = 1.77e-308 => underflow
// x = 1.777e-308 gives ==> no underflow
x=1.77e-308;
feclearexcept(FE_ALL_EXCEPT);
y=x/10.0;
if (fetestexcept(FE_UNDERFLOW)) {
puts("Underflow\n");
}
else puts("No underflow\n");
}
gcc program.c -lm
; I also tried Clang, which gave me the same result. Any explanation?
The result underflows if the magnitude of the mathematical result is so small that the mathematical result cannot be represented, without extraordinary roundoff error, in an object of the specified type. C11 §7.12.1 6#include <float.h>
#include <stdio.h>
#include <fenv.h>
#include <math.h>
int uf_test(double x, double denominator){
printf("%.17e %24a ", x, x);
feclearexcept(FE_ALL_EXCEPT);
double y=x/denominator;
int uf = !!fetestexcept(FE_UNDERFLOW);
printf("%-24a %s\n", y, uf ? "Underflow" : "");
return uf;
}
int main(void) {
uf_test(DBL_MIN, 2.0);
uf_test(1.777e-308, 2.0);
uf_test(1.77e-308, 2.0);
uf_test(DBL_TRUE_MIN, 2.0);
uf_test(pow(2.0, -1000), 10.0);
uf_test(DBL_MIN, 10.0);
uf_test(1.777e-308, 10.0);
uf_test(1.77e-308, 10.0);
uf_test(DBL_TRUE_MIN, 10.0);
return 0;
}
2.22507385850720138e-308 0x1p-1022 0x1p-1023
1.77700000000000015e-308 0x1.98e566222bcfcp-1023 0x1.98e566222bcfcp-1024
1.77000000000000003e-308 0x1.97490d21e478cp-1023 0x1.97490d21e478cp-1024
4.94065645841246544e-324 0x1p-1074 0x0p+0 Underflow
// No underflow as inexact result is not too small
9.33263618503218879e-302 0x1p-1000 0x1.999999999999ap-1004
// Underflow as result is too small and inexact
2.22507385850720138e-308 0x1p-1022 0x1.99999999999ap-1026 Underflow
// No underflow as result is exact
1.77700000000000015e-308 0x1.98e566222bcfcp-1023 0x1.471deb4e8973p-1026
1.77000000000000003e-308 0x1.97490d21e478cp-1023 0x1.45d40a818394p-1026 Underflow
4.94065645841246544e-324 0x1p-1074 0x0p+0 Underflow