是否存在可以在IEEE 754 half-precision数字上执行计算或将它们转换为双精度和从双精度转换的Java库?
这些方法中的任何一种都是合适的:
-
将数字保持为半精度格式,并使用整数运算和bit-twiddling计算(如MicroFloat用于单精度和双精度)
-
以单精度或双精度执行所有计算,转换为半精度进行传输(在这种情况下,我需要的是经过良好测试的转换函数 . )
Edit :转换需要100%准确 - 输入文件中有大量的NaN,无穷大和次正规 .
相关问题,但对于JavaScript:Decompressing Half Precision Floats in Javascript
5 回答
我创建了一个名为HalfPrecisionFloat的java类,它使用x4u的解决方案 . 该类具有便捷方法和错误检查 . 它更进一步,有从2字节半精度值返回Double和Float的方法 .
希望这会对某人有所帮助 .
==>
这是单元测试
我对小正浮点数感兴趣,所以我使用 12 bits mantissa, no sign bit, and 4 bits exponent, with bias 15 构建了这个变体,这样它可以表示0到1.00之间的数字(独占)非常好 . 它在尾数额外有2位分辨率,但是相同的指数低 .
测试给出:
法线:
对于次正常测试:
您可以使用
Float.intBitsToFloat()
和Float.floatToIntBits()
将它们转换为原始浮点值和从原始浮点值转换它们 . 如果你可以使用截断的精度(而不是舍入),那么转换应该可以通过几个位移来实现 .我现在已经付出了更多的努力,结果并没有我在开始时预期的那么简单 . 这个版本现在在我能想象的每个方面进行测试和验证,我非常有信心它可以为所有可能的输入值生成精确的结果 . 它支持任意方向的精确舍入和次正规转换 .
与本书相比,我实现了两个小扩展,因为16位浮点数的一般精度相当低,这可能使浮点格式的固有异常在视觉上可感知,而较大的浮点类型由于其足够的精度而通常不会被注意到 .
第一个是
toFloat()
函数中的这两行:类型大小的正常范围内的浮点数采用指数,因此精度为值的大小 . 但这并非顺利采用,而是按步骤进行:切换到下一个更高的指数会导致精度降低一半 . 对于尾数的所有值,精度现在保持不变,直到下一个跳到下一个更高的指数 . 上面的扩展代码通过返回该特定半浮点值的覆盖32位浮点范围的地理中心中的值,使这些转换更平滑 . 每个正常的半浮点值都精确映射到8192个32位浮点值 . 返回的值应该恰好位于这些值的中间 . 但是在半浮点指数的转换处,较低的4096值具有两倍于上4096值的精度,因此覆盖的数字空间仅为另一侧的一半 . 所有这些8192 32位浮点值映射到相同的半浮点值,因此将半浮点数转换为32位并返回导致相同的半浮点值,无论选择了哪个8192中间32位值 . 现在,扩展现在在转换时产生更平滑的半步长因子sqrt(2),如右图所示,而左图像应该将锐步步骤可视化为2而没有抗锯齿 . 您可以安全地从代码中删除这两行以获得标准行为 .
第二个扩展名在
fromFloat()
函数中:此扩展稍微扩展了半浮点数格式的数字范围,方法是保存一些32位值,从而将其提升为Infinity . 受影响的值是那些在没有舍入的情况下小于无穷大的值,并且由于舍入而仅变为无穷大 . 如果您不想要此扩展名,可以安全地删除上面显示的行 .
我试图尽可能多地优化
fromFloat()
函数中正常值的路径,这使得它由于使用了预先计算和未移位的常量而变得不那么可读 . 我没有't put as much effort into ' toFloat()',因为它无论如何都不会超过查找表的性能 . 因此,如果速度真的很重要,可以使用toFloat()
函数仅填充带有0x10000元素的静态查找表,而不是使用此表进行实际转换 . 使用当前的x64服务器虚拟机大约快3倍,使用x86客户端虚拟机大约快5倍 .我把代码放在公共领域 .
x4u的代码正确地将值1编码为0x3c00(ref:https://en.wikipedia.org/wiki/Half-precision_floating-point_format) . 但是具有平滑度改进的解码器将其解码为1.000122 . 维基百科条目表示可以表示整数值0..2048究竟 . 不太好...
从toFloat代码中删除
"| 0x3ff"
确保toFloat(fromFloat(k)) == k
对于-2048..2048范围内的整数k,可能代价是平滑度稍差 .在我看到这里发布的解决方案之前,我已经掀起了一些简单的事情:
不过,我确实喜欢其他发布解决方案中的方法 . 以供参考: