繁体   English   中英

使用两个浮点数进行双除法?

[英]double division by using two floats?

我想使用两个浮点数进行双重划分(似乎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;

那么结果是正确的。

用浮点除法计算计数的倒数,然后使用牛顿-拉夫森倒数公式将精度提高到全双精度。

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? 这是双重的。 因此,它分为两个部分。 bigquotient等于bigquotientbig + bigquotientlittle。 继续:

double littlequotient = dividendlittle / divisor;

再次,littlequotient是littlequotientbig + littlequotientlittle。 现在,我们添加商:

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是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正确舍入,还是仅需要最后一到两个正确的答案?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM