V.B.
V.B.

Reputation: 6382

.NET decimal cross-platform standard

If I save C# decimal array to a binary blob with a binary writer, will I be able to seamlessly read this blob in Java or Python or R? Do these language have a corresponding data type or is there a cross-platform standard that .NET decimal adheres to?

I am converting all my numeric data to decimals before storing, because when an array of decimals is diffed and then compressed, the resulting blob size is much smaller for real world data than a float blob compressed by any algo (my tests show c.2x less space). And decimals do not lose precision on diffing. But I am not sure if I could read this blobs from any other language other than .NET ones.

I am reading the wiki page but cannot answer this simple question myself.

Update:

Currently I take an unsafe reference to decimal[] array and cast it to (byte* ) pointer, but this is equivalent to binary writer. The question is about cross-platform decimal interop, not serialization. See my comment in the first answer.

Upvotes: 1

Views: 636

Answers (1)

Dai
Dai

Reputation: 155075

The documentation for the System.Decimal type does not state what internal representation it uses (unlike System.Single and System.Double which use IEEE-754). Given this, you cannot assume that the raw binary state representation of any decimal number will be consistent between .NET Framework versions or even between physical machines running the same version.

I assume you'd be using the BinaryWriter.Write(Decimal value) method. The documentation for this method does not make any statement about the actual format being used.

Looking at the .NET Reference source code, we see that BinaryWriter.Write(Decimal) uses an internal method: Decimal.GetBytes(Byte[] buffer) which uses an undocumented format which might change in future or may differ per-machine.

However! The Decimal class does provide a public method GetBits which does make guarantees about the format of data it returns, so I suggest you use this instead:

// Writing
Int32[] bits = myDecimal.GetBits();

binaryWriter.Write( (byte)bits.Length );
foreach(Int32 component in bits) binaryWriter.Write( component );

// Reading
byte count = binaryReader.ReadByte();
Int32[] bits = new Int32[ count ];
for(Int32 i = 0; i < bits.Count; i++ ) {
    bits[i] = binaryReader.ReadInt32();
}

Decimal value = new Decimal( bits );

This approach uses 17 bytes to store a Decimal instance in a way that is documented and guaranteed to work regardless of the internal design of the Decimal type. 16 bytes store the actual value, and 1 byte stores the number of 32-bit integers needed to represent the decimal (in case the number ever changes from 4).

Upvotes: 5

Related Questions