【问题标题】:C rounding of unsigned->float conversion where src is equal distant from its rounded up or down value?无符号->浮点转换的C舍入,其中src与其向上或向下舍入的值相等?
【发布时间】:2013-12-03 21:40:47
【问题描述】:

查看 C 中从无符号到浮点到无符号的往返转换,我有点惊讶地看到无符号到浮点值的舍入如下:

0x80000080

向下舍入为 (float)0x80000000,而不是向上舍入为 (float)0x80000100。请注意,由于我们在浮点数中有 1+23 个有效尾数位可用,我们可以准确地表示任何具有最低 0xFF 位清除的无符号值。是的,这两种舍入可能性都与 0x80000080 相距 128,因此可以说这是任意选择。

但是,考虑从 0x80000000 开始的 256 位区域中的全部值范围的舍入

#include <stdio.h>

int main()
{
   unsigned i ;

   for ( i = 0 ; i < 256 ; i++ )
   {
      unsigned v = 0x80000000 + i ;

      int roundUpDiff = 256 - i ;

      float f = (float)v ;
      unsigned r = (unsigned)f ;

      printf( "0x%08X = 0x80000000 + %d = 0x80000100 - %d -> 0x%08X\n", v, i, roundUpDiff, r ) ;
   }

   return 0 ;
}

输出的一个子集是:

0x8000007C = 0x80000000 + 124 = 0x80000100 - 132 -> 0x80000000
0x8000007D = 0x80000000 + 125 = 0x80000100 - 131 -> 0x80000000
0x8000007E = 0x80000000 + 126 = 0x80000100 - 130 -> 0x80000000
0x8000007F = 0x80000000 + 127 = 0x80000100 - 129 -> 0x80000000
0x80000080 = 0x80000000 + 128 = 0x80000100 - 128 -> 0x80000000
0x80000081 = 0x80000000 + 129 = 0x80000100 - 127 -> 0x80000100
0x80000082 = 0x80000000 + 130 = 0x80000100 - 126 -> 0x80000100
0x80000083 = 0x80000000 + 131 = 0x80000100 - 125 -> 0x80000100

如果计算所有值的舍入选择的方向,我们会看到 0x80000000-0x80000080 范围内的所有值都向下舍入(即 256 个值中的 129 个向下舍入),并且所有值都向上舍入0x80000081-0x800000FF 范围内的值(即 256 个值中的 127 个向上取整)。

使用小数四舍五入的类比,如果我们四舍五入到最接近的十,这似乎是一个四舍五入的决定:

9,8,7,6 

接近十,但要四舍五入:

5,4,3,2,1,0

趋近于零?

这样的舍入模式的动机是什么(我认为这是默认的舍入模式,因为我没有明确指定)?

【问题讨论】:

标签: c floating-point rounding


【解决方案1】:

典型的 FP 舍入模式(可以控制)是四舍五入到最近,与偶数相关。
对于兼容的 C 编译器,整数舍入接近 0。另请参阅@Pascal Cuoq 评论。

[编辑] 第一篇文章是signed。每个 OP 更改为 unsigned

例如:uint32_tfloatuint32_t

8000007F 0x1.000000p+31 80000000  Nearer to lower value, round down   
80000080 0x1.000000p+31 80000000  Tie, round down as its "even"  
80000081 0x1.000002p+31 80000100  Nearer to higher value, round up   

8000017F 0x1.000002p+31 80000100  Nearer to lower value, round down  
80000180 0x1.000004p+31 80000200  Tie, round up as its "even"  
80000181 0x1.000004p+31 80000200  Nearer to higher value, round up  

在此上下文中的“偶数”表示要舍入到的 2 个选项,选择 float 的最低有效位设置为 0 的选项。


参考

C11dr 附录 F.3(规范)IEC 60559 浮点算法说

— 从整数到浮点类型的转换提供了 IEC 60559 从整数到浮点的转换。
— 从浮点类型到整数类型的转换提供了类似于 IEC 60559 的转换,但始终向零舍入。

【讨论】:

  • 浮点到整数向零舍入(“截断”),因为标准是这样说的(不是“几乎总是”)。整数到浮点舍入是实现定义的,大多数实现都将其定义为“根据 FPU 的舍入模式”。
  • @PascalCuoq:附件 F(如果支持)不要求它根据舍入模式吗?
  • @R.. C11dr F.3 1 确实说“从浮点类型到整数类型的转换提供了类似 IEC 60559 的转换,但总是向零舍入。”
  • @R.. 附件 F 中没有关于从整数到浮点数的转换。我想说的是 6.3.1.4:2 (C99) 中没有添加任何额外的约束。一个基本原理可能是,即使是在硬件中处理 IEEE 754 基本操作的处理器也可能会将整数转换为/从整数转换为软件(例如 PowerPC)。
  • @Pascal Cuoq 我的“整数舍入几乎总是向 0 舍入”源于 C99 之前的版本,它允许整数除法执行“向零截断”以外的操作。但是说“浮点到整数向零舍入”肯定是最新的并且适用于这里。因此,我对您的评论进行了编辑。
猜你喜欢
  • 2012-02-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多