读写非标准浮点值
Posted
技术标签:
【中文标题】读写非标准浮点值【英文标题】:Reading and writing non-standard floating point values 【发布时间】:2019-08-08 10:16:03 【问题描述】:我正在使用 C# 中的二进制文件(旧视频游戏的 3d 模型文件)。文件格式没有正式记录,但其中一些已被游戏社区逆向工程。
我无法理解如何读取/写入 4 字节浮点值。社区成员向我提供了以下解释:
例如,字节
EE 62 ED FF
表示值 -18.614。字节是小端序的。前 2 个字节代表数值的小数部分,后 2 个字节代表数值的整个部分。
对于小数部分,
62 EE
转换为十进制是25326。这表示1的分数,也可以描述为65536/65536。因此,将 25326 除以 65536 得到 0.386。对于整个部分,
FF ED
转换为十进制是 65517。65517 表示整数 -19(即 65517 - 65536)。这使得值 -19 + .386 = -18.614。
这个解释大部分是有道理的,但我对两件事感到困惑:
-
神奇的数字65536有什么意义吗?
BinaryWriter.Write(-18.613f)
将字节写入79 E9 94 C1
,所以我的假设是我正在使用的二进制文件使用它自己的专有方法来存储 4 字节浮点值(即我不能互换使用 C# 的 float
并且将需要先对值进行编码/解码)?
【问题讨论】:
首先不是浮点值。 65536=2^16... 这可能是重要的,但同时也是任意的 还有25326 / 65536
不是0.386
【参考方案1】:
首先,这不是Floating Point Number,而是Fix Point Number
注意:定点数具有为整数部分(小数左边的部分)保留的特定位数(或位数)点)
神奇的数字65536有什么意义
它是无符号 16 位数字可以容纳的最大值数,或者 2^16
,是的,它很重要,因为您正在使用的数字是为整数和小数分量编码的 2 * 16 位值。
所以我的假设是我正在使用的二进制文件使用它自己的 存储 4 字节浮点值的专有方法
没有错,.Net 中的浮点值遵循IEEE Standard for Floating-Point Arithmetic (IEEE 754) technical standard
当您使用BinaryWriter.Write(float);
时,它基本上只是将位移动到byte
s 并将其写入Stream
。
uint TmpValue = *(uint *)&value;
_buffer[0] = (byte) TmpValue;
_buffer[1] = (byte) (TmpValue >> 8);
_buffer[2] = (byte) (TmpValue >> 16);
_buffer[3] = (byte) (TmpValue >> 24);
OutStream.Write(_buffer, 0, 4);
如果你想读取和写入这个特殊值,你需要做同样的事情,你将不得不读取和写入字节并自己转换它们
【讨论】:
我认为这不是Fix Point Number
,因为它是Last 2 bytes **adds*8 first 2 bytes
,而不是All 4 bytes divided by 65536
。你怎么看!?
@PiggyChu001 你可能是对的,它也不完全在固定点值的定义之下
很高兴你同意。【参考方案2】:
这应该是游戏独有的内置值。
应该更类似于Fraction Value
。
其中62 EE
代表值的Fraction Part
,FF ED
代表值的Whole Number Part
。
While Number Part
很容易理解所以我就不解释了。
Fraction Part
的解释是:
对于每 2 个字节,有 65536
个可能性(0 ~ 65535)。
256 X 256 = 65536
因此是幻数65536
。
而且游戏本身必须有一个内置算法来将前 2 个字节除以 65536。
选择除此之外的任何数字将是 waste of memory space
并导致 decreased accuracy of the value which can be represented
。
当然,这完全取决于游戏希望呈现的准确度。
【讨论】:
以上是关于读写非标准浮点值的主要内容,如果未能解决你的问题,请参考以下文章
多线程 锁策略 ( 悲观/乐观锁 读写/互斥锁 重量/轻量级锁挂起等待/自旋锁 公平/非公平锁 可重入/不可重入锁)