简体   繁体   中英

How do I convert byte values into decimals?

I'm trying to load some decimal values from a file but I can't work out the correct way to take the raw values and convert them into decimals.

I've read the file out into a byte array, and each chunk of four bytes is supposed to represent one decimal value. To help figure it out, I've constructed a table of how the decimal values 1 through to 46 are represented as four byte chunks.

For instance, the number 1 appears as 0,0,128,63 the number 2 as 0,0,0,64 and so on up to 46, which is 0,0,56,66. The full table is available here .

There is also another series of numbers which go to three decimal places and include negatives, which is here .

The only documentation I have states

They are stored least significant byte first: 1's, 256's, 65536's, 16777216's. This makes the hex sequence 01 01 00 00 into the number 257 (decimal). In C/C++, to read eg a float, do: float x; fread(&x, sizeof(float), 1, fileptr);

However I'm using .NET's File.ReadAllBytes method so this isn't much help. If anyone can spare a few minutes to look at the examples files and see if they can spot a way to convert the values to decimals I'd be most grateful.

You can use BitConverter.ToSingle to read a float value from a byte array, so to get a sequence of floats, you could do something like this:

byte[] data = File.ReadAllBytes(fileName);
int count = data.Length / 4;
Debug.Assert(data.Length % 4 == 0);

IEnumerable<float> values = Enumerable.Range(0, count)
    .Select(i => BitConverter.ToSingle(data, i*4));

Have you looked into using the BitConverter class? It converts between byte arrays and various types.

Edit: MSDN has a helpful comment on the documentation for BitConverter at http://msdn.microsoft.com/en-us/library/system.bitconverter_methods(v=vs.85).aspx :

public static decimal ToDecimal(byte[] bytes)
{
  int[] bits = new int[4];
  bits[0] = ((bytes[0] | (bytes[1] << 8)) | (bytes[2] << 0x10)) | (bytes[3] << 0x18); //lo
  bits[1] = ((bytes[4] | (bytes[5] << 8)) | (bytes[6] << 0x10)) | (bytes[7] << 0x18); //mid
  bits[2] = ((bytes[8] | (bytes[9] << 8)) | (bytes[10] << 0x10)) | (bytes[11] << 0x18); //hi
  bits[3] = ((bytes[12] | (bytes[13] << 8)) | (bytes[14] << 0x10)) | (bytes[15] << 0x18); //flags

  return new decimal(bits);
}

public static byte[] GetBytes(decimal d)
{
  byte[] bytes = new byte[16];

  int[] bits = decimal.GetBits(d);
  int lo = bits[0];
  int mid = bits[1];
  int hi = bits[2];
  int flags = bits[3];

  bytes[0] = (byte)lo;
  bytes[1] = (byte)(lo >> 8);
  bytes[2] = (byte)(lo >> 0x10);
  bytes[3] = (byte)(lo >> 0x18);
  bytes[4] = (byte)mid;
  bytes[5] = (byte)(mid >> 8);
  bytes[6] = (byte)(mid >> 0x10);
  bytes[7] = (byte)(mid >> 0x18);
  bytes[8] = (byte)hi;
  bytes[9] = (byte)(hi >> 8);
  bytes[10] = (byte)(hi >> 0x10);
  bytes[11] = (byte)(hi >> 0x18);
  bytes[12] = (byte)flags;
  bytes[13] = (byte)(flags >> 8);
  bytes[14] = (byte)(flags >> 0x10);
  bytes[15] = (byte)(flags >> 0x18);

  return bytes;
}

The .NET library implemented Decimal.GetBytes() method internally.

I've used the decompiled .NET library to create a simple conversion methods between decimal and byte arrary - you can find it here:

https://gist.github.com/eranbetzalel/5384006#file-decimalbytesconvertor-cs

EDIT : Here is the full source code from my link.

public decimal BytesToDecimal(byte[] buffer, int offset = 0)
{
  var decimalBits = new int[4];

  decimalBits[0] = buffer[offset + 0] | (buffer[offset + 1] << 8) | (buffer[offset + 2] << 16) | (buffer[offset + 3] << 24);
  decimalBits[1] = buffer[offset + 4] | (buffer[offset + 5] << 8) | (buffer[offset + 6] << 16) | (buffer[offset + 7] << 24);
  decimalBits[2] = buffer[offset + 8] | (buffer[offset + 9] << 8) | (buffer[offset + 10] << 16) | (buffer[offset + 11] << 24);
  decimalBits[3] = buffer[offset + 12] | (buffer[offset + 13] << 8) | (buffer[offset + 14] << 16) | (buffer[offset + 15] << 24);

  return new Decimal(decimalBits);
}

public byte[] DecimalToBytes(decimal number)
{
  var decimalBuffer = new byte[16];

  var decimalBits = Decimal.GetBits(number);

  var lo = decimalBits.Value[0];
  var mid = decimalBits.Value[1];
  var hi = decimalBits.Value[2];
  var flags = decimalBits.Value[3];

  decimalBuffer[0] = (byte)lo;
  decimalBuffer[1] = (byte)(lo >> 8);
  decimalBuffer[2] = (byte)(lo >> 16);
  decimalBuffer[3] = (byte)(lo >> 24);

  decimalBuffer[4] = (byte)mid;
  decimalBuffer[5] = (byte)(mid >> 8);
  decimalBuffer[6] = (byte)(mid >> 16);
  decimalBuffer[7] = (byte)(mid >> 24);

  decimalBuffer[8] = (byte)hi;
  decimalBuffer[9] = (byte)(hi >> 8);
  decimalBuffer[10] = (byte)(hi >> 16);
  decimalBuffer[11] = (byte)(hi >> 24);

  decimalBuffer[12] = (byte)flags;
  decimalBuffer[13] = (byte)(flags >> 8);
  decimalBuffer[14] = (byte)(flags >> 16);
  decimalBuffer[15] = (byte)(flags >> 24);

  return decimalBuffer;
}

As others have mentioned, use the BitConverter class, see the example below:

     byte[] bytez = new byte[] { 0x00, 0x00, 0x80, 0x3F };
     float flt = BitConverter.ToSingle(bytez, 0); // 1.0

     bytez = new byte[] { 0x00, 0x00, 0x00, 0x40 };
     flt = BitConverter.ToSingle(bytez, 0); // 2.0

     bytez = new byte[] { 0, 0, 192, 190 };
     flt = BitConverter.ToSingle(bytez, 0); // -0.375

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM