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。宏在这里是类型安全的吗?此外,上述实现对于负数有效吗?
实施它的最佳方式是什么?
你能提供干净的代码吗?
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)