public Currency(decimal amount) { if (amount == 0m) { this.bits = 0; return; } var bits = Decimal.GetBits(amount); Span <byte> mantissabytes = stackalloc byte[12]; System.Buffers.Binary.BinaryPrimitives.WriteInt32LittleEndian(mantissabytes.Slice(0, 4), bits[0]); System.Buffers.Binary.BinaryPrimitives.WriteInt32LittleEndian(mantissabytes.Slice(4, 4), bits[1]); System.Buffers.Binary.BinaryPrimitives.WriteInt32LittleEndian(mantissabytes.Slice(8, 4), bits[2]); var bigmantissa = new System.Numerics.BigInteger(mantissabytes, true, false); var isPositive = (bits[3] & 0xF000_0000) == 0; var exponent = (bits[3] >> 16) & 0xFF; // C# decimal is stored as 'mantissa / 10^exponent' where exponent must be (0, 28) and mantissa is 96 bits, // while ripple stores decimals as 'mantissa * 10^exponent' where exponent must be (-96, 80) and mantissa is 54 bits. // First flip the exponent (C# divides, ripple multiplies) exponent = -exponent; // We need to scale the mantissa to be between 1000_0000_0000_0000 and 9999_9999_9999_9999 while (bigmantissa < minMantissa) { exponent -= 1; bigmantissa *= 10; } while (bigmantissa > maxMantissa) { exponent += 1; bigmantissa /= 10; } // mantissa will now fit into 54 bits, exponent should be between -96 and 80. mantissabytes.Clear(); var ok = bigmantissa.TryWriteBytes(mantissabytes, out var bytesWritten, true, false); System.Diagnostics.Debug.Assert(ok); System.Diagnostics.Debug.Assert(bytesWritten <= 7); var mantissa = System.Buffers.Binary.BinaryPrimitives.ReadUInt64LittleEndian(mantissabytes); System.Diagnostics.Debug.Assert(minExponent <= exponent && exponent <= maxExponent); System.Diagnostics.Debug.Assert(minMantissa <= mantissa && mantissa <= maxMantissa); this.bits = Pack(isPositive, exponent, mantissa); }