C 四舍五入双精度整数,以避免在后续求和时四舍五入
我如何实现这一点C 四舍五入双精度整数,以避免在后续求和时四舍五入,c,floating-point,double,ieee-754,C,Floating Point,Double,Ieee 754,我如何实现这一点 // round to the nearest double so that x + ref doesn't cause round off error double round(double x, double ref) { } 所以 double x = ....; double y = ....; double x_new = round(x, y); return x_new + y; // NO ROUND OFF! 换句话说(y+x_new)-x_new严格
// round to the nearest double so that x + ref doesn't cause round off error
double round(double x, double ref) { }
所以
double x = ....;
double y = ....;
double x_new = round(x, y);
return x_new + y; // NO ROUND OFF!
换句话说(y+x_new)-x_new严格等同于y在Python中可以直接转换为C的可能解决方案
import math
from decimal import Decimal
def round2(x, ref):
x_n, x_exp = math.frexp(x)
ref_n, ref_exp = math.frexp(ref)
assert x_exp <= ref_exp
diff_exp = ref_exp - x_exp
factor = 2. ** (53 - diff_exp)
x_new_as_int = int(round(x_n * factor))
x_new_as_norm_float = float(x_new_as_int) / factor
return math.ldexp(x_new_as_norm_float, x_exp)
x = 0.001
y = 1.0
assert (y + x) - x != y
x_new = round2(x, y)
assert (y + x_new) - x_new == y
print "x:", Decimal(x)
print "x_new:", Decimal(x_new)
print "relative difference:", (x_new/x - 1.)
导入数学
从十进制输入十进制
def第2轮(x,参考):
x_n,x_exp=math.frexp(x)
ref\u n,ref\u exp=math.frexp(ref)
断言x_exp让我们假设x
和y
都是正的
设S
为双精度和x+y
有两种情况:
- 如果
x
≤ y
,那么,S-y
由Sterbenz引理精确。因此,加法(S-y)+y
是精确的(它精确地生成S
,这是一个双精度数字)。因此,您可以为x\u new
选择S-y
。不仅y+x\u new
是精确的,而且它产生与y+x
相同的结果S
- 如果
x
y
,则根据y
有效位中设置的位数,您可能会遇到问题。例如,如果设置了y
的有效位中的最后一位,则y
的二进制位之后的二进制位中的任何数字z
都不能具有z+y
精确的属性
这个答案与你的想法有着模糊的联系。这通常不可能以你想要的方式实现。文本“到最近的双精度”表示您希望返回x
附近的x\u new
。但是,如果x
大于y
,则在x
附近的某个数字的y
的任何相加都将迫使y
的一些低位超出总和。例如,假设x
为264,y
为1。满足要求的最接近的双精度(使用IEEE-754 64位二进制)是253-1,这根本不接近2**64。@eric,这是正确的。假设x归一化指数(由frexp返回)小于或等于y/ref归一化指数,因为“双舍入”已经有了一个特定的含义,“双”用作形容词。请注意检查(y+x_new)-x_new==y
与检查x_new+y
是否准确不同。后者意味着前者,但不是必需的。示例:y=1e300,x\u new=1
(y+x_new)-x_new==1e300==y
但是添加的y+x_new
不精确。看起来此解决方案依赖于IEEE-754 64位二进制文件。C不将double
指定为。您是否正在寻找一种通用于C的解决方案?@chux它肯定应该是C99可移植的。我不知道ieee-754 64位c99 double.0B100000110001001101110100101111000110101001111100@paolo_losi我太慢了,得出的结论是我的解决方案有点不对劲(很好,你找到了一个例子)。确切地说,我想知道将我的解决方案更改为2*y-(2*y-x)
是否会使它正确(仍然假设为0)≤ <代码>x
≤ <代码>y
)。至少现在我可以试一下你的例子,如果还不能证明的话,这将是一个线索。@paolo_losi我已经修改了我的答案很多。它现在包含了一个与我先前想要的答案(0)相同的假设的明显正确的解决方案≤ <代码>x
≤ <代码>y)。在x
大于y
的情况下,可能无法提供令人满意的x\u new
,例如如果y
的有效位以设定位结束。