代码之家  ›  专栏  ›  技术社区  ›  testalino

用两个浮点数来除法?

  •  0
  • testalino  · 技术社区  · 14 年前

    我想用两个浮点数做一个双除法(看来直接计算不支持双除法)。

    有可能吗?

    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;
    

    5 回复  |  直到 12 年前
        1
  •  5
  •   Axn    14 年前

    用浮点除法计算计数倒数,然后用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;
    
        2
  •  3
  •   Eric Lippert    14 年前

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

    假设一个double有两个部分,大部分和小部分,每个部分大约有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;
    

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

    float f1 = dividendbig;
    float f2 = dividendlittle;
    float r1 = f1 / divisor;
    

    好的,什么是r1?这是一个浮子。所以它只有一部分。r1是大商。

    float r2 = f2 / divisor;
    

    什么是r2?这是一个浮子。所以它只有一部分。r2是小商大。

    double result = (double)r1 + (double)r2;
    

    把它们加在一起,就得到大商大+小商大。 大商小怎么了? 你已经失去了32位的精度,所以你一路上得到32位的精度是不足为奇的。 在32位的64位算术中,你还没有想出正确的算法。

    为了计算 (big + little)/divisor ,你不能简单地 (big / divisor) + (little / divisor) . 当你是 舍入 在期间 每一个

    现在明白了吗?

        3
  •  3
  •   Daniel Daranas    14 年前

    是的,只要你:

    • 记住,不是所有的双打都能在第一时间进入花车

    在阅读了您的评论(要求双精度)后,我更新的答案是:

    不。

        4
  •  1
  •   Naelin    14 年前

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

        5
  •  0
  •   Stephen Canon    14 年前

    当然不应该有任何损失 精确的。这就是为什么我用 精确地说,然后我可以投两个 漂浮并做除法。

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

    也就是说,是的 可能的