我试图计算给定的double和下一个可表示的double之间的差异(或者最小的double数加上给定的数字会改变值)
#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=%le\n",f1(num)) ;
printf("f2=%le\n",f2(num)) ;
printf("difference=%le\n",diff) ;
if(num+f1(num)/2.0==num) printf("Equal1\n") ;
if(num+f2(num)/2.0==num) printf("Equal2\n") ;
return 0;
}`
似乎我的f2()函数返回的值等于我使用nextafter()函数计算的差值。F1()函数有时
返回值等于f2(),有时返回值小于f2()的2倍。
但是检查“if”条件会发现f1()返回的值是两个连续double之间的实际差值,因为num+f1(num)/2.0==num和num+f2(num)/2.0!=num。
那么为什么有时候(例如num=199.23999)f1()!=f2()?我做错了什么?
1条答案
按热度按时间kokeuurv1#
f1
不查找 a 与下一个可表示数之间的差值(在更大幅度的方向上)。它查找2 x 的最小幂,使得|a|而 x 不会产生|a|.如果 a'是 a 之后的下一个可表示数,那么 *a *'-a 就是它们之间的差,并且将 *a *'-a 加到 a 上会产生 *a *'。但是这并不意味着将(*a *'-a)/2加到 a 上不会产生 *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不产生1 + 1·2− 52;对于输入1+1·2−52,f1
产生2−53,因为2−53加1+2·2−52(而2− 54加1 + 2·2−54不产生1)。