11

是的,我知道 IEEE-754 半精度标准,是的,我知道在该领域所做的工作。简单地说,我试图在 2 个字节中保存一个简单的浮点数(如52.1、 或)。1.25

我在JavaC#中尝试了一些实现,但它们通过解码不同的数字来破坏输入值。您输入32.1并在编码解码后得到32.0985.

有什么方法可以在不破坏输入值的情况下仅以 16 位存储浮点数?

非常感谢。

4

6 回答 6

11

您可以将三位数字存储在 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
于 2012-05-02T13:43:08.460 回答
7

C# 对此没有内置功能,但您可以尝试使用定点方法。

8,8 定点示例(逗号前 8,逗号后 8):

float value = 123.45;
ushort fixedIntValue = (ushort)(value * 256);

这样,号码是这样存储的:XXXXXXXX,XXXXXXXX

您可以使用以下方法再次检索浮动:

float value = fixedIntValue / 256f;
于 2012-05-02T13:40:26.607 回答
5

你确定你需要这样的微优化,而不是简单地使用floatordouble吗?

存储 ashort并理解例如它除以 100 得到实际数字会更好吗?(例如,您的 52.1 和 1.25 示例可以存储为 5210 和 125)我认为这可能是您的最佳解决方案。

如果您打算使用实际的浮点数,则可以将解码后的数字四舍五入到 x 位有效数字(从您的示例中为 3),这通常可以让您返回与开始时相同的数字(请注意是的,这是故意含糊不清的——除非您存储原件,否则您不能保证获得原件)。

于 2012-05-02T13:40:32.313 回答
4

问题是您无法32.1任何二进制浮点类型精确表示。

在单精度中,最接近的可表示值是 32.099998。在半精度下,它显然是 32.0985。

您可以考虑使用十进制浮点类型,但这种解决方案并不是半精度独有的。

于 2012-05-02T13:38:42.670 回答
1

从您的示例中,您想要存储 3 位数字和一个小数点。您可以简单地将 11 个符号的“字母”编码为 4 位代码,并将 4 x 4 位存储在 2 个字节中。

于 2012-05-02T13:39:06.063 回答
1

有 4,278,190,080 个 32 位浮点值,不包括 NaN 和无穷大。两个字节中的 16 位有 65,536 个值。显然,不可能将所有浮点值唯一地编码在两个字节中。

您要编码哪些?

即使对于符号和指数的单个值(例如,从 4 到 8 的所有浮点值,不包括 8),也有 8,388,608 个浮点值,因此您甚至无法将它们编码为两个字节。

您必须将自己限制为要编码的一小部分值。完成此操作后,人们可能会对如何对其进行编码提出建议。您要解决的实际问题是什么?

于 2012-05-02T20:49:21.807 回答