提问人:alrav 提问时间:11/16/2022 最后编辑:HolyBlackCatalrav 更新时间:11/16/2022 访问量:222
如何安全地执行从双精度到浮点的缩小转换?
How do I perform a narrowing conversion from double to float safely?
问:
当双精度缩小到浮点数时,我遇到了一些 -Wnarrowing 转换错误。我怎样才能以一种明确定义的方式做到这一点?最好使用模板中的选项,我可以切换以将行为从抛出异常切换到钳制到最接近的值或简单的截断。我正在查看转换,但似乎它只是在引擎盖下执行静态转换和比较跟进:了解 gsl::narrow 实现。我想要一些更健壮的东西,因为根据 C++ 程序员应该了解的所有常见未定义行为是什么? 如果该值在目标类型中不可表示,则为 UB。我也非常喜欢这个实现,但它也依赖于一个:是否可以优化一个 static_cast<float> from double,分配给 double?我不想为此使用boost。还有其他选择吗?如果这在 c++03 中工作是最好的,但 c++0x(实验性 c++11)也是可以接受的......如果真的需要,或者 11 个......gsl::narrow
static_cast<>
static_cast<>
因为有人问,这里有一个简单的玩具例子:
#include <iostream>
float doubleToFloat(double num) {
return static_cast<float>(num);
}
int main( int, char**){
double source = 1; // assume 1 could be any valid double value
try{
float dest = doubleToFloat(source);
std::cout << "Source: (" << source << ") Dest: (" << dest << ")" << std::endl;
}
catch( std::exception& e )
{
std::cout << "Got exception error: " << e.what() << std::endl;
}
}
我的主要兴趣是向doubleToFloat(...)添加错误处理和安全性,如果需要,还可以添加各种自定义异常。
答:
这取决于你所说的“安全”是什么意思。在大多数情况下,精度很可能会下降。是否要检测是否发生这种情况?断言,还是只是知道它并通知用户?
一种可能的解决方案是将双精度静态转换为浮点,然后返回双精度,并比较之前和之后。相等的可能性不大,但您可以断言精度的损失在您的容忍范围内。
float doubleToFloat(double a_in, bool& ar_withinSpec, double a_tolerance)
{
auto reducedPrecision = static_cast<float>(a_in);
auto roundTrip = static_cast<double>(reducedPrecision);
ar_withinSpec = (roundTrip < a_tolerance);
return reducedPrecision;
}
评论
只要浮点类型可以存储无穷大(这是极有可能的),就不会出现未定义的行为。你可以测试你是否真的想确定。std::numeric_limits<float>::has_infinity
用于静音警告,如果要检查溢出,可以执行如下操作:static_cast
template <typename T>
bool isInfinity(T f) {
return f == std::numeric_limits<T>::infinity()
|| f == -std::numeric_limits<T>::infinity();
}
float doubleToFloat(double num) {
float result = static_cast<float>(num);
if (isInfinity(result) && !isInfinity(num)) {
// overflow happened
}
return result;
}
任何未溢出的值都将完全转换为两个最接近的值之一(可能是最接近的值)。您可以使用 std::fesetround
显式设置舍入方向。double
float
评论
double
float
FLT_MAX
double
float