int到float转换的精度损失

时间:2018-09-30 22:57:21

标签: c++ floating-point type-conversion

在C ++中,如果I的范围是F,则将类型static_cast<I>(static_cast<F>(i)) == i的整数值转换为浮点类型I是准确的-与F一样。 static_cast<F>(i)的整数值范围的一部分。

是否可以(如果使用的话)如何计算template <class F, class I> bool is_cast_safe(I value) { return std::abs(alue) < std::numeric_limits<F>::digits; } std::cout << is_cast_safe<float>(4) << std::endl; // true std::cout << is_cast_safe<float>(0x1000001) << std::endl; // false 的精度损失(不使用范围更广的其他浮点类型)?

首先,我尝试编写一个函数,该函数将在转换是否安全(安全,即不损失精度)的情况下返回,但是我必须承认我不太确定其正确性。

{{1}}

谢谢。

2 个答案:

答案 0 :(得分:1)

is_cast_safe可以通过以下方式实现:

static const F One = 1;
F ULP = std::scalbn(One, std::ilogb(value) - std::numeric_limits<F>::digits + 1);
I U = std::max(ULP, One);
return value % U; 

这会将ULP转换为value的结果中,将F设置为最低位数的值。 logbf返回最高位的位置(作为浮点基数的指数),并减去位数后的一位将调整为最低位。然后scalbn为我们提供该头寸的值,即ULP。

然后value可以准确地用F表示,并且前提是它是ULP的倍数。为了测试这一点,我们将ULP转换为I(如果小于1,则替换为1),然后将value的其余部分除以ULP(或1)。

此外,如果担心到F的转换可能溢出,也可以插入代码来处理。

计算更改的实际金额比较麻烦。到浮点数的转换可以向上或向下取整,并且选择的规则是实现定义的,尽管最常见的舍入关系为偶数。因此,无法根据我们在numeric_limits中给出的浮点属性来计算实际的变化。它必须涉及执行转换并以浮点数进行一些工作。绝对可以做到这一点,但这很麻烦。我认为一种可行的方法是:

  • 假设value为非负数。 (负值可以类似地处理,但为简单起见,现在省略。)
  • 首先,测试转换为F时是否溢出。这本身很棘手,因为如果值太大,则行为是不确定的。 this answer中提出了一些类似的考虑,以解决有关从浮点到整数(在C中)安全转换的问题。
  • 如果该值没有溢出,则将其转换。令结果为x。将x除以浮点基数r,得到y。如果y不是整数(可以使用fmodtrunc测试),则转换是准确的。
  • 否则,将y转换为I,生成z。这是安全的,因为y小于原始的value,因此它必须适合I
  • 然后,由于转换导致的错误是(z-value/r)*r + value%r

答案 1 :(得分:0)

I loss = abs(static_cast<I>(static_cast<F>(i))-i)应该可以完成这项工作。唯一的例外是i的大小很大,因此static_cast<F>(i)会生成超出范围的F

(我想这里I abs(I)可用)