30

I have to convert values (double/float in C#) to bytes and need some help..

// Datatype long 4byte -99999999,99 to 99999999,99
// Datatype long 4byte -99999999,9 to 99999999,9
// Datatype short 2byte -999,99 to 999,99
// Datatype short 2byte -999,9 to 999,9

In my "world at home" i would just string it and ASCII.GetBytes().

But now, in this world, we have to make less possible space.
And indeed that '-99999999,99' takes 12 bytes instead of 4! if it's a 'long' datatype.

[EDIT]
Due to some help and answer I attach some results here,

long lng = -9999999999L;
byte[] test = Encoding.ASCII.GetBytes(lng.ToString());  // 11 byte
byte[] test2 = BitConverter.GetBytes(lng);              // 8 byte
byte[] mybyt = BitConverter.GetBytes(lng);              // 8 byte
byte[] bA = BitConverter.GetBytes(lng);                 // 8 byte

There still have to be one detail left to find out. The lng-variabel got 8 byte even if it helds a lower values, i.e. 99951 (I won't include the ToString() sample).

If the value are even "shorter", which means -999,99 -- 999,99 it will only take 2 byte space.
[END EDIT]

10
  • You know that long and short are integral type, so no decimals, right? And that a long is 8 bytes, not 4! That is "int". Commented Aug 26, 2011 at 8:40
  • 3
    I'm amazed how many answers there are when the question doesn't even make sense. What has he got and what is he trying to get? Commented Aug 26, 2011 at 8:54
  • @xanatos Your point is worth mentioning. The values are floats in the beginning (but that's another question). Commented Aug 26, 2011 at 9:37
  • 2
    @Jonas Perhaps you want to make an "adaptative-length binary serialization of a double", right? So you can serialize a double in 2 bytes if it's between -999,99 and 999,99 and in four bytes if it's between -99999999,99 and 99999999,99 and clearly you ignore the numbers > 99999999,99 and < -99999999,99. Is everything right? Commented Aug 26, 2011 at 9:43
  • 1
    @Jonas I'll add that it isn't possible to save EXACTLY a number like 99999999,99 (signed) in 4 bytes, because the log2 of (99999999,99 * 100) (to make it an integer) is 33,22 so it will need 34 bits + 1 bit for the sign and, because you probably want to be able to recognize the short 2 bytes form from the long 4 bytes form when you deserialize it, you'll need an extra bit, so 35 bits that is more than 4 bytes. Commented Aug 26, 2011 at 9:46

6 Answers 6

59

Have you checked BitConverter

long lng =-9999999999L;
byte[] mybyt = BitConverter.GetBytes(lng);

hope this is what you are looking

Sign up to request clarification or add additional context in comments.

3 Comments

Note that the result depends on your machine's endianness.
what it has to depend in your opinion?
yes, @mpartel is right and if you convert the resulting byte array back to int64 you might get a different value!
10

Try to do it in this way:

long l = 4554334;

byte[] bA = BitConverter.GetBytes(l);

1 Comment

Old answer, but the only thing I don't like about this is the use of the lower case L, which looks like you are trying to get the bytes of the number 1: GetBytes(l) vs GetBytes(1) can be hard on someone trying to debug large coding blocks after you are gone. Not a downvote! Just pointing that out.
9

Be aware that in 2 bytes you can only have 4 full digits + sign, and in 4 bytes you can only have 9 digits + sign, so I had to scale your prereqs accordingly.

public static byte[] SerializeLong2Dec(double value)
{
    value *= 100;
    value = Math.Round(value, MidpointRounding.AwayFromZero);

    if (value < -999999999.0 || value > 999999999.0)
    {
        throw new ArgumentOutOfRangeException();
    }

    int value2 = (int)value;

    return BitConverter.GetBytes(value2);
}

public static double DeserializeLong2Dec(byte[] value)
{
    int value2 = BitConverter.ToInt32(value, 0);
    return (double)value2 / 100.0;
}

public static byte[] SerializeLong1Dec(double value) {
    value *= 10;
    value = Math.Round(value, MidpointRounding.AwayFromZero);

    if (value < -999999999.0 || value > 999999999.0) {
        throw new ArgumentOutOfRangeException();
    }

    int value2 = (int)value;

    return BitConverter.GetBytes(value2);
}

public static double DeserializeLong1Dec(byte[] value) {
    int value2 = BitConverter.ToInt32(value, 0);
    return (double)value2 / 10.0;
}

public static byte[] SerializeShort2Dec(double value) {
    value *= 100;
    value = Math.Round(value, MidpointRounding.AwayFromZero);

    if (value < -9999.0 || value > 9999.0) {
        throw new ArgumentOutOfRangeException();
    }

    short value2 = (short)value;

    return BitConverter.GetBytes(value2);
}

public static double DeserializeShort2Dec(byte[] value) {
    short value2 = BitConverter.ToInt16(value, 0);
    return (double)value2 / 100.0;
}

public static byte[] SerializeShort1Dec(double value) {
    value *= 10;
    value = Math.Round(value, MidpointRounding.AwayFromZero);

    if (value < -9999.0 || value > 9999.0) {
        throw new ArgumentOutOfRangeException();
    }

    short value2 = (short)value;

    return BitConverter.GetBytes(value2);
}

public static double DeserializeShort1Dec(byte[] value) {
    short value2 = BitConverter.ToInt16(value, 0);
    return (double)value2 / 10.0;
}

So that it's clear, the range of a (signed) short (16 bits) is -32,768 to 32,767 so it's quite clear that you only have 4 full digits plus a little piece (the 0-3), the range of a (signed) int (32 bits) is −2,147,483,648 to 2,147,483,647 so it's quite clear that you only have 9 full digits plus a little piece (the 0-2). Going to a (signed) long (64 bits) you have -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 so 18 digits plus a (big) piece. Using floating points you lose in accuracy. A float (32 bits) has an accuracy of around 7 digits, while a double (64 bits) has an accuracy of around 15-16 digits.

Comments

5

To everyone reading this question and the answers. Please note that:

//convert to bytes
long number = 123;
byte[] bytes = BitConverter.GetBytes(number);

//convert back to int64
long newNumber = BitConverter.ToInt64(bytes);

//numbers are different on x64 systems!!!
number != newNumber;

The workaround is to check which system you run on:

newNumber = BitConverter.IsLittleEndian
    ? BitConverter.ToInt64(bytes, 0)
    : BitConverter.ToInt64(bytes.Reverse().ToArray(), 0);

1 Comment

I don't understand this. Both x86 and x64 are little endian.
2

As the other answers have pointed out, you can use BitConverter to get the byte representation of primitive types.

You said that in the current world you inhabit, there is an onus on representing these values as concisely as possible, in which case you should consider variable length encoding (though that document may be a bit abstract).

If you decide this approach is applicable to your case I would suggest looking at how the Protocol Buffers project represents scalar types as some of these types are encoded using variable length encoding which produces shorter output if the data set favours smaller absolute values. (The project is open source under a New BSD license, so you will be able to learn the technique employed from the source repository or even use the source in your own project.)

Comments

1
long longValue = 9999999999L;

        Console.WriteLine("Long value: " + longValue.ToString());

        bytes = BitConverter.GetBytes(longValue);

        Console.WriteLine("Byte array value:");

        Console.WriteLine(BitConverter.ToString(bytes));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.