我可以信任ceil()结果的实际转换吗?

时间:2011-11-02 17:26:49

标签: c++ c floating-point floating-accuracy ceil

假设我有一些代码,例如:

float a, b = ...; // both positive
int s1 = ceil(sqrt(a/b));
int s2 = ceil(sqrt(a/b)) + 0.1;

s1 != s2有可能吗?我担心的是a/b是一个完美的广场。例如,可能是a=100.0b=4.0,那么ceil的输出应该是5.00000,但如果它是4.99999呢?

类似的问题:100.0/4.0是否有可能评估说5.00001,然后ceil会将其四舍五入到6.00000

我宁愿在整数数学中这样做,但sqrt有点螺丝计划。

编辑:有关如何更好地实施此建议的建议也将受到赞赏! ab值是整数值,因此实际代码更像是:ceil(sqrt(float(a)/b))

编辑:根据levis501的回答,我想我会这样做:

float a, b = ...; // both positive
int s = sqrt(a/b);
while (s*s*b < a) ++s;

谢谢大家!

5 个答案:

答案 0 :(得分:6)

我不认为这是可能的。无论sqrt(a/b)的值如何,它产生的是我们用作的一些值N:

int s1 = ceil(N);
int s2 = ceil(N) + 0.1;

由于ceil总是产生一个整数值(尽管表示为double),我们总会有一些值X,第一个产生X.0,第二个产生X.1。转换为int将始终截断.1,因此两者都会生成X

如果X太大以至于X.1溢出了double的范围,那么似乎会有例外。我不知道这可能在哪里。除了接近0(不考虑溢出)之外,数字的平方根将始终小于输入数字。因此,在ceil(N)+0.1溢出之前,a/b中用作输入的sqrt(a/b)必须已经溢出。

答案 1 :(得分:3)

您可能想为您的案例编写一个显式函数。 e.g:

/* return the smallest positive integer whose square is at least x */
int isqrt(double x) {
  int y1 = ceil(sqrt(x));
  int y2 = y1 - 1;
  if ((y2 * y2) >= x) return y2;
  return y1;
}

这将处理比率a/b的平方根在double精度范围内的奇怪情况。

答案 2 :(得分:1)

浮点数的平等确实是一个问题,但如果我们处理整数,恕我直言。

如果您的情况为100.0/4.0,那么它应该完全评估为25.0,因为25.0可以完全表示为浮点数,与...相反25.1

答案 3 :(得分:-1)

是的,s1 != s2完全有可能。为什么这是一个问题呢? 看起来很自然s1 != (s1 + 0.1)

顺便说一句,如果您希望将5.00001四舍五入到5.00000而不是6.00000,请使用rint代替ceil


要回答实际问题(在评论中) - 您可以使用sqrt获取起点,然后使用整数算法找到正确的方格。

int min_dimension_greater_than(int items, int buckets)
{
    double target = double(items) / buckets;
    int min_square = ceil(target);
    int dim = floor(sqrt(target));
    int square = dim * dim;
    while (square < min_square) {
        seed += 1;
        square = dim * dim;
    }
    return dim;
}

是的,这可以改进很多,这只是一个快速草图。

答案 4 :(得分:-2)

s1将始终等于s2。

C和C ++标准对数学例程的准确性没有太多说明。从字面上看,标准是不可能实现的,因为C标准说sqrt(x)返回x的平方根,但是2的平方根不能用浮点精确表示。

实现具有良好性能的例程,总是返回正确的舍入结果(在舍入到最接近的模式中,这意味着结果是最接近精确结果的可表示的浮点数,并且有利于a的关系低零位)是一个棘手的研究问题。好的数学库目标精度小于1 ULP(因此返回两个最接近的可表示数字之一),可能略高于.5 ULP。 (ULP是最小精度单位,低位的值在指数字段中给定特定值。)某些数学库可能比这更糟糕。您需要询问供应商或查看文档以获取更多信息。

所以sqrt可能略有偏差。如果确切的平方根是一个整数(在整数可以在浮点中精确表示的范围内)并且库保证错误小于1 ULP,那么sqrt的结果必须完全正确,因为除了确切的结果是至少1 ULP。

类似地,如果库保证错误小于1 ULP,则ceil必须返回确切的结果,因为确切的结果是可表示的,并且任何其他结果将至少为1 ULP。另外,ceil的本质是这样的,我希望任何合理的数学库总是返回一个整数,即使库的其余部分质量不高。

对于溢出情况,如果ceil(x)超出了所有整数都可以精确表示的范围,则ceil(x)+。1比任何其他可表示的数字更接近ceil(x),因此在实现浮点标准(IEEE 754)的任何系统中,将ce添加.1到ceil(x)的舍入结果应为ceil(x)。如果您处于默认的舍入模式,即舍入到最接近的模式。可以将舍入模式更改为round-to-infinity,这可能导致ceil(x)+。1为高于ceil(x)的整数。