我试图计算给定的双精度和下一个可表示的双精度之间的差异(或最小的双精度加到给定的数字改变值)
#include <stdio.h>
#include <math.h>
double f1(double a)
{
double diff=1.0,num=fabs(a);
while(num+(diff/2.0)>num )
{
diff/=2.0 ;
}
while(num+(diff*2.0)==num)
{
diff*=2.0 ;
}
return diff ;
}
double f2(double a)
{
int e=log2(fabs(a)) ;
double diff=pow(2,-52+e) ;
return diff ;
}
int main()
{
double num ;
//printf("Enter number:") ; scanf("%le",&num) ;
double diff=nextafter(num,INFINITY)-num ;
printf("f1=%len",f1(num)) ;
printf("f2=%len",f2(num)) ;
printf("difference=%len",diff) ;
if(num+f1(num)/2.0==num) printf("Equal1n") ;
if(num+f2(num)/2.0==num) printf("Equal2n") ;
return 0;
}`
似乎我的f2()函数返回的值等于我使用nextafter()函数计算的差值。f1()函数有时
返回值等于f2(),有时返回值小于f2()的2倍。
但是检查&;if&;条件显示f1()返回的值是两个连续的双精度数之间的实际差值,因为num+f1(num)/2.0==num和num+f2(num)/2.0!=num.
那么为什么有时(例如num=199.23999) f1()!=f2()?我做错了什么?
f1
没有发现a与下一个可表示的数之间的差异(在更大的方向上)。它找到两个x的最小幂,使得|a|和x的浮点相加不会产生|a|。
如果a'是a之后的下一个可表示的数,则a'-a是它们之间的差值,将a'-a加上a'得到a'。但这并不意味着将(a' - a)/2加到a'不会产生a'。是否使用取决于舍入。
在实数算术中,(a' - a)/2与a的和是a与a'之间的中点。默认的舍入规则是向最近的可表示值舍入,当存在平局时,向最近的有效位数为偶数的低位数的可表示值舍入。
考虑三个连续的可表示数1+0•2- 52, 1+1•2- 52和1+2•2- 52。当2−53与1+0•2−52相加时,得到的实数算术和为1+0.5•2−52,最接近的两个可表示值为1+0•2−52和1+1•2−52。其中,前者有一个偶数低位数,因此浮点加法产生它作为结果。当2−53与1+1•2−52相加时,得到的实数算术和为1+1.5•2−52,最接近的两个可表示值为1+1•2−52和1+2•2−52。其中,后者有一个偶数低位数,因此浮点加法将其作为结果。
这意味着对于输入1+0•2- 52,f1
产生2- 52,因为将2- 52与1+0•2- 52相加产生1+1•2- 52,而将2- 53相加则不会产生。对于输入1+1•2−52,f1
产生2−53,因为加2−53产生1+2•2−52(但加2−54则不会)。