ceil在c 语言中的用法,在C中实现ceil()

您将编写的任何内容都不比使用标准库实现更优雅。没有任何代码总是比优雅的代码更优雅。

除此之外,这种方法有两个主要缺陷:

如果X大于INT_MAX + 1或小于INT_MIN - 1,则宏的行为未定义。这意味着您的实现可能会为近一半的浮点数提供不正确的结果。您还将提出无效标志,与IEEE-754相反。

它得到-0,+ / - 无穷大和南错的边缘情况。事实上,唯一正确的边缘情况是+0。

您可以以类似于您尝试的方式实现ceil,如此(此实现假定IEEE-754双精度):

#include

double ceil(double x) {

// All floating-point numbers larger than 2^52 are exact integers, so we

// simply return x for those inputs. We also handle ceil(nan) = nan here.

if (isnan(x) || fabs(x) >= 0x1.0p52) return x;

// Now we know that |x| < 2^52, and therefore we can use conversion to

// long long to force truncation of x without risking undefined behavior.

const double truncation = (long long)x;

// If the truncation of x is smaller than x, then it is one less than the

// desired result. If it is greater than or equal to x, it is the result.

// Adding one cannot produce a rounding error because `truncation` is an

// integer smaller than 2^52.

const double ceiling = truncation + (truncation < x);

// Finally, we need to patch up one more thing; the standard specifies that

// ceil(-small) be -0.0, whereas we will have 0.0 right now. To handle this

// correctly, we apply the sign of x to the result.

return copysign(ceiling, x);

}像这样的东西就像你能得到的那样优雅而且仍然是正确的。

我对马丁在答案中提出的(通常是好的!)实施方案表示了一些担忧。以下是我将如何实现他的方法:

#include

#include

static inline uint64_t toRep(double x) {

uint64_t r;

memcpy(&r, &x, sizeof x);

return r;

}

static inline double fromRep(uint64_t r) {

double x;

memcpy(&x, &r, sizeof x);

return x;

}

double ceil(double x) {

const uint64_t signbitMask = UINT64_C(0x8000000000000000);

const uint64_t significandMask = UINT64_C(0x000fffffffffffff);

const uint64_t xrep = toRep(x);

const uint64_t xabs = xrep & signbitMask;

// If |x| is larger than 2^52 or x is NaN, the result is just x.

if (xabs >= toRep(0x1.0p52)) return x;

if (xabs < toRep(1.0)) {

// If x is in (1.0, 0.0], the result is copysign(0.0, x).

// We can generate this value by clearing everything except the signbit.

if (x <= 0.0) return fromRep(xrep & signbitMask);

// Otherwise x is in (0.0, 1.0), and the result is 1.0.

else return 1.0;

}

// Now we know that the exponent of x is strictly in the range [0, 51],

// which means that x contains both integral and fractional bits. We

// generate a mask covering the fractional bits.

const int exponent = xabs >> 52;

const uint64_t fractionalBits = significandMask >> exponent;

// If x is negative, we want to truncate, so we simply mask off the

// fractional bits.

if (xrep & signbitMask) return fromRep(xrep & ~fractionalBits);

// x is positive; to force rounding to go away from zero, we first *add*

// the fractionalBits to x, then truncate the result. The add may

// overflow the significand into the exponent, but this produces the

// desired result (zero significand, incremented exponent), so we just

// let it happen.

return fromRep(xrep + fractionalBits & ~fractionalBits);

}关于这种方法需要注意的一点是,它不会为非整数输入引发不精确的浮点标志。这可能与您的使用有关,也可能不是。我列出的第一个实现确实提升了标志。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值