按位随机舍入

如何解决按位随机舍入

我有一段 C 代码,它将 binary64 值四舍五入到 binary32。问题是我不太完全理解代码。我知道它直接对浮点数的位进行运算,但我无法理解发生了什么。你能和我分享一些见解吗?

float function(double x){
  uint64_t temp = *(uint64_t*)&x;
  uint32_t r = (rand() * (0xFFFFFFFF/RAND_MAX)) % 0x1FFFFFFF;
  temp += r;
  temp = temp & 0xFFFFFFFFE0000000;

  return (float)*(double *)&temp;
}

位掩码代表什么? (我的直觉告诉我这与指数和尾数如何以二进制格式表示有关,但我无法将其可视化)
为什么随机变量 r 是这样计算的?
通过代码进行交互会是什么样子?

解决方法

uint64_t temp = (uint64_t)&x;

这是获取表示 double x 的位的错误尝试。这很糟糕,因为它违反了 C 的别名规则 (C 2018 6.5 7)。正确的代码应该是 uint64_t temp; memcpy(&temp,&x,sizeof temp);uint64_t temp = (union { double d; uint64_t u; }) { x } .d;。前者将 x 的字节复制到 temp 中,后者使用复合字面量来创建一个临时对象,该对象是一个联合,用于重新解释位。 C 标准支持这两者。

uint32_t r = (rand() * (0xFFFFFFFF/RAND_MAX)) % 0x1FFFFFFF;

* (0xFFFFFFFF/RAND_MAX)) 尝试将 rand 的结果缩放到区间 [0,FFFFFFFF16]。这样做可能不完美。然后 % 0x1FFFFFFF 将其减少到区间 [0,1FFFFFFF16)。请注意收尾 )] - 这是一个不包括 1FFFFFFF16 的半开区间。这里有一些问题:

  • 这可能是一个错字; & 0x1FFFFFFF 会干净地提取低 29 位,在完全闭合的区间 [0,1FFFFFFF16] 中产生结果。使用 % 会产生不同的结果,没有明显的数学目的,并且会强制进行耗时的除法。
  • 使用 %&,没有明显的理由首先缩放到 FFFFFFFF16;一个人可能会直接到达所需的最后间隔。
  • 这只会产生积极的结果;这个数字只会在数量上增加或不变,永远不会减少。这可能是需要的,但不清楚为什么。缺乏这方面和其他方面的文档表明代码质量不足。

temp += r;

这将随机数添加到 double 的低位。有时,它会导致高位进位。 (如果高位全为1,这也可以进位到指数字段。)

temp = temp & 0xFFFFFFFFE0000000;

这会清除低 29 位。在通常用于 floatdouble 的 IEEE-754 binary32 和 binary64 格式中,float 有效位有 24 位(其中 23 位编码在主要有效位字段中),而 double }} 有效位有 53 位(在主有效位字段中编码 52 位),因此差值为 29。因此,清除 double 编码中的低 29 位将产生一个可以精确表示为 {{1 }},如果指数在 float 范围内。

清除这些位的目的可能是防止在转换为 float 期间进行第二次向上舍入,如下所示。上一行中的加法 float 可能导致有效数的高位进位,因此其意图很可能是确保数字只增加一个单位,而不是两个单位。

temp += r;

与上面的初始行一样,这是将这些位重新解释为 return (float)*(double *)&temp; 的错误尝试。 (之后它被强制转换为 double,这对于标准 C 来说是不必要的,因为 float 语句的操作数会自动转换为函数的返回类型,但是,如果使用严格的代码检查,它可以消除有关缩小转换的警告。)正确的代码应该是 returnmemcpy(&x,&temp,sizeof x); return x;

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?