floor()是否返回了可以完全表示的内容?

时间:2009-01-13 18:33:27

标签: c floating-point ieee-754 c89 floor

在C89中,floor()返回一个double。以下是否可以保证有效?

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

我担心的是,地板的结果可能无法在IEEE 754中完全代表。所以d得到类似2.99999,x最终为2。

对于这个问题的答案是肯定的,int范围内的所有整数必须完全可以表示为双精度,而floor必须始终返回该精确表示的值。

3 个答案:

答案 0 :(得分:14)

如果浮点类型支持所需的尾数位,则所有整数都可以具有精确的浮点表示。由于double使用53位作为尾数,因此它可以精确地存储所有32位int。毕竟,您可以将值设置为尾数为零指数。

答案 1 :(得分:3)

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

中的表示

(另外,Mehrdad的答案对于32位整数是正确的。在64位双 64位int的编译器中,你当然会遇到更多问题......)< / p>

编辑:也许你的意思是“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
  转换为double:   4.61168601842739E + 18
地板(双层):4.61168601842739E + 18
  转换回长:   4611686018427387904个
  
  原值:9223372036854775805
  转换为double:   9.22337203685478E + 18
地板(双层):9.22337203685478E + 18
  转换回长:   -9223372036854775808

换句话说:

(long) floor((double) original)

并不总是与original相同。这不应该让人感到意外 - 有更多的长值而不是双倍(给定NaN值)并且大量的双精度不是整数,因此我们不能指望每一个长度都可以完全表示。但是,所有32位整数可表示为双精度。

答案 2 :(得分:2)

我觉得你对你想问的问题有点困惑。 floor(3 + 0.5)不是一个很好的例子,因为3,0.5及其总和都可以在任何真实的浮点格式中完全表示。 floor(0.1 + 0.9)会是一个更好的例子,这里真正的问题不是floor的结果是否完全可以表示,而是调用之前是否不精确{{1}如果所有数字都是精确的,将导致返回值与您期望的不同。在这种情况下,我认为答案是肯定的,但这在很大程度上取决于你的特定数字。

我邀请其他人批评这种方法,如果它不好,但一种可能的解决方法可能是在调用floor之前将您的数字乘以(1.0+0x1p-52)或类似的东西(可能使用floor会更好)。这可以补偿数字的最后一个二进制位置中的错误导致它恰好落在下面而不是精确地落在整数值上的情况,但是它不会解释在多个操作中累积的错误。如果您需要这种级别的数值稳定性/准确性,您需要进行深度分析或使用可以正确处理数字的任意精度或精确数学库。

相关问题