示例#1
0
文件: Currency.cs 项目: Ibasa/Ripple
        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);
        }