C++ 在 std::floor 之后转换为 int 是否保证正确的结果?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/605533/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 16:12:54  来源:igfitidea点击:

Does casting to an int after std::floor guarantee the right result?

c++mathfloor

提问by Jesse Beder

I'd like a floorfunction with the syntax

我想要一个floor具有语法的函数

int floor(double x);

but std::floorreturns a double. Is

std::floor返回一个double. 是

static_cast <int> (std::floor(x));

guaranteed to give me the correct integer, or could I have an off-by-one problem? It seems to work, but I'd like to know for sure.

保证给我正确的整数,或者我可能有一个一对一的问题?它似乎有效,但我想确定。

For bonus points, why the heck does std::floorreturn a doublein the first place?

对于奖励积分,为什么首先std::floor返回 a double

采纳答案by Jon Skeet

The range of double is way greater than the range of 32 or 64 bit integers, which is why std::floorreturns a double. Casting to intshould be fine so long as it's within the appropriate range - but be aware that a doublecan't represent all 64 bit integers exactly, so you may also end up with errors when you go beyond the point at which the accuracy of doubleis such that the difference between two consecutive doubles is greater than 1.

double 的范围远大于 32 或 64 位整数的范围,这就是std::floor返回 a 的原因double。铸造到int应该罚款,只要它是在适当的范围内-但要知道,一个double不能代表所有的64位整数准确,所以你也可能有错误的结束,当你超越在其精度的点double是这样的两个连续双打之间的差值大于 1。

回答by jalf

static_cast <int> (std::floor(x));

does pretty much what you want, yes. It gives you the nearest integer, rounded towards -infinity. At least as long as your input is in the range representable by ints. I'm not sure what you mean by 'adding .5 and whatnot, but it won't have the same effect

几乎可以满足您的要求,是的。它为您提供最接近的整数,四舍五入到 -infinity。至少只要您的输入在整数可表示的范围内。我不确定您所说的“添加 .5 之类的”是什么意思,但它不会产生相同的效果

And std::floor returns a double because that's the most general. Sometimes you might want to round off a float or double, but preserve the type. That is, round 1.3f to 1.0f, rather than to 1.

std::floor 返回双精度值,因为这是最通用的。有时您可能想要舍入浮点数或双精度数,但保留类型。也就是说,将 1.3f 舍入到 1.0f,而不是到 1。

That'd be hard to do if std::floor returned an int. (or at least you'd have an extra unnecessary cast in there slowing things down).

如果 std::floor 返回一个 int ,那将很难做到。(或者至少你会有一个额外的不必要的演员在那里减慢速度)。

If floor only performs the rounding itself, without changing the type, you can cast that to int if/when you need to.

如果 floor 仅执行舍入本身,而不更改类型,则可以在需要时将其转换为 int 。

Another reason is that the range of doubles is far greater than that of ints. It may not be possible to round all doubles to ints.

另一个原因是doubles的范围远大于ints的范围。可能无法将所有双精度舍入为整数。

回答by Michal Czardybon

The C++ standard says (4.9.1):

C++ 标准说(4.9.1):

"An rvalue of a floating point type can be converted to an rvalue of an integer type. The conversion truncates; that is, the fractional part is discarded. The behavior is undefined if the truncated value cannot be represented in the destination type".

“浮点类型的右值可以转换为整数类型的右值。转换会截断;也就是说,小数部分被丢弃。如果截断的值不能在目标类型中表示,则行为未定义”。

So if you are converting a double to an int, the number is within the range of int and the required rounding-up is toward zero, then it is enough to simply cast the number to int:

因此,如果您将 double 转换为 int,则该数字在 int 的范围内并且所需的四舍五入接近零,那么只需将数字转换为 int 就足够了:

(int)x;

(int)x;

回答by Anonymous

If you want to deal with various numeric conditions and want to handle different types of conversions in a controlled way, then maybe you should look at the Boost.NumericConversion. This library allows to handle weird cases (like out-of-range, rounding, ranges, etc.)

如果您想处理各种数字条件并希望以受控方式处理不同类型的转换,那么也许您应该查看Boost.NumericConversion。该库允许处理奇怪的情况(如超出范围、四舍五入、范围等)

Here is the example from the documentation:

这是文档中的示例:

#include <cassert>
#include <boost/numeric/conversion/converter.hpp>

int main() {

    typedef boost::numeric::converter<int,double> Double2Int ;

    int x = Double2Int::convert(2.0);
    assert ( x == 2 );

    int y = Double2Int()(3.14); // As a function object.
    assert ( y == 3 ) ; // The default rounding is trunc.

    try
    {
        double m = boost::numeric::bounds<double>::highest();
        int z = Double2Int::convert(m); // By default throws positive_overflow()
    }
    catch ( boost::numeric::positive_overflow const& )
    {
    }

    return 0;
}

回答by Dan Olson

Most of the standard math library uses doubles but provides float versions as well. std::floorf() is the single precision version of std::floor() if you'd prefer not to use doubles.

大多数标准数学库使用双精度数,但也提供浮点数版本。如果您不想使用双精度数,则 std::floorf() 是 std::floor() 的单精度版本。

Edit: I've removed part of my previous answer. I had stated that the floor was redundant when casting to int, but I forgot that this is only true for positive floating point numbers.

编辑:我已经删除了我以前的答案的一部分。我已经说过在转换为 int 时地板是多余的,但我忘记了这仅适用于正浮点数。