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

C# 使用两个浮点数进行双除法?,c#,floating-point,directx-11,compute-shader,C#,Floating Point,Directx 11,Compute Shader,我想用两个浮点数做一个双除法,因为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

我想用两个浮点数做一个双除法,因为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;
000105446285765182结果

000105446284102106正确结果

这与f1中的舍入有关。如果值为:

 double value = 0.0073812344471474;
那么结果是正确的

可能吗

是的,只要你:

接受不可避免的精度损失 请记住,并不是所有的双人花车都适合放在首位 使现代化 在阅读了您的评论后,双精度是一项要求,我的最新答案是:


没有。

那么像这样的东西怎么样

结果=值*double1f/浮点数; ?

这里你只划分了两个浮动。我有比需要更多的演员,但重要的是这个概念

编辑: 好的,所以你担心实际值和四舍五入值之间的差异,对吗?所以只要反复做,直到你做对为止

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%的时间。

显然,您的算术错误并不是很清楚。让我把它说清楚

假设一个双精度计数器有两个部分,大部分和小部分,每个部分的精度大约为32位。这并不完全是双打的工作方式,但对我们的目的来说,它将起作用

浮子只有一部分

想象一下,我们一次执行32位,但将所有内容保持在双倍:

double divisor = whatever;
double dividend = dividendbig + dividendlittle;
double bigquotient = dividendbig / divisor;
什么是大商?是双人房。所以它有两个部分。大商等于大商大+大商小。继续:

double littlequotient = dividendlittle / divisor;
同样,littlequotient是littlequotientbig+littlequotientlittle。现在我们加上商:

double quotient = bigquotient + littlequotient;
我们如何计算呢?商有两部分。商big将设置为bigquotientbig。商Little将设置为bigquotientlittle+littlequotientbig。小商小商被丢弃

现在假设你在花车里做。你有:

float f1 = dividendbig;
float f2 = dividendlittle;
float r1 = f1 / divisor;
好的,r1是什么?这是一个浮子。所以它只有一部分。r1是大商

float r2 = f2 / divisor;
double result = (double)r1 + (double)r2;
什么是r2?这是一个浮子。所以它只有一部分。r2有点大

float r2 = f2 / divisor;
double result = (double)r1 + (double)r2;
你把它们加在一起,得到大商big+小商big。大商利特尔怎么了?你已经失去了32位的精度,所以在这一过程中,你会得到32位的精度,这也就不足为奇了。您还没有找到用32位近似64位算术的正确算法

为了计算大+小/除数,不能简单地计算大/除数+小/除数。当你在每一次除法中四舍五入时,代数规则并不适用


现在清楚了吗?

使用浮点除法计算计数的倒数,然后使用牛顿-拉斐逊倒数公式将精度提高到全倍

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;
在评论中,你说:


当然不应该有任何损失 精确性。这就是为什么我使用 两辆彩车。如果我愿意接受你的损失 精确,然后我可以投两个 浮动并进行除法

IEEE-754单精度值有24个有效二进制数字。双精度值有53个有效数字。您甚至不能将双精度值表示为两个单精度值而不损失精度,更不用说使用这种表示进行算术了


这就是说,只使用双精度和单精度、双精度减法/加法和单精度运算之间的转换就可以进行正确的四舍五入双精度除法,但如果您真的想正确地进行,这是相当复杂的。您需要实际的IEEE-754正确舍入,还是只需要最后一位或两位的正确答案?

如果计数是二的幂,则精度可能会提高。@Justin有趣。这其实是真的。为什么?不幸的是,计数并不总是2的幂。如果你没有双除法,你有双乘法吗?@testalino:浮点像分数*2^指数一样存储,所以当你执行2的幂除法时,它通常可以调整指数而不损失任何精度。这只会提高r1和r2的精度,而不是原来的f1和f2,它们已经被四舍五入以适应浮点。@Naelin是的,当然不应该有任何精度损失。这就是我使用两个浮动的原因。如果我愿意接受精度损失,那么我可以直接使用两个浮点并进行除法。@testalino:float是一种舍入类型,特别是IEEE754类型。NET中唯一的十进制非舍入类型是decimal。我知道,我只想要一个精度为双精度的除法,使用浮点数。我不想要绝对精度GPU没有分贝这和值*1.0/计数双精度的结果不一样。你是对的;那只是碰巧发生在我身上
使用我测试的内容。我真傻,一路上都很清楚。我的问题中甚至提到了这一点。我想知道怎么做,否则我就不会问这个问题了。我没有问为什么我的尝试没有成功,因为我已经知道了原因。@testalino:你说问题在于f1计算中的舍入。这不是问题所在。问题是r1计算中的舍入。这就是我要指出的。我可能永远都不需要完全的双精度。不过,浮动绝对不够好。到目前为止,我已经标出了一个有效的答案。是的,如果你不需要正确的四舍五入,这是非常正确的答案。尽管您可能只需要一个细化步骤就可以成功。