我想实现我自己的ceil()
in C
。在库中搜索源代码并找到,但似乎很难理解。我想要干净优雅的代码。
我也在SO上搜索,找到了一些答案here https://stackoverflow.com/questions/2796639/implementation-of-ceil-function-in-c。似乎没有一个答案是正确的。答案之一是:
#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) )
AFAIK,返回类型ceil()
不是整数。宏在这里是类型安全的吗?
此外,上述实现对于负数有效吗?
实施它的最佳方式是什么?
你能提供干净的代码吗?
对于大于的数字,您引用的宏肯定无法正常工作INT_MAX
但仍然可以精确地表示为双精度数。
唯一的实现方法ceil()
正确地(假设您无法使用等效的汇编指令来实现它)是对浮点数的二进制表示进行位旋转,如在s_ceil.c
第一个链接后面的源文件。了解代码的工作原理需要了解底层平台的浮点表示——该表示很可能是IEEE 754 http://en.wikipedia.org/wiki/IEEE_floating_point——但是没有办法解决这个问题。
Edit:
中的一些复杂性s_ceil.c
源于它处理的特殊情况(NaN、无穷大)以及它需要在无法假设 64 位整数类型存在的情况下完成其工作的事实。
所有位调整的基本思想是屏蔽尾数的小数位,如果数字大于零,则加 1...但是还涉及一些额外的逻辑,以确保您执行在所有情况下都是正确的事情。
这是一个说明性版本ceil()
我拼凑而成的花车。当心:这确实not正确处理特殊情况,并且它没有经过广泛的测试——所以不要实际使用它。然而,它确实有助于说明比特处理所涉及的原理。我尝试对该例程进行广泛的注释,但这些注释确实假设您了解浮点数如何以 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;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)