从std::round转换为int是否安全
Is it safe to cast to int from std::round?
我有一个关于std::round with signature的问题:double round (double x);
假设我有这个代码:
int i = std::round(0.9);
在这种情况下,std::round
应该返回1.00000000000
,但这与0.9999999999999
非常接近,我担心浮点错误最终会将其四舍五入。
我希望i == 1
,但这有保证吗?
std::round
函数返回一个浮点值,">从零开始舍入一半大小写"。与任何double
到int
的隐式转换一样,编译器将发出警告:
从'double'到'int'的转换,可能丢失数据
如果要返回整数值,请使用std::lround或std::lrint。
是。只要你不溢出接收类型。
您在这里没有任何顾虑:std::round(0.9)
将精确地四舍五入到1.0
,因此i == 1
是有保证的
该标准坚持使用返回的double
所假定的最接近的整数值。
请注意,对于IEEE754double
,超过2的52次方的所有值都是整数值!其推论是,您的四舍五入候选数已经为整数值,因此函数减少为no-op。因此,例如,std::round(4503599627370496.5)
将返回4503599627370496
的事实完全与4503599627370496.5
最初不能表示为double
的事实有关。
作为最后的技术要点,请注意,std::round
表现得非常好,部分原因是a.5
形式的任何数字(四舍五入中的截断点)都是并矢有理,因此可以精确地用二进制浮点表示。这就是为什么另一种方法,如添加0.5
和截断,可能会引入错误,因为如果这样做,可能会出现笑话数字。
C++标准在这方面遵循C标准。在N1570(~C11)中,round
的描述如下:
round
函数以浮点格式将其参数四舍五入到最接近的整数值,从零开始取整一半大小写,而不考虑当前的取整方向。
然而,正如Ron所指出的,像lrint
这样的函数正是您想要的。
根据cppreference:
浮动-积分转换
浮点类型的prvalue可以转换为任何整数类型。分数部分被截断,即小数部分被丢弃。如果该值不适合destination类型,行为未定义(即使在destination类型是无符号的,模运算不适用)。如果目标类型是bool,这是一个布尔转换(见下文)。
尽管这并不能证明它在所有平台上都是真的,但您可以尝试四舍五入所有可能的浮点值,看看会发生什么:
#include <cmath>
#include <iostream>
#include <limits>
int main() {
// Define the range of valid 'int' values
const float mi = std::numeric_limits<int>::min();
const float ma = std::numeric_limits<int>::max();
float maxd = -std::numeric_limits<float>::infinity();
std::size_t k = 0;
// Iterate over all float point values between 'mi' and 'ma'
for (float f = mi; f < ma; f = std::nextafter(f, ma), ++k) {
// Static cast after round
auto i = static_cast<int>(std::round(f));
// Convert back to float and check the difference
float d = std::abs(static_cast<float>(i) - f);
// Store the largest recorded difference
if (d > maxd) {
maxd = d;
}
// Print progress to the console, just to see it's not stuck
if (k % 1321 == 0) {
std::cout << k << ": " << f << " r";
}
}
std::cout << std::endl;
// Prints 0.5 for me
std::cout << maxd << std::endl;
}
如果你担心可能发生的事情确实发生了,上面的程序会打印一个大于0.5的值。
如何添加0.5,然后强制转换为int(截断)
if(x < 0) { //number is negative
return (int) x - 0.5;
} else {
return (int) x + 0.5;//number is positive
}
在您的示例中,它肯定会返回1因为1.49999999999强制转换为int是1
- 是否可以从int转换为enum类类型
- '[](std::list& list)<int>{return std::move(list)}(list)' 是否保证将 'list' 留空?
- 是否可以保证按字节的零 int 是零的表示形式?
- 是否可以将无符号 int 的最大值转换为 int 并将结果转换为 -1?
- 将uint8_t转换为已签名的 int 是否至少有时不正确?
- 判断 int 是否在 C++ 中赋值的任何优雅方法
- 从std::round转换为int是否安全
- 有没有办法检查int是否不等于数组中的所有值?(C )
- "!" "== 0"是否检查 int 是否是 0 的好做法?
- 从函数返回向量<向量<int>>是否会调用 C++11 中的任何移动构造函数
- 确定 int 是否包含特定数字的函数出现问题
- int 是否有运算符==
- 确定 int 是否不为 0,没有 if 语句
- 本地引用int是否有任何好处
- 在C++中,函数定义的int a[]和int*a是否相同
- 在C++中递增未初始化的 int 是否安全
- 将string映射到int是否可能比使用hashmap更快?
- Int a=1, a || 1是否为常量表达式
- ' int a = 0, b = a '是否有未定义的行为?
- 将本机方法定义为公共本机synchronized int doSum(int a, int b)是否正确?