我想使用两个浮点数进行双重划分(看起来Direct Compute不支持双重划分)。
这可能吗?
这是我到目前为止所尝试的(c#代码,以后应该是HLSL):
int count = 7;
double value = 0.0073812398871474;
float f1 = (float)value;
float f2 = (float)((value - f1));
float r1 = f1 / count;
float r2 = f2 / count;
double result = (double)r1 + (double)r2;
0,00105446285765182(结果)
0,00105446284102106(正确的结果)
它与f1中的舍入有关。如果值是:
double value = 0.0073812344471474;
然后结果是正确的。
答案 0 :(得分:5)
使用浮点除法计算计数的倒数,然后使用Newton-Raphson倒数公式将精度提高到全双精度。
int count = 7;
double value = 0.0073812398871474;
double r = (double) (1.0f / count); // approximate reciprocal
r = r * (2.0 - count*r); // much better approximation
r = r * (2.0 - count*r); // should be full double precision by now.
double result = value * r;
答案 1 :(得分:3)
这可能吗?
是的,只要你:
阅读完评论后(需要双精度),我更新的答案是:
没有
答案 2 :(得分:3)
显然你的算术错误并不是很明显。让我拼出来。
假设一个double有两个部分,大部分和小部分,每个部分大约有32位精度。 (这不是双打的确切方式,但它可以用于我们的目的。)
一个浮点只有一个部分。
想象一下,我们一次只做32位,但保持所有内容都是双倍的:
double divisor = whatever;
double dividend = dividendbig + dividendlittle;
double bigquotient = dividendbig / divisor;
什么是大商品?这是双倍的。所以它有两个部分。 bigquotient等于bigquotientbig + bigquotientlittle。继续:
double littlequotient = dividendlittle / divisor;
再次,小商数是小商品+小商品。现在我们添加商:
double quotient = bigquotient + littlequotient;
我们如何计算?商有两部分。 quotientbig将设置为bigquotientbig。 quotientlittle将设置为bigquotientlittle + littlequotientbig。 littlequotientlittle被丢弃了。
现在假设你在花车里做。你有:
float f1 = dividendbig;
float f2 = dividendlittle;
float r1 = f1 / divisor;
好的,什么是r1?这是一个浮动。所以它只有一个部分。 r1是bigquotientbig。
float r2 = f2 / divisor;
什么是r2?这是一个浮动。所以它只有一个部分。 r2很小。
double result = (double)r1 + (double)r2;
你把它们加在一起,你得到bigquotientbig + littlequotientbig。 bigquotientlittle发生了什么变化?你已经失去了32位的精度,所以你一路上就会得到32位不准确的东西也就不足为奇了。 你没有想出用32位近似64位算术的正确算法。
为了计算(big + little)/divisor
,您不能简单地执行(big / divisor) + (little / divisor)
。在每个分区期间舍入时,该代数规则不适用!
现在清楚了吗?
答案 3 :(得分:1)
那么怎么样呢
result = value * (double)(1f / (float)count);
?
那里你只划分了两个花车。我有更多的演员而不是需要,但这是重要的概念。
编辑:
好的,所以你担心实际和圆形之间的区别,对吧?所以,一遍又一遍地做,直到你做对了!
double result = 0;
double difference = value;
double total = 0;
float f1 = 0;
while (difference != 0)
{
f1 = (float)difference;
total += f1;
difference = value - total;
result += (double)(f1 / count);
}
...但是你知道,简单的答案仍然是“不”。这仍然没有捕获所有舍入错误。根据我的测试,它最多将不准确性降低到1e-17,大约30%的时间。
答案 4 :(得分:0)
在评论中,您说:
当然不应该有任何损失 精度这就是我使用的原因 两个花车。如果我愿意接受损失 精确,然后我可以投两个 漂浮并做分工。
IEEE-754 single precision
值有24位有效二进制数字。 double precision
的值有53位有效数字。您甚至不能将双精度值表示为两个单精度值而不会损失精度,更不用说使用这种表示算术。
也就是说,可能使用双精度和单精度之间的转换,双精度减法/加法和单精度运算来进行正确舍入的双精度除法,但是如果真的那么它会非常复杂我想做对。您是否需要实际的IEEE-754正确舍入,或者只需要最后一两位的答案?