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
// 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 |