using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; namespace System { internal static class DecimalEx { [StructLayout(LayoutKind.Explicit)] private struct DecimalBits { [FieldOffset(0)] public int flags; [FieldOffset(4)] public int hi; [FieldOffset(8)] public int lo; [FieldOffset(12)] public int mid; } [StructLayout(LayoutKind.Explicit)] private struct DecCalc { private const uint TenToPowerNine = 1000000000; // NOTE: Do not change the offsets of these fields. This structure must have the same layout as Decimal. [FieldOffset(0)] public uint uflags; [FieldOffset(4)] public uint uhi; [FieldOffset(8)] public uint ulo; [FieldOffset(12)] public uint umid; /// /// The low and mid fields combined in little-endian order /// [FieldOffset(8)] private ulong ulomidLE; internal static uint DecDivMod1E9(ref DecCalc value) { ulong high64 = ((ulong)value.uhi << 32) + value.umid; ulong div64 = high64 / TenToPowerNine; value.uhi = (uint)(div64 >> 32); value.umid = (uint)div64; ulong num = ((high64 - (uint)div64 * TenToPowerNine) << 32) + value.ulo; uint div = (uint)(num / TenToPowerNine); value.ulo = div; return (uint)num - div * TenToPowerNine; } } private const int ScaleShift = 16; static ref DecCalc AsMutable(ref decimal d) => ref Unsafe.As(ref d); internal static uint High(this decimal value) { return Unsafe.As(ref value).uhi; } internal static uint Low(this decimal value) { return Unsafe.As(ref value).ulo; } internal static uint Mid(this decimal value) { return Unsafe.As(ref value).umid; } internal static bool IsNegative(this decimal value) { return Unsafe.As(ref value).flags < 0; } internal static int Scale(this decimal value) { return (byte)(Unsafe.As(ref value).flags >> ScaleShift); } internal static uint DecDivMod1E9(ref decimal value) { return DecCalc.DecDivMod1E9(ref AsMutable(ref value)); } } }