是的,我知道 IEEE-754 半精度标准,是的,我知道在该领域所做的工作。简单地说,我试图在 2 个字节中保存一个简单的浮点数(如52.1
、 或)。1.25
我在Java和C#中尝试了一些实现,但它们通过解码不同的数字来破坏输入值。您输入32.1
并在编码解码后得到32.0985
.
有什么方法可以在不破坏输入值的情况下仅以 16 位存储浮点数?
非常感谢。
您可以将三位数字存储在 BCD 中,并将剩余的四位用于小数点位置:
52.1 = 521 * 10 ^ -1 => 0x1521
1.25 = 125 * 10 ^ -2 => 0x2125
这将为您提供从 0.0000000000000001 到 999 的范围。您当然可以为小数点添加偏移量,例如范围为 0.0000000001 到 999000000。
四位用于小数点放置的简单实现,其余用于值。没有任何错误检查,也没有彻底检查。!=
(用于比较双精度时,某些值可能存在精度问题。)
public static short Encode(double value) {
int cnt = 0;
while (value != Math.Floor(value)) {
value *= 10.0;
cnt++;
}
return (short)((cnt << 12) + (int)value);
}
public static double Decode(short value) {
int cnt = value >> 12;
double result = value & 0xfff;
while (cnt > 0) {
result /= 10.0;
cnt--;
}
return result;
}
例子:
Console.WriteLine(Encode(52.1));
Console.WriteLine(Decode(4617));
输出:
4617
52.1
C# 对此没有内置功能,但您可以尝试使用定点方法。
8,8 定点示例(逗号前 8,逗号后 8):
float value = 123.45;
ushort fixedIntValue = (ushort)(value * 256);
这样,号码是这样存储的:XXXXXXXX,XXXXXXXX
您可以使用以下方法再次检索浮动:
float value = fixedIntValue / 256f;
你确定你需要这样的微优化,而不是简单地使用float
ordouble
吗?
存储 ashort
并理解例如它除以 100 得到实际数字会更好吗?(例如,您的 52.1 和 1.25 示例可以存储为 5210 和 125)我认为这可能是您的最佳解决方案。
如果您打算使用实际的浮点数,则可以将解码后的数字四舍五入到 x 位有效数字(从您的示例中为 3),这通常可以让您返回与开始时相同的数字(请注意是的,这是故意含糊不清的——除非您存储原件,否则您不能保证获得原件)。
问题是您无法32.1
以任何二进制浮点类型精确表示。
在单精度中,最接近的可表示值是 32.099998。在半精度下,它显然是 32.0985。
您可以考虑使用十进制浮点类型,但这种解决方案并不是半精度独有的。
从您的示例中,您想要存储 3 位数字和一个小数点。您可以简单地将 11 个符号的“字母”编码为 4 位代码,并将 4 x 4 位存储在 2 个字节中。
有 4,278,190,080 个 32 位浮点值,不包括 NaN 和无穷大。两个字节中的 16 位有 65,536 个值。显然,不可能将所有浮点值唯一地编码在两个字节中。
您要编码哪些?
即使对于符号和指数的单个值(例如,从 4 到 8 的所有浮点值,不包括 8),也有 8,388,608 个浮点值,因此您甚至无法将它们编码为两个字节。
您必须将自己限制为要编码的一小部分值。完成此操作后,人们可能会对如何对其进行编码提出建议。您要解决的实际问题是什么?