比较浮点和积分的符合标准的方法
Standards compliant way to compare float to integral?
假设我有两个对象i
和f
,它们的类型分别为I
和F
。我知道std::is_integral<I>::value
是真的,std::is_floating_point<F>::value
是真的。
是否有完全符合标准的方法来确定i
的值是否小于f
的值?注意强调"完全符合标准",对于这个问题,我只对有C++标准保证支持的答案感兴趣。
琐碎的实现i < I(f)
不起作用,因为f
的值可能不适合i
。琐碎的实现F(i) < f
也不起作用,因为f
的精度可能不足以表示i
,导致i
四舍五入到等于f
的值(如果您有IEEE754浮点,16777219 < 16777220.f
将失败)。
但真正的困境来了:如果你想使用std::numeric_limits::max
来缓解这些问题,那就回到比较浮点和整数的原始问题吧!这是因为std::numeric_limits::max
的类型等于原始类型。
-
如果
f
在I
的范围之外,您可以通过其符号来判断结果。 -
如果
f
在I
的范围内,但太大而没有小数部分,则将其作为整数进行比较。 -
否则,将
i
强制转换为F
是安全的,因为四舍五入不会更改比较结果:f
已经小于I
中任何将被四舍五舍五入的值。
。
template< typename I, typename F >
std::enable_if_t< std::is_integral_v< I > && std::is_floating_point_v< F >,
bool > less( I i, F f ) {
// Return early for operands of different signs.
if ( i < 0 != f < 0 ) return i < 0;
bool rev = i >= 0;
if ( rev ) {
f = - f; // Make both operands non-positive.
i = - i; // (Negativity avoids integer overflow here.)
}
if ( f < /* (F) */ std::numeric_limits<I>::min() ) {
// |i| < |f| because f is outside the range of I.
return rev;
}
if ( f * std::numeric_limits<F>::epsilon() <= -1 ) {
// f must be an integer (in I) because of limited precision in F.
I fi = f;
return rev? fi < i : i < fi;
}
// |f| has better than integer precision.
// If (F) |i| loses precision, it will still be greater than |f|.
return rev? f < i : i < f;
}
演示:http://coliru.stacked-crooked.com/a/b5c4bea14bc09ee7
我会这样做:
我认为f是有限的,无穷大和NaN的情况将在其他地方处理。
-
比较f和f(i),如果不相等,则完成,f和i要么<或>
-
如果相等,则比较I(f)和I
唯一的假设是:
-
如果有一个浮点值恰好为i,则F(i)给出该值
-
如果存在一个与f值完全相同的整数,则I(f)给出该值
-
函数F和I 的单调性
编辑
更明确地说,上面的技巧是用于编写比较函数,而不仅仅是测试等式。。。
floatType F(intType i);
intType I(floatType f);
int cmpfi(floatType f,intType i)
{
assert(isfinite(f));
if(f < F(i)) return -1;
if(f == F(i))
{
if( I(f) < i ) return -1;
return I(f) > i;
}
return 1;
}
由您将此草案转换为可以处理几种不同floatType/intType 的C++代码
- 没有取消引用/解包对象的标准方法?
- 是否有一种标准方法来计算两个 asctime() 值之间的天数
- 导入模块的标准方法
- 有没有一种标准方法可以在C++中获取第 n 个"下一个"浮点值
- C++ 捕获异常后进行清理的标准方法是什么?
- memcpy 是将浮子打包到 uint32 中的标准方法吗?
- 读取二进制文件的惯用C++17标准方法是什么
- 在 c++ 中创建 dll 并在 delphi 中调用的标准方法
- 在 NTL 中构造多项式的标准方法是什么?
- C 是否具有对两个STD :: sets,vectors等进行三角比较的标准方法
- 获取非专用标准::矢量容器的标准方法<bool>
- 将结构传递到头文件的标准方法
- C 11中的标准方法是什么,可以访问std :: vector中元素n的指针
- 组合来自多个线程的数据的标准方法?
- 标准::字符串::空的未定义符号错误;Mac OS High Sierra 上的 c++ 标准方法链接错误
- 在C++中初始化布尔向量的标准方法是什么
- 在C 中对二进制对象进行编码/解码的标准方法
- 有没有一种标准方法来确保一段代码在全局范围内执行
- 处理对存储在私有映射中的值的封装访问的标准方法,而不破坏C++中的抽象
- 是否有一种替换C风格的Bool数组的标准方法