在 C89 中,floor() 返回双精度值。以下内容是否保证有效?

double d = floor(3.0 + 0.5);
int x = (int) d;
assert(x == 3);

我担心的是,floor 的结果可能无法在 IEEE 754 中准确表示。所以 d 得到类似 2.99999 的值,而 x 最终为 2。

要使这个问题的答案为“是”,int 范围内的所有整数都必须能够精确地表示为双精度数,并且 Floor 必须始终返回精确表示的值。

有帮助吗?

解决方案

如果您的浮点类型支持所需的尾数位的所有整数可以具有精确浮点表示。由于double使用53位为尾数,它可以精确地存储所有32位ints。毕竟,你可以只设定值尾数零指数。

其他提示

如果 Floor() 的结果不能完全表示,您期望 d 的值是多少?当然如果你有 得到 变量中浮点数的表示,那么根据定义它是完全可以表示的,不是吗?你已经 得到 代表在...

(此外,Mehrdad 的答案对于 32 位整数来说是正确的。在具有 64 位 double 的编译器中 64 位 int,当然你还有更多问题......)

编辑:也许你的意思是“floor()的理论结果,即小于或等于参数的最大整数值可能无法表示为 int”。这当然是真的。对于 int 为 32 位的系统显示这一点的简单方法:

int max = 0x7fffffff;
double number = max;
number += 10.0;
double f = floor(number);
int oops = (int) f;

我不记得当从浮点到整数的转换溢出时 C 会做什么......但这将会发生在这里。

编辑:还有其他有趣的情况需要考虑。这是一些 C# 代码和结果 - 至少我想 相似的 事情会发生在C.在 C# 中, double 被定义为 64 位,因此 long.

using System;
class Test
{
    static void Main()
    {
        FloorSameInteger(long.MaxValue/2);
        FloorSameInteger(long.MaxValue-2);
    }

    static void FloorSameInteger(long original)
    {
        double convertedToDouble = original;
        double flooredToDouble = Math.Floor(convertedToDouble);
        long flooredToLong = (long) flooredToDouble;

        Console.WriteLine("Original value: {0}", original);
        Console.WriteLine("Converted to double: {0}", convertedToDouble);
        Console.WriteLine("Floored (as double): {0}", flooredToDouble);
        Console.WriteLine("Converted back to long: {0}", flooredToLong);
        Console.WriteLine();
    }
}

结果:

原值:4611686018427387903
转换为双精度:4.61168601842739E+18
地板(双人):4.61168601842739E+18
转换回长整型:4611686018427387904

原值:9223372036854775805
转换为双精度:9.22337203685478E+18
地板(双人):9.22337203685478E+18
转换回长整型:-9223372036854775808

换句话说:

(long) floor((double) original)

并不总是与 original. 。这应该不足为奇 - long 值比 double 多(给定 NaN 值),并且大量 double 不是整数,因此我们不能期望每个 long 都能精确表示。然而,所有 32 位整数 可以表示为双打。

我觉得你有点困惑,你要问什么。 floor(3 + 0.5)是不是一个很好的例子,由于3,0.5,和它们的总和都在任何真实世界的浮点格式精确表示。 floor(0.1 + 0.9)会是一个更好的例子,这里真正的问题不是floor的结果是否准确地表示,但无论是数量的的不精确性之前的调用floor将导致从你不同的返回值所期望的,已经确切所有数字。在这种情况下,我相信答案是肯定的,但它在很大程度上取决于您的具体数字。

我邀请其他人,如果是不好的要批评这种做法,但一个可能的解决方法可能是通过(1.0+0x1p-52)或(可能使用floor会更好)调用nextafter之前,类似的事情乘以你的电话号码。这可以补偿情况在数的一个二进制地方的错误导致它的正下方,而不是正好落在一个整数值,但它不会占已积累了一些操作错误。如果你需要的数字稳定性/正确性的这个水平,你需要或者做一些深入的分析或使用任意精度或精确,数学函数库,可以正确处理您的号码。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top