对于某个整数类型,即使浮点数值远超出整数可表示范围,我该如何找到最靠近某个浮点数值的整数值?
更准确地说:
设 F 是一个浮点类型(可能是 float、double 或 long double)。设 I 是一个整数类型。
假设 F 和 I 都有 std::numeric_limits<> 的有效特化。
给定一个可表示的 F 值,并且只使用 C++03,我该如何找到最接近的可表示 I 值?
我需要一个纯粹、高效和线程安全的解决方案,并且假设平台除了 C++03 保证的东西之外什么也不知道。
如果不存在这样的解决方案,是否可以使用 C99/C++11 的新功能找到一个解决方案?
使用 C99 的 lround() 似乎存在问题,因为它报告定义域错误的方式比较复杂。这些定义域错误能以一种便携和线程安全的方式捕获吗?
注:我知道 Boost 可能通过其 boost::numerics::converter<> 模板提供解决方案,但由于其高度复杂和冗长,我无法从中提取要点,因此我无法确定他们的解决方案是否假定了 C++03 之外的内容。
以下天真的方法失败了,因为当 f 的整数部分不是 I 的可表示值时,I(f) 的结果在 C++03 中是未定义的。
更准确地说:
设 F 是一个浮点类型(可能是 float、double 或 long double)。设 I 是一个整数类型。
假设 F 和 I 都有 std::numeric_limits<> 的有效特化。
给定一个可表示的 F 值,并且只使用 C++03,我该如何找到最接近的可表示 I 值?
我需要一个纯粹、高效和线程安全的解决方案,并且假设平台除了 C++03 保证的东西之外什么也不知道。
如果不存在这样的解决方案,是否可以使用 C99/C++11 的新功能找到一个解决方案?
使用 C99 的 lround() 似乎存在问题,因为它报告定义域错误的方式比较复杂。这些定义域错误能以一种便携和线程安全的方式捕获吗?
注:我知道 Boost 可能通过其 boost::numerics::converter<> 模板提供解决方案,但由于其高度复杂和冗长,我无法从中提取要点,因此我无法确定他们的解决方案是否假定了 C++03 之外的内容。
以下天真的方法失败了,因为当 f 的整数部分不是 I 的可表示值时,I(f) 的结果在 C++03 中是未定义的。
template<class I, class F> I closest_int(F f)
{
return I(f);
}
考虑以下方法:
template<class I, class F> I closest_int(F f)
{
if (f < std::numeric_limits<I>::min()) return std::numeric_limits<I>::min();
if (std::numeric_limits<I>::max() < f) return std::numeric_limits<I>::max();
return I(f);
}
由于F(std::numeric_limits<I>::min())
和F(std::numeric_limits<I>::max())
的整数部分可能仍然无法在I
中表示,因此这也会失败。
最后考虑这第三种方法,它也会失败:
template<class I, class F> I closest_int(F f)
{
if (f <= std::numeric_limits<I>::min()) return std::numeric_limits<I>::min();
if (std::numeric_limits<I>::max() <= f) return std::numeric_limits<I>::max();
return I(f);
}
这次 I(f)
总是有一个明确定义的结果,然而,由于 F(std::numeric_limits<I>::max())
可能比 std::numeric_limits<I>::max()
小得多,因此可能会返回一个整数值低于 std::numeric_limits<I>::max()
的浮点值的 std::numeric_limits<I>::max()
。
请注意,所有的麻烦都是因为不确定转换 F(i)
是否向最接近的可表示浮点值上舍入或下舍入。
以下是C++03的相关章节(4.9 浮点-整数转换):
整数类型或枚举类型的右值可以转换为浮点类型的右值。如果可能的话结果是精确的。否则,它是实现定义的选择,要么是下一个更低的可表示值,要么是更高的可表示值。
+.5
可以很容易地插入:f += (f >= 0) ? +0.5 : -0.5;
。 - Alexey Frunze