简体   繁体   English

int(ceil(x))是否表现良好?

[英]Is int(ceil(x)) well-behaved?

If I have a floating point number x, which is within the range of [0, 10 6 ], is it guaranteed in Python that int(ceil(x)) will be rounded up correctly? 如果我有一个浮点数x,它在[0,10 6 ]的范围内,是否可以在Python中保证int(ceil(x))将被正确舍入?

It seems possible from what little I know that ceil may be rounded down leading to an incorrect result. 似乎有可能从我知道的很少,ceil可能会向下舍入导致不正确的结果。 Something like: x = 7.6, ceil(x)=7.999.., int(ceil(x))=7. 类似于:x = 7.6,ceil(x)= 7.999 ..,int(ceil(x))= 7。 Can that happen? 这会发生吗?

A correctly implemented ceil returns the exact mathematical value of ceil( x ), with no error. 正确实现的ceil返回ceil( x )的精确数学值,没有错误。 When IEEE 754, or any reasonable floating-point system, is in use, ceil is not subject to rounding errors. 当使用IEEE 754或任何合理的浮点系统时, ceil不会出现舍入误差。

This does not prevent adverse effects from sources other than the ceil function. 这不能防止来自ceil功能以外的其他来源的不利影响。 For example, ceil(1.000000000000000000000000000000001) will return 1 because 1.000000000000000000000000000000001 is converted to a floating-point value before ceil is called, and that conversion rounds its result. 例如, ceil(1.000000000000000000000000000000001)将返回1,因为1.000000000000000000000000000000001在调用ceil之前转换为浮点值,并且该转换将其结果舍入。 Similarly, a conversion from double to float followed by a call to ceil may yield a value that is not the ceiling of the original double value. 类似地,从double转换为float然后调用ceil可能会产生一个不是原始double值的上限的值。

The conversion of the result of ceil to int of course relies on the range of int . ceil的结果转换为int当然依赖于int的范围。 As long as the value is in range, the conversion should not change the value. 只要值在范围内,转换就不应更改该值。

Python's guarantee about the floating-point format for float isn't very strict. Python对float的浮点格式的保证不是很严格。 I think all it says is that it uses double, and in the case of CPython that's whatever the C compiler calls double . 我认为所有它都说它使用了double,而在CPython的情况下,它就是C编译器调用的double

For numbers up to a million you're fine. 对于高达一百万的数字,你很好。 No floating-point format in practical use loses precision for integers that small. 实际使用中没有浮点格式会丢失小的整数精度。 The C standard requires that double is OK up to 10 decimal digits. C标准要求double可以达到10位小数。

What you've probably observed is that due to floating-point rounding int(sum([1.1] * 10)) is 10, not 11. That's because sum([1.1] * 10) is 10.999999999999998 , not 11.0 . 你可能观察到的是由于浮点舍入int(sum([1.1] * 10))是10,而不是11.那是因为sum([1.1] * 10)10.999999999999998 ,而不是11.0

The result of ceil is always exactly an integer, so it will never be rounded down by int (or if you like it will be rounded down, but doing so doesn't change it's value!) ceil的结果总是一个整数,因此它永远不会被int向下舍入(或者如果你喜欢它将向下舍入,但这样做不会改变它的值!)

If you want information about python's float you should check the sys.float_info function. 如果您需要有关python float信息,您应该检查sys.float_info函数。 In particular its documentation makes it quite clear the python float s act exactly like C float / double s and provide the same guarantees. 特别是它的文档很清楚python float的行为与C float / double s完全相同,并提供相同的保证。 In fact it links to this part of C's standard. 实际上它链接到C标准的这一部分。

So python's guarantees are the same as C's double. 因此python的保证与C的双重保证相同。 If an integer can be represented exactly as float then int(the_float) will return the correct integer. 如果一个整数可以完全表示为float,那么int(the_float)将返回正确的整数。 The problem is that for big enough float s not all integers can be represented exactly. 问题是,对于足够大的float并非所有整数都可以精确表示。

Rob's example: 罗伯的例子:

int(math.ceil(18014398509481985.5)) => 18014398509481984

Is not a failure of int or ceil , but simply the fact that 18014398509481985.5 can not be represented exactly: 不是 intceil的失败,而只是18014398509481985.5 无法准确表示的事实:

>>> 18014398509481985.5
1.8014398509481984e+16

In summary: if the ceiling of x can be represented exactly then int(ceil(x)) will return the correct integer. 总结:如果x的上限可以精确表示,那么int(ceil(x)) 返回正确的整数。 Otherwise int(x) will return the integer returned by ceil(x) which need not be the "mathematical ceiling of x ". 否则int(x)将返回ceil(x)返回的整数,该整数不必是“ x数学上限”。

Currently, almost all computers conform to IEEE 754 and so you can be sure that int(ceil(x)) returns the correct result according to the standard. 目前,几乎所有计算机都符合IEEE 754,因此您可以确保int(ceil(x))根据标准返回正确的结果。

In embedded systems this might not be true but I'm not sure that python can even run on not-IEEE 754 compliant architectures. 在嵌入式系统中,这可能不是真的,但我不确定python甚至可以在不符合IEEE 754标准的架构上运行。


If you do not trust what we can say you can always try to read the source code of PyLong_FromDouble in Objects/longobject.c : 如果你不相信我们可以说的话,你总是可以尝试在Objects/longobject.c阅读PyLong_FromDouble的源代码:

PyObject *
PyLong_FromDouble(double dval)
{
    PyLongObject *v;
    double frac;
    int i, ndig, expo, neg;
    neg = 0;
    if (Py_IS_INFINITY(dval)) {
        PyErr_SetString(PyExc_OverflowError,
                        "cannot convert float infinity to integer");
        return NULL;
    }
    if (Py_IS_NAN(dval)) {
        PyErr_SetString(PyExc_ValueError,
                        "cannot convert float NaN to integer");
        return NULL;
    }
    if (dval < 0.0) {
        neg = 1;
        dval = -dval;
    }
    frac = frexp(dval, &expo); /* dval = frac*2**expo; 0.0 <= frac < 1.0 */
    if (expo <= 0)
        return PyLong_FromLong(0L);
    ndig = (expo-1) / PyLong_SHIFT + 1; /* Number of 'digits' in result */
    v = _PyLong_New(ndig);
    if (v == NULL)
        return NULL;
    frac = ldexp(frac, (expo-1) % PyLong_SHIFT + 1);
    for (i = ndig; --i >= 0; ) {
        digit bits = (digit)frac;
        v->ob_digit[i] = bits;
        frac = frac - (double)bits;
        frac = ldexp(frac, PyLong_SHIFT);
    }
    if (neg)
        Py_SIZE(v) = -(Py_SIZE(v));
    return (PyObject *)v;
}

the code isn't a simple cast because long integers aren't represented as C doubles. 代码不是简单的强制转换,因为长整数不表示为C双精度。 And it seems like even in python2 there's no PyInt_FromDouble . 似乎即使在python2中也没有PyInt_FromDouble

It's often the case that there's rounding errors in floating point numbers, but that's only because not all numbers that are reprensentable in decimal are perfectly represented in binary. 通常情况是浮点数存在舍入误差,但这只是因为并非所有以十进制表示的数字都以二进制形式完美表示。 Those numbers that can be represented exactly won't have any rounding applied. 那些可以准确表示的数字将不会应用任何舍入。 That is the case for integer values up to 2**53, so with only 6 digits you will be safe. 对于最大为2 ** 53的整数值就是这种情况,所以只有6位数就可以安全。

The lowest positive integer value that can't be represented exactly in a float is 9007199254740993. 无法在float精确表示的最小正整数值是9007199254740993。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM