File: System\Numerics\NumericsHelpers.cs
Web Access
Project: src\runtime\src\libraries\System.Runtime.Numerics\src\System.Runtime.Numerics.csproj (System.Runtime.Numerics)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Runtime.Intrinsics;

namespace System.Numerics
{
    internal static class NumericsHelpers
    {
        public static void GetDoubleParts(double dbl, out int sign, out int exp, out ulong man, out bool fFinite)
        {
            ulong bits = BitConverter.DoubleToUInt64Bits(dbl);

            sign = 1 - ((int)(bits >> 62) & 2);
            man = bits & 0x000FFFFFFFFFFFFF;
            exp = (int)(bits >> 52) & 0x7FF;
            if (exp == 0)
            {
                // Denormalized number.
                fFinite = true;
                if (man != 0)
                {
                    exp = -1074;
                }
            }
            else if (exp == 0x7FF)
            {
                // NaN or Infinite.
                fFinite = false;
                exp = int.MaxValue;
            }
            else
            {
                fFinite = true;
                man |= 0x0010000000000000;
                exp -= 1075;
            }
        }

        /// <summary>Performs an in-place two's complement. Use with care for immutable types.</summary>
        public static void DangerousMakeTwosComplement(Span<nuint> d)
        {
            // Given a number:
            //     XXXXXXXXXXXY00000
            // where Y is non-zero,
            // The result of two's complement is
            //     AAAAAAAAAAAB00000
            // where A = ~X and B = -Y

            // Trim trailing 0s (at the first in little endian array)
            int i = d.IndexOfAnyExcept(0u);

            if ((uint)i >= (uint)d.Length)
            {
                return;
            }

            // Make the first non-zero element to be two's complement
            d[i] = (nuint)(-(nint)d[i]);
            d = d.Slice(i + 1);

            if (d.IsEmpty)
            {
                return;
            }

            DangerousMakeOnesComplement(d);
        }

        /// <summary>Performs an in-place one's complement. Use with care for immutable types.</summary>
        public static void DangerousMakeOnesComplement(Span<nuint> d)
        {
            // Given a number:
            //     XXXXXXXXXXX
            // where Y is non-zero,
            // The result of one's complement is
            //     AAAAAAAAAAA
            // where A = ~X

            while (Vector512.IsHardwareAccelerated && d.Length >= Vector512<nuint>.Count)
            {
                Vector512<nuint> complement = ~Vector512.Create(d);
                complement.CopyTo(d);
                d = d.Slice(Vector512<nuint>.Count);
            }

            while (Vector256.IsHardwareAccelerated && d.Length >= Vector256<nuint>.Count)
            {
                Vector256<nuint> complement = ~Vector256.Create(d);
                complement.CopyTo(d);
                d = d.Slice(Vector256<nuint>.Count);
            }

            while (Vector128.IsHardwareAccelerated && d.Length >= Vector128<nuint>.Count)
            {
                Vector128<nuint> complement = ~Vector128.Create(d);
                complement.CopyTo(d);
                d = d.Slice(Vector128<nuint>.Count);
            }

            for (int i = 0; i < d.Length; i++)
            {
                d[i] = ~d[i];
            }
        }

        /// <summary>Branchless abs: arithmetic right shift produces 0 (positive) or -1 (negative) mask,
        /// then XOR-and-subtract flips negative values without branching.</summary>
        public static nuint Abs(int a)
        {
            nuint mask = (nuint)(a >> 31);
            return ((nuint)a ^ mask) - mask;
        }
    }
}