How do I save a floating-point number in 2 bytes?

别来无恙 提交于 2019-12-01 05:26:05

You could store three digits in BCD and use the remaining four bits for the decimal point position:

52.1 = 521 * 10 ^ -1 => 0x1521
1.25 = 125 * 10 ^ -2 => 0x2125

This would give you a range from 0.0000000000000001 to 999. You can of course add an offset for the decimal point to get for example the range 0.0000000001 to 999000000.


Simple implementation of four bit used for decimal point placement, and the rest for the value. Without any error check, and not thoroughly checked. (May have precision issues with some values when using != to compare doubles.)

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;
}

Example:

Console.WriteLine(Encode(52.1));
Console.WriteLine(Decode(4617));

Output:

4617
52.1

C# has no built in functionality for that, but you could try a fixed point approach.

Example of 8,8 Fixed point (8 before comma, 8 after):

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

This way, the number is stored like this: XXXXXXXX,XXXXXXXX

and you can retrieve the float again using this:

float value = fixedIntValue / 256f;

Are you sure you need such a micro-optimization, over simply using a float or double?

Would you be better served by storing a short and understanding that, e.g., it's divided by 100 to make the actual number? (E.g. your examples of 52.1 and 1.25 could be stored as 5210 and 125) I think this might be the best solution for you.

If you're set on using an actual floating-point number, you can take the decoded number and round it to x significant digits, (from your example, 3) which should usually get you back the same number you started with (note that yes, that's intentionally vague - you can't guarantee getting the original unless you store the original).

The problem is that you can't precisely represent 32.1 in any binary floating-point type.

In single-precision, the closest representable value is 32.099998. In half-precision, it's apparently 32.0985.

You could consider a decimal floating-point type, but this solution is not unique to half-precision.

There are 4,278,190,080 32-bit floating-point values, not including NaNs and infinities. There are 65,536 values for the 16 bits in two bytes. Clearly, it is impossible to uniquely encode all the floating-point values in two bytes.

Which ones do you want to encode?

Even for a single value of the sign and exponent (e.g., all floating-point values from 4 to 8, not including 8), there are 8,388,608 floating-point values, so you cannot even encode those in two bytes.

You have to restrict yourself to a small subset of values to encode. Once you have done that, people may have suggestions about how to encode them. What is the actual problem you are trying to solve?

High Performance Mark

From your examples you want to store 3 digits and a decimal point. You could simply encode your 'alphabet' of 11 symbols into a 4-bit code, and store 4 x 4 bits in 2 bytes.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!