通过使用两个浮子进行双重分区?
-
28-09-2019 - |
题
我想使用两个浮子进行双重偏差(看来直接计算不支持双偏转)。
那可能吗?
这是我到目前为止尝试的(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;
然后结果是正确的。
解决方案
计算与浮点部分裂的计数相互量,然后使用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;
其他提示
显然,您的算术错误对您而言尚不清楚。让我拼出它。
假设双重部分有两个部分,大部分和小部分,每个部分都有大约32位精确度。 (这并不是双打的工作方式,但它将用于我们的目的。)
浮子只有一部分。
想象一下,我们一次做32位,但要使所有内容保持双打:
double divisor = whatever;
double dividend = dividendbig + dividendlittle;
double bigquotient = dividendbig / divisor;
什么是大夸大?这是双重的。因此有两个部分。 BigQuotient等于BigQuotientbig + BigQuotientlittle。继续:
double littlequotient = dividendlittle / divisor;
同样,LittleQuotient是LittleQuotientbig + LittleQuotientlittle。现在我们添加商:
double quotient = bigquotient + littlequotient;
我们如何计算?商有两个部分。商人将设置为bigquotientbig。顾问将设置为bigquotientlittle + littlequotientbig。 LittleQuotientlittle被丢弃。
现在假设您在浮标中进行。你有:
float f1 = dividendbig;
float f2 = dividendlittle;
float r1 = f1 / divisor;
好,什么是R1?这是一个浮标。因此,它只有一部分。 R1是bigquotientbig。
float r2 = f2 / divisor;
什么是R2?这是一个浮标。因此,它只有一部分。 R2是Littlequotientbig。
double result = (double)r1 + (double)r2;
您将它们添加在一起,然后获得BigQuotientbig + LittleQuotientBig。 Bigquotientlittle怎么了? 您在那里失去了32位精确度,因此,您在此过程中获得32位的无限要求也就不足为奇了。 您根本没有想出正确的算法,以近似于32位的64位算术。
为了计算 (big + little)/divisor
, ,你不能简单地做 (big / divisor) + (little / divisor)
. 。该代数规则在您时不适用 四舍五入 中 每一个 分配!
现在很清楚吗?
那可能吗?
是的,只要你:
- 接受不可避免的精确损失
- 请记住,并非所有双打首先都适合浮标
更新
阅读您的评论(双重精度是必需的)之后,我的更新答案是:
不。
那么类似的事
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%。
在评论中,您说:
当然,不应丧失精确度。这就是为什么我使用两个浮子。如果我接受丧失精度,那么我可以施放两个浮子并进行分区。
IEEE-754 single precision
值有24个重要的二进制数字。一种 double precision
值具有53个重要数字。您甚至不能将双重精度值表示为两个单个精确值而不会丢失准确性,更不用说算术了。
也就是说,是 可能的 仅使用双重和双精度扣除/加法和单个精度操作之间的转换进行正确的圆形双精度划分,但是如果您真的想正确执行此操作,那就很复杂了。您是否需要实际的IEEE-754正确的圆形,或者只是一个正确的答案,直到最后一两个位?