如何在 C++ 中安全地将双精度数转换为整数?

How do I safely convert a double into an integer in C++?

有没有一种方法可以将双精度数转换为整数,而不会在过程中冒任何意外错误的风险?我在 Programming - Principles and Practice Using C++(一本由 c++ 的创建者编写的书)中读到,double 不能转换为整数,但我已经对其进行了测试,它在大约 80% 的时间内正确转换。如果可能的话,完全没有风险地做到这一点的最佳方法是什么?

例如,这可以正确转换。

double bruh = 10.0;
int a = bruh;
cout << bruh << "\n";

但这不是。

double bruh = 10.9;
int a = bruh;
cout << bruh << "\n";

简而言之,它不会自动舍入,所以我认为这就是它“不安全”的原因。

不可能将所有双精度数转换为整数而不会有丢失数据的风险。

首先,如果双精度数包含小数部分 (42.9),则该小数部分将丢失。

其次,与大多数整数相比,双精度数可以容纳更大范围的值,约为 1.7e308,因此当您进入更大的值时,您根本无法将它们存储为整数。

way to convert a double into an integer without risking any undesired errors
in short, it doesn't round automatically so I think that's what constitutes it as "unsafe"

要转换为整数值:

x = round(x);

要转换为整数类型:

从像 long lround(double x); 这样的圆形函数开始。它“Returns 值最接近 x 的整数值,中间情况从零四舍五入。”

如果回合结果超出 long 范围,则会出现问题,代码可能需要先进行测试。

// Carefully form a double the is 1 more than LONG_MAX
#define LONG_MAXP1 ((LONG_MAX/2 + 1)*2.0)

long val = 0;
if (x - LONG_MAXP1 < -0.5 && x - LONG_MIN > -0.5) {
  val = lround(x);
} else {
  Handle_error();
}

详细信息:为了测试 double 是否在舍入到 long 的范围内,仔细测试端点很重要。数学上的有效范围是 (LONG_MIN-0.5 ... LONG_MAX + 0.5),但这些端点可能无法准确表示为 double。相反,代码使用附近的 LONG_MINLONG_MAXP1,它们的大小是 2 的幂并且很容易精确地表示为 double.