在 C 中实现 ceil()

Gre*_*lin 5 c floating-point implementation ceil

我想ceil()在 中实现我自己的C。在库中搜索源代码并在此处找到,但似乎很难理解。我想要干净优雅的代码。

我也在 SO 上进行了搜索,在这里找到了一些答案。似乎没有一个答案是正确的。答案之一是:

#define CEILING_POS(X) ((X-(int)(X)) > 0 ? (int)(X+1) : (int)(X))
#define CEILING_NEG(X) ((X-(int)(X)) < 0 ? (int)(X-1) : (int)(X))
#define CEILING(X) ( ((X) > 0) ? CEILING_POS(X) : CEILING_NEG(X) )
Run Code Online (Sandbox Code Playgroud)

AFAIK,返回类型ceil()不是 int。宏在这里是类型安全的吗?此外,上述实现对于负数有效吗?

实施它的最佳方式是什么?

你能提供干净的代码吗?

Mar*_*n B 3

INT_MAX对于大于但仍可以精确表示为双精度的数字,您引用的宏肯定无法正常工作。

正确实现的唯一方法ceil()(假设您无法使用等效的汇编指令实现它)是对浮点数的二进制表示进行位旋转,就像在s_ceil.c第一个链接后面的源文件中所做的那样。要了解代码的工作原理,需要了解底层平台的浮点表示形式(该表示形式很可能是IEEE 754),但没有办法解决这个问题。

编辑:

一些复杂性s_ceil.c源于它处理的特殊情况(NaN、无穷大)以及它需要在无法假设 64 位整数类型存在的情况下完成其工作的事实。

所有位调整的基本思想是屏蔽尾数的小数位,如果数字大于零,则加 1...但是还涉及一些额外的逻辑,以确保您执行在所有情况下都是正确的事情。

ceil()这是我拼凑而成的 for floats的说明性版本。注意:这不能正确处理特殊情况,也没有经过广泛测试——所以不要实际使用它。然而,它确实有助于说明比特处理所涉及的原理。我尝试对该例程进行广泛的注释,但这些注释确实假设您了解浮点数如何以 IEEE 754 格式表示。

union float_int
{
    float f;
    int i;
};

float myceil(float x)
{
    float_int val;
    val.f=x;

    // Extract sign, exponent and mantissa
    // Bias is removed from exponent
    int sign=val.i >> 31;
    int exponent=((val.i & 0x7fffffff) >> 23) - 127;
    int mantissa=val.i & 0x7fffff;

    // Is the exponent less than zero?
    if(exponent<0) 
    {   
        // In this case, x is in the open interval (-1, 1)
        if(x<=0.0f)
            return 0.0f;
        else
            return 1.0f;
    }
    else
    {
        // Construct a bit mask that will mask off the
        // fractional part of the mantissa
        int mask=0x7fffff >> exponent;

        // Is x already an integer (i.e. are all the
        // fractional bits zero?)
        if((mantissa & mask) == 0)
            return x;
        else
        {
            // If x is positive, we need to add 1 to it
            // before clearing the fractional bits
            if(!sign)
            {
                mantissa+=1 << (23-exponent);

                // Did the mantissa overflow?
                if(mantissa & 0x800000)
                {
                    // The mantissa can only overflow if all the
                    // integer bits were previously 1 -- so we can
                    // just clear out the mantissa and increment
                    // the exponent
                    mantissa=0;
                    exponent++;
                }
            }

            // Clear the fractional bits
            mantissa&=~mask;
        }
    }

    // Put sign, exponent and mantissa together again
    val.i=(sign << 31) | ((exponent+127) << 23) | mantissa;

    return val.f;
}
Run Code Online (Sandbox Code Playgroud)