You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
213 lines
5.6 KiB
213 lines
5.6 KiB
5 years ago
|
// Copyright (c) Microsoft. All rights reserved.
|
||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||
|
|
||
|
#if !NET_4_6
|
||
|
using System.Diagnostics;
|
||
|
using System.Diagnostics.Contracts;
|
||
|
using System.Runtime.InteropServices;
|
||
|
|
||
|
namespace System.Numerics
|
||
|
{
|
||
|
[StructLayout(LayoutKind.Explicit)]
|
||
|
internal struct DoubleUlong
|
||
|
{
|
||
|
[FieldOffset(0)]
|
||
|
public double Dbl;
|
||
|
|
||
|
[FieldOffset(0)]
|
||
|
public ulong Uu;
|
||
|
}
|
||
|
|
||
|
internal static class NumericsHelpers
|
||
|
{
|
||
|
private const int _uintBitCount = 32;
|
||
|
|
||
|
public static void GetDoubleParts(double dbl, out int sign, out int exp, out ulong man, out bool fFinite)
|
||
|
{
|
||
|
Contract.Ensures(Contract.ValueAtReturn(out sign) == +1 || Contract.ValueAtReturn(out sign) == -1);
|
||
|
|
||
|
DoubleUlong du;
|
||
|
du.Uu = 0;
|
||
|
du.Dbl = dbl;
|
||
|
|
||
|
sign = 1 - ((int)(du.Uu >> 62) & 2);
|
||
|
man = du.Uu & 0x000FFFFFFFFFFFFF;
|
||
|
exp = (int)(du.Uu >> 52) & 0x7FF;
|
||
|
if (exp == 0)
|
||
|
{
|
||
|
// Denormalized number.
|
||
|
fFinite = true;
|
||
|
if (man != 0)
|
||
|
{
|
||
|
exp = -1074;
|
||
|
}
|
||
|
}
|
||
|
else if (exp == 0x7FF)
|
||
|
{
|
||
|
// NaN or Inifite.
|
||
|
fFinite = false;
|
||
|
exp = int.MaxValue;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fFinite = true;
|
||
|
man |= 0x0010000000000000;
|
||
|
exp -= 1075;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static double GetDoubleFromParts(int sign, int exp, ulong man)
|
||
|
{
|
||
|
DoubleUlong du;
|
||
|
du.Dbl = 0;
|
||
|
|
||
|
if (man == 0)
|
||
|
{
|
||
|
du.Uu = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Normalize so that 0x0010 0000 0000 0000 is the highest bit set.
|
||
|
var cbitShift = CbitHighZero(man) - 11;
|
||
|
if (cbitShift < 0)
|
||
|
{
|
||
|
man >>= -cbitShift;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
man <<= cbitShift;
|
||
|
}
|
||
|
|
||
|
exp -= cbitShift;
|
||
|
Debug.Assert((man & 0xFFF0000000000000) == 0x0010000000000000);
|
||
|
|
||
|
// Move the point to just behind the leading 1: 0x001.0 0000 0000 0000
|
||
|
// (52 bits) and skew the exponent (by 0x3FF == 1023).
|
||
|
exp += 1075;
|
||
|
|
||
|
if (exp >= 0x7FF)
|
||
|
{
|
||
|
// Infinity.
|
||
|
du.Uu = 0x7FF0000000000000;
|
||
|
}
|
||
|
else if (exp <= 0)
|
||
|
{
|
||
|
// Denormalized.
|
||
|
exp--;
|
||
|
if (exp < -52)
|
||
|
{
|
||
|
// Underflow to zero.
|
||
|
du.Uu = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
du.Uu = man >> -exp;
|
||
|
Debug.Assert(du.Uu != 0);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Mask off the implicit high bit.
|
||
|
du.Uu = (man & 0x000FFFFFFFFFFFFF) | ((ulong)exp << 52);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (sign < 0)
|
||
|
{
|
||
|
du.Uu |= 0x8000000000000000;
|
||
|
}
|
||
|
|
||
|
return du.Dbl;
|
||
|
}
|
||
|
|
||
|
// Do an in-place two's complement. "Dangerous" because it causes
|
||
|
// a mutation and needs to be used with care for immutable types.
|
||
|
public static void DangerousMakeTwosComplement(uint[] d)
|
||
|
{
|
||
|
if (d != null && d.Length > 0)
|
||
|
{
|
||
|
d[0] = ~d[0] + 1;
|
||
|
|
||
|
var i = 1;
|
||
|
// first do complement and +1 as long as carry is needed
|
||
|
for (; d[i - 1] == 0 && i < d.Length; i++)
|
||
|
{
|
||
|
d[i] = ~d[i] + 1;
|
||
|
}
|
||
|
// now ones complement is sufficient
|
||
|
for (; i < d.Length; i++)
|
||
|
{
|
||
|
d[i] = ~d[i];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static ulong MakeUlong(uint uHi, uint uLo)
|
||
|
{
|
||
|
return ((ulong)uHi << _uintBitCount) | uLo;
|
||
|
}
|
||
|
|
||
|
public static uint Abs(int a)
|
||
|
{
|
||
|
var mask = (uint)(a >> 31);
|
||
|
return ((uint)a ^ mask) - mask;
|
||
|
}
|
||
|
|
||
|
public static uint CombineHash(uint u1, uint u2)
|
||
|
{
|
||
|
return ((u1 << 7) | (u1 >> 25)) ^ u2;
|
||
|
}
|
||
|
|
||
|
public static int CombineHash(int n1, int n2)
|
||
|
{
|
||
|
return (int)CombineHash((uint)n1, (uint)n2);
|
||
|
}
|
||
|
|
||
|
public static int CbitHighZero(uint u)
|
||
|
{
|
||
|
if (u == 0)
|
||
|
{
|
||
|
return 32;
|
||
|
}
|
||
|
|
||
|
var cbit = 0;
|
||
|
if ((u & 0xFFFF0000) == 0)
|
||
|
{
|
||
|
cbit += 16;
|
||
|
u <<= 16;
|
||
|
}
|
||
|
if ((u & 0xFF000000) == 0)
|
||
|
{
|
||
|
cbit += 8;
|
||
|
u <<= 8;
|
||
|
}
|
||
|
if ((u & 0xF0000000) == 0)
|
||
|
{
|
||
|
cbit += 4;
|
||
|
u <<= 4;
|
||
|
}
|
||
|
if ((u & 0xC0000000) == 0)
|
||
|
{
|
||
|
cbit += 2;
|
||
|
u <<= 2;
|
||
|
}
|
||
|
if ((u & 0x80000000) == 0)
|
||
|
{
|
||
|
cbit += 1;
|
||
|
}
|
||
|
|
||
|
return cbit;
|
||
|
}
|
||
|
|
||
|
public static int CbitHighZero(ulong uu)
|
||
|
{
|
||
|
if ((uu & 0xFFFFFFFF00000000) == 0)
|
||
|
{
|
||
|
return 32 + CbitHighZero((uint)uu);
|
||
|
}
|
||
|
|
||
|
return CbitHighZero((uint)(uu >> 32));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|