Skip to content

Instantly share code, notes, and snippets.

@mjs3339
Last active August 27, 2021 19:10
Show Gist options
  • Save mjs3339/6f2706fe712178cfb92725a5b14583f2 to your computer and use it in GitHub Desktop.
Save mjs3339/6f2706fe712178cfb92725a5b14583f2 to your computer and use it in GitHub Desktop.
Arbitrary Precision Signed BigDecimal
using System;
using System.Diagnostics;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Text;
[Serializable]
[DebuggerDisplay("{DDisplay}")]
public struct BigDecimal : IComparable, IComparable<BigDecimal>, IEquatable<BigDecimal>
{
private const int MaxFactorials = 200;
private static int _bitWidth = 64;
public static float MaxPrecision = _bitWidth / 64f * 20f;
private static readonly BigInteger DoublePrecision = BigInteger.Pow(10, 308);
private static readonly BigInteger DoubleMaxValue = (BigInteger)double.MaxValue;
private static readonly BigInteger DoubleMinValue = (BigInteger)double.MinValue;
private static readonly BigInteger DecimalPrecision = BigInteger.Pow(10, 28);
private static readonly BigInteger DecimalMaxValue = (BigInteger)decimal.MaxValue;
private static readonly BigInteger DecimalMinValue = (BigInteger)decimal.MinValue;
private static BigDecimal[] Factorials;
private int _scale;
private BigInteger _unscaledValue;
public BigDecimal(BigInteger value) : this(value, 0)
{
}
public BigDecimal(xIntX value) : this((BigInteger)value, 0)
{
}
public BigDecimal(BigIntX value) : this((BigInteger)value, 0)
{
}
public BigDecimal(BigInteger value, int scale)
{
_unscaledValue = value;
_scale = scale;
}
public BigDecimal(long value) : this(value, 0)
{
}
public BigDecimal(double value) : this((decimal)value)
{
}
public BigDecimal(float value) : this((decimal)value)
{
}
public BigDecimal(byte[] value)
{
var number = new byte[value.Length - 4];
var flags = new byte[4];
Array.Copy(value, 0, number, 0, number.Length);
Array.Copy(value, value.Length - 4, flags, 0, 4);
_unscaledValue = new BigInteger(number);
_scale = BitConverter.ToInt32(flags, 0);
}
public BigDecimal(BigRational value)
{
var num = (BigDecimal)value.Numerator;
var den = (BigDecimal)value.Denominator;
var bigDecRes = num / den;
_unscaledValue = bigDecRes._unscaledValue;
_scale = bigDecRes.Scale;
}
public BigDecimal(BigDecimal value)
{
_unscaledValue = value._unscaledValue;
_scale = value.Scale;
}
public BigDecimal(decimal value)
{
var bytes = new byte[16];
var bits = decimal.GetBits(value);
var lo = bits[0];
var mid = bits[1];
var hi = bits[2];
var flags = bits[3];
bytes[0] = (byte)lo;
bytes[1] = (byte)(lo >> 8);
bytes[2] = (byte)(lo >> 0x10);
bytes[3] = (byte)(lo >> 0x18);
bytes[4] = (byte)mid;
bytes[5] = (byte)(mid >> 8);
bytes[6] = (byte)(mid >> 0x10);
bytes[7] = (byte)(mid >> 0x18);
bytes[8] = (byte)hi;
bytes[9] = (byte)(hi >> 8);
bytes[10] = (byte)(hi >> 0x10);
bytes[11] = (byte)(hi >> 0x18);
bytes[12] = (byte)flags;
bytes[13] = (byte)(flags >> 8);
bytes[14] = (byte)(flags >> 0x10);
bytes[15] = (byte)(flags >> 0x18);
var unscaledValueBytes = new byte[12];
Array.Copy(bytes, unscaledValueBytes, unscaledValueBytes.Length);
var unscaledValue = new BigInteger(unscaledValueBytes);
var scale = bytes[14];
if (bytes[15] == 128)
unscaledValue *= BigInteger.MinusOne;
_unscaledValue = unscaledValue;
_scale = scale;
}
public BigDecimal(string value)
{
if (!value.ContainsOnly("0123456789+-.eE"))
throw new Exception($"Input value must only contain these '0123456789+-.eE', value'{value}");
var len = value.Length;
var start = 0;
var point = 0;
var dot = -1;
var negative = false;
if (value[0] == '+')
{
++start;
++point;
}
else if (value[0] == '-')
{
++start;
++point;
negative = true;
}
while (point < len)
{
var c = value[point];
if (c == '.')
{
if (dot >= 0)
throw new Exception($"There are multiple '.'s in the value {value}");
dot = point;
}
else if (c == 'e' || c == 'E')
{
break;
}
++point;
}
string val;
if (dot >= 0)
{
val = value.Substring(start, dot) + value.Substring(dot + 1, point - (dot + 1));
_scale = point - 1 - dot;
}
else
{
val = value.Substring(start, point);
_scale = 0;
}
if (val.Length == 0)
throw new Exception($"There are no digits in the value {value}");
if (negative)
val = "-" + val;
_unscaledValue = val.BigIntegerBase10();
if (point < len)
try
{
point++;
switch (value[point])
{
case '+':
{
point++;
if (point >= len)
throw new Exception($"No exponent following e or E. Value {value}");
var scale = value.Substring(point);
_scale -= int.Parse(scale);
return;
}
case '-':
{
point++;
if (point >= len)
throw new Exception($"No exponent following e or E. Value {value}");
var scale = value.Substring(point);
_scale += int.Parse(scale);
return;
}
default:
throw new Exception($"Malformed exponent in value {value}");
}
}
catch (Exception ex)
{
throw new Exception($"Malformed exponent in value {value}");
}
}
public int BitWidth
{
get => _bitWidth;
set
{
_bitWidth = value;
MaxPrecision = _bitWidth / 64f * 20f;
}
}
private string DDisplay => ToString();
public static BigDecimal Zero
{
get;
} = new(BigInteger.Zero);
public static BigDecimal One
{
get;
} = new(BigInteger.One);
public static BigDecimal MinusOne
{
get;
} = new(BigInteger.MinusOne);
public bool IsEven => _unscaledValue.IsEven;
public bool IsOne => _unscaledValue.IsOne;
public bool IsPowerOfTwo => _unscaledValue.IsPowerOfTwo;
public bool IsZero => _unscaledValue.IsZero;
public int Sign => _unscaledValue.Sign;
public int Scale
{
get => _scale;
private set => _scale = value;
}
public BigInteger UnscaledValue => _unscaledValue;
public BigDecimal WholePart => BigInteger.Divide(_unscaledValue, BigInteger.Pow(10, Scale));
public BigDecimal FractionalPart => this - WholePart;
public int DecimalPlaces
{
get
{
var a = new BigDecimal(_unscaledValue);
var dPlaces = 0;
if (a.Sign == 0)
return 1;
if (a.Sign < 0)
try
{
a = -a;
}
catch (Exception ex)
{
return 0;
}
var biRadix = new BigDecimal(10);
while (a > 0)
try
{
a /= biRadix;
dPlaces++;
}
catch (Exception ex)
{
break;
}
return dPlaces;
}
}
int IComparable.CompareTo(object obj)
{
if (obj == null)
return 1;
if (!(obj is BigDecimal))
throw new Exception("Argument must be of type BigDecimal.");
return Compare(this, (BigDecimal)obj);
}
public int CompareTo(BigDecimal other)
{
return Compare(this, other);
}
public bool Equals(BigDecimal other)
{
return _unscaledValue == other._unscaledValue && _scale == other.Scale;
}
public override bool Equals(object obj)
{
if (obj == null)
return false;
if (!(obj is BigDecimal))
return false;
return Equals((BigDecimal)obj);
}
public static BigDecimal Round(BigDecimal number, int decimalPlaces)
{
BigDecimal power = BigInteger.Pow(10, decimalPlaces);
number *= power;
return number >= 0 ? (BigInteger)(number + 0.5) / power : (BigInteger)(number - 0.5) / power;
}
public void Round(int decimalPlaces)
{
var number = this;
BigDecimal power = BigInteger.Pow(10, decimalPlaces);
number *= power;
var n = number >= 0 ? (BigInteger)(number + 0.5) / power : (BigInteger)(number - 0.5) / power;
_unscaledValue = n._unscaledValue;
_scale = n.Scale;
}
public override int GetHashCode()
{
return UnscaledValue.GetHashCode() ^ _scale.GetHashCode();
}
public override string ToString()
{
return ToStringInt();
}
public string ToString(IFormatProvider provider)
{
var number = _unscaledValue.ToString("G");
if (_scale > 0 && WholePart != 0 && number.Length - _scale >= 0)
return number.Insert(number.Length - _scale, ".");
return _unscaledValue.ToString(provider);
}
private string ToStringInt()
{
var number = _unscaledValue.ToString("G");
if (_scale > 0 && WholePart != 0 && number.Length - _scale >= 0)
return number.Insert(number.Length - _scale, ".");
StringBuilder buf;
var intString = _unscaledValue.ToString();
var insertionPoint = intString.Length - _scale;
if (insertionPoint == 0)
return (Sign < 0 ? "-0." : "0.") + intString;
if (insertionPoint > 0)
{
buf = new StringBuilder(intString);
buf.Insert(insertionPoint, '.');
if (Sign < 0)
buf.Insert(0, '-');
}
else
{
buf = new StringBuilder(3 - insertionPoint + intString.Length);
buf.Append(Sign < 0 ? "-0." : "0.");
for (var i = 0; i < -insertionPoint; i++)
buf.Append('0');
buf.Append(intString);
}
if (_scale == 0)
buf.Append("0");
return buf.ToString();
}
public static BigDecimal Parse(string value)
{
return new BigDecimal(value);
}
public byte[] ToByteArray()
{
var unscaledValue = _unscaledValue.ToByteArray();
var scale = BitConverter.GetBytes(_scale);
var bytes = new byte[unscaledValue.Length + scale.Length];
Array.Copy(unscaledValue, 0, bytes, 0, unscaledValue.Length);
Array.Copy(scale, 0, bytes, unscaledValue.Length, scale.Length);
return bytes;
}
public (byte[] unscaledValue, byte[] scale) ToByteArrays()
{
return (_unscaledValue.ToByteArray(), BitConverter.GetBytes(_scale));
}
public static BigDecimal Abs(BigDecimal value)
{
return value._unscaledValue.Sign < 0 ? -value : value;
}
public static BigDecimal Negate(BigDecimal value)
{
return new BigDecimal(BigInteger.Negate(value._unscaledValue), value.Scale);
}
public static BigDecimal Add(BigDecimal x, BigDecimal y)
{
return x + y;
}
public static BigDecimal Subtract(BigDecimal x, BigDecimal y)
{
return x - y;
}
public static BigDecimal Multiply(BigDecimal x, BigDecimal y)
{
return x * y;
}
public static BigDecimal Divide(BigDecimal dividend, BigDecimal divisor)
{
return dividend / divisor;
}
public static BigDecimal Pow(BigDecimal baseValue, BigInteger exponent)
{
if (exponent.Sign == 0)
return One;
if (exponent.Sign < 0)
{
if (baseValue == Zero)
throw new Exception("Cannot raise zero to a negative power.");
baseValue = One / baseValue;
exponent = BigInteger.Negate(exponent);
}
var result = baseValue;
while (exponent > BigInteger.One)
{
result *= baseValue;
exponent--;
}
return result;
}
public static int Compare(BigDecimal r1, BigDecimal r2)
{
return (r1 - r2)._unscaledValue.Sign;
}
public static bool operator ==(BigDecimal x, BigDecimal y)
{
return x.Equals(y);
}
public static bool operator !=(BigDecimal x, BigDecimal y)
{
return !x.Equals(y);
}
public static bool operator <(BigDecimal x, BigDecimal y)
{
return Compare(x, y) < 0;
}
public static bool operator <=(BigDecimal x, BigDecimal y)
{
return Compare(x, y) <= 0;
}
public static bool operator >(BigDecimal x, BigDecimal y)
{
return Compare(x, y) > 0;
}
public static bool operator >=(BigDecimal x, BigDecimal y)
{
return Compare(x, y) >= 0;
}
public static BigDecimal operator +(BigDecimal value)
{
return value;
}
public static BigDecimal operator -(BigDecimal value)
{
return new BigDecimal(-value._unscaledValue, value.Scale);
}
public static BigDecimal operator ++(BigDecimal value)
{
return value + One;
}
public static BigDecimal operator --(BigDecimal value)
{
return value - One;
}
public static BigDecimal operator +(BigDecimal left, BigDecimal right)
{
BigDecimal ret;
if (left.Scale >= right.Scale)
{
ret = left;
}
else
{
var value = left._unscaledValue * BigInteger.Pow(10, right.Scale - left.Scale);
ret = new BigDecimal(value, right.Scale);
}
BigDecimal ret1;
if (right.Scale >= left.Scale)
{
ret1 = right;
}
else
{
var value1 = right._unscaledValue * BigInteger.Pow(10, left.Scale - right.Scale);
ret1 = new BigDecimal(value1, left.Scale);
}
return new BigDecimal(ret._unscaledValue + ret1._unscaledValue, ret.Scale);
}
public static BigDecimal operator -(BigDecimal left, BigDecimal right)
{
BigDecimal ret;
if (left.Scale >= right.Scale)
{
ret = left;
}
else
{
var value = left._unscaledValue * BigInteger.Pow(10, right.Scale - left.Scale);
ret = new BigDecimal(value, right.Scale);
}
BigDecimal ret1;
if (right.Scale >= left.Scale)
{
ret1 = right;
}
else
{
var value1 = right._unscaledValue * BigInteger.Pow(10, left.Scale - right.Scale);
ret1 = new BigDecimal(value1, left.Scale);
}
return new BigDecimal(ret._unscaledValue - ret1._unscaledValue, ret.Scale);
}
public static BigDecimal operator *(BigDecimal left, BigDecimal right)
{
return new BigDecimal(left._unscaledValue * right._unscaledValue, left.Scale + right.Scale);
}
public static BigDecimal operator /(BigDecimal left, BigDecimal right)
{
var value = left._unscaledValue;
var scale = left.Scale;
while (scale > 0 && value % 10 == 0)
{
value /= 10;
scale--;
}
var v1 = new BigDecimal(value, scale);
var value1 = right._unscaledValue;
var scale1 = right.Scale;
while (scale1 > 0 && value1 % 10 == 0)
{
value1 /= 10;
scale1--;
}
var v2 = new BigDecimal(value1, scale1);
while (v1.Scale > 0 || v2.Scale > 0)
{
if (v1.Scale > 0)
v1 = new BigDecimal(v1._unscaledValue, v1.Scale - 1);
else
v1 = new BigDecimal(v1._unscaledValue * 10, 0);
if (v2.Scale > 0)
v2 = new BigDecimal(v2._unscaledValue, v2.Scale - 1);
else
v2 = new BigDecimal(v2._unscaledValue * 10, 0);
}
var factor = 0;
var v1Value = v1._unscaledValue;
while (factor < (int)MaxPrecision && v1Value % v2._unscaledValue != 0)
{
v1Value *= 10;
factor++;
}
return new BigDecimal(v1Value / v2._unscaledValue, factor);
}
public static BigDecimal operator %(BigDecimal left, BigDecimal right)
{
var value = left._unscaledValue;
var scale = left.Scale;
while (scale > 0 && value % 10 == 0)
{
value /= 10;
scale--;
}
var v1 = new BigDecimal(value, scale);
var value1 = right._unscaledValue;
var scale1 = right.Scale;
while (scale1 > 0 && value1 % 10 == 0)
{
value1 /= 10;
scale1--;
}
var v2 = new BigDecimal(value1, scale1);
while (v1.Scale > 0 || v2.Scale > 0)
{
if (v1.Scale > 0)
v1 = new BigDecimal(v1._unscaledValue, v1.Scale - 1);
else
v1 = new BigDecimal(v1._unscaledValue * 10, 0);
if (v2.Scale > 0)
v2 = new BigDecimal(v2._unscaledValue, v2.Scale - 1);
else
v2 = new BigDecimal(v2._unscaledValue * 10, 0);
}
return new BigDecimal(v1._unscaledValue % v2._unscaledValue);
}
public static explicit operator sbyte(BigDecimal value)
{
return (sbyte)BigInteger.Divide(value._unscaledValue, BigInteger.Pow(10, value.Scale));
}
public static explicit operator ushort(BigDecimal value)
{
return (ushort)BigInteger.Divide(value._unscaledValue, BigInteger.Pow(10, value.Scale));
}
public static explicit operator uint(BigDecimal value)
{
return (uint)BigInteger.Divide(value._unscaledValue, BigInteger.Pow(10, value.Scale));
}
public static explicit operator ulong(BigDecimal value)
{
return (ulong)BigInteger.Divide(value._unscaledValue, BigInteger.Pow(10, value.Scale));
}
public static explicit operator byte(BigDecimal value)
{
return (byte)BigInteger.Divide(value._unscaledValue, BigInteger.Pow(10, value.Scale));
}
public static explicit operator short(BigDecimal value)
{
return (short)BigInteger.Divide(value._unscaledValue, BigInteger.Pow(10, value.Scale));
}
public static explicit operator int(BigDecimal value)
{
return (int)BigInteger.Divide(value._unscaledValue, BigInteger.Pow(10, value.Scale));
}
public static explicit operator long(BigDecimal value)
{
return (long)BigInteger.Divide(value._unscaledValue, BigInteger.Pow(10, value.Scale));
}
public static explicit operator BigInteger(BigDecimal value)
{
return BigInteger.Divide(value._unscaledValue, BigInteger.Pow(10, value.Scale));
}
public static explicit operator xIntX(BigDecimal value)
{
return xIntX.Divide(value._unscaledValue, BigInteger.Pow(10, value.Scale));
}
public static explicit operator BigIntX(BigDecimal value)
{
return BigIntX.Divide(value._unscaledValue, BigInteger.Pow(10, value.Scale));
}
public static explicit operator float(BigDecimal value)
{
return (float)(double)value;
}
public static explicit operator double(BigDecimal value)
{
var factor = BigInteger.Pow(10, value.Scale);
if (SafeCastToDouble(value._unscaledValue) && SafeCastToDouble(factor))
return (double)value._unscaledValue / (double)factor;
var dnv = value._unscaledValue * DoublePrecision / factor;
if (dnv.IsZero)
return value.Sign < 0 ? BitConverter.Int64BitsToDouble(unchecked((long)0x8000000000000000)) : 0d;
double result = 0;
var isDouble = false;
var scale = 308;
while (scale > 0)
{
if (!isDouble)
{
if (SafeCastToDouble(dnv))
{
result = (double)dnv;
isDouble = true;
}
else
{
dnv /= 10;
}
}
result /= 10;
scale--;
}
if (!isDouble)
return value.Sign < 0 ? double.NegativeInfinity : double.PositiveInfinity;
return result;
}
public static explicit operator decimal(BigDecimal value)
{
var factor = BigInteger.Pow(10, value.Scale);
if (SafeCastToDecimal(value._unscaledValue) && SafeCastToDecimal(factor))
return (decimal)value._unscaledValue / (decimal)factor;
var dnv = value._unscaledValue * DecimalPrecision / factor;
if (dnv.IsZero)
return decimal.Zero;
for (var scale = 28; scale >= 0; scale--)
if (!SafeCastToDecimal(dnv))
{
dnv /= 10;
}
else
{
var dec = new DecimalUInt32();
dec.dec = (decimal)dnv;
dec.flags = (dec.flags & ~0x00FF0000) | (scale << 16);
return dec.dec;
}
throw new Exception("Value was either too large or too small for a Decimal.");
}
public static implicit operator BigDecimal(sbyte value)
{
return new BigDecimal(value);
}
public static implicit operator BigDecimal(ushort value)
{
return new BigDecimal(value);
}
public static implicit operator BigDecimal(uint value)
{
return new BigDecimal(value);
}
public static implicit operator BigDecimal(ulong value)
{
return new BigDecimal((BigInteger)value);
}
public static implicit operator BigDecimal(byte value)
{
return new BigDecimal(value);
}
public static implicit operator BigDecimal(short value)
{
return new BigDecimal(value);
}
public static implicit operator BigDecimal(int value)
{
return new BigDecimal(value);
}
public static implicit operator BigDecimal(long value)
{
return new BigDecimal(value);
}
public static implicit operator BigDecimal(BigInteger value)
{
return new BigDecimal(value);
}
public static implicit operator BigDecimal(xIntX value)
{
return new BigDecimal(value);
}
public static implicit operator BigDecimal(BigIntX value)
{
return new BigDecimal(value);
}
public static implicit operator BigDecimal(float value)
{
return new BigDecimal(value);
}
public static implicit operator BigDecimal(double value)
{
return new BigDecimal(value);
}
public static implicit operator BigDecimal(decimal value)
{
return new BigDecimal(value);
}
public static implicit operator BigDecimal(BigRational value)
{
return new BigDecimal(value);
}
private static bool SafeCastToDouble(BigInteger value)
{
return DoubleMinValue <= value && value <= DoubleMaxValue;
}
private static bool SafeCastToDecimal(BigInteger value)
{
return DecimalMinValue <= value && value <= DecimalMaxValue;
}
private static BigInteger GetLastDigit(BigInteger value)
{
return value % new BigInteger(10);
}
private static int GetNumberOfDigits(BigInteger value)
{
return BigInteger.Abs(value).ToString().Length;
}
private static BigDecimal Factorial(BigDecimal x)
{
BigDecimal r = 1;
BigDecimal c = 1;
while (c <= x)
{
r *= c;
c++;
}
return r;
}
public static BigDecimal Exp(BigDecimal x)
{
BigDecimal r = 0;
BigDecimal r1 = 0;
var k = 0;
while (true)
{
r += Pow(x, k) / Factorial(k);
if (r == r1)
break;
r1 = r;
k++;
}
return r;
}
public static BigDecimal Sine(BigDecimal ar, int n)
{
if (Factorials == null)
{
Factorials = new BigDecimal[MaxFactorials];
for (var i = 0; i < MaxFactorials; i++)
Factorials[i] = new BigDecimal(0, 0);
for (var i = 1; i < MaxFactorials + 1; i++)
Factorials[i - 1] = Factorial(i);
}
var sin = ar;
for (var i = 1; i <= n; i++)
{
var trm = Pow(ar, i * 2 + 1);
trm /= Factorials[i * 2];
if ((i & 1) == 1)
sin -= trm;
else
sin += trm;
}
return sin;
}
public static BigDecimal Atan(BigDecimal ar, int n)
{
var atan = ar;
for (var i = 1; i <= n; i++)
{
var trm = Pow(ar, i * 2 + 1);
trm /= i * 2;
if ((i & 1) == 1)
atan -= trm;
else
atan += trm;
}
return atan;
}
public static BigDecimal Cosine(BigDecimal ar, int n)
{
if (Factorials == null)
{
Factorials = new BigDecimal[MaxFactorials];
for (var i = 0; i < MaxFactorials; i++)
Factorials[i] = new BigDecimal(0, 0);
for (var i = 1; i < MaxFactorials + 1; i++)
Factorials[i - 1] = Factorial(i);
}
BigDecimal cos = 1.0;
for (var i = 1; i <= n; i++)
{
var trm = Pow(ar, i * 2);
trm /= Factorials[i * 2 - 1];
if ((i & 1) == 1)
cos -= trm;
else
cos += trm;
}
return cos;
}
public static BigDecimal GetE(int n)
{
BigDecimal e = 1.0;
var c = n;
while (c > 0)
{
BigDecimal f = 0;
if (c == 1)
{
f = 1;
}
else
{
var i = c - 1;
f = c;
while (i > 0)
{
f *= i;
i--;
}
}
c--;
e += 1.0 / f;
}
return e;
}
public static BigDecimal Tangent(BigDecimal ar, int n)
{
return Sine(ar, n) / Cosine(ar, n);
}
public static BigDecimal CoTangent(BigDecimal ar, int n)
{
return Cosine(ar, n) / Sine(ar, n);
}
public static BigDecimal Secant(BigDecimal ar, int n)
{
return 1.0 / Cosine(ar, n);
}
public static BigDecimal NthRoot(BigDecimal value, int nth)
{
BigDecimal lx;
var a = value;
var n = nth;
BigDecimal s = 1.0;
do
{
var t = s;
lx = a / Pow(s, n - 1);
var r = (n - 1) * s;
s = (lx + r) / n;
} while (lx != s);
return s;
}
public static BigDecimal LogN(BigDecimal value)
{
var E = GetE(MaxFactorials);
BigDecimal a;
var p = value;
BigDecimal n = 0.0;
while (p >= E)
{
p /= E;
n++;
}
n += p / E;
p = value;
do
{
a = n;
var lx = p / Exp(n - 1.0);
var r = (n - 1.0) * E;
n = (lx + r) / E;
} while (n != a);
return n;
}
public static BigDecimal Log(BigDecimal n, int b)
{
return LogN(n) / LogN(b);
}
public static BigDecimal CoSecant(BigDecimal ar, int n)
{
return 1.0 / Sine(ar, n);
}
public static BigDecimal Ceiling(BigDecimal value, int precision)
{
var v1 = new BigDecimal(value);
v1 = RemoveTrailingZeros(v1);
var diff = GetNumberOfDigits(v1._unscaledValue) - precision;
if (diff > 0)
{
for (var i = 0; i < diff; i++)
{
v1._unscaledValue = BigInteger.Divide(v1._unscaledValue, 10);
v1.Scale--;
}
if (v1._unscaledValue.Sign < 0)
v1._unscaledValue--;
else
v1._unscaledValue++;
}
return v1;
}
public static BigDecimal Floor(BigDecimal value, int precision)
{
var v1 = new BigDecimal(value);
v1 = RemoveTrailingZeros(v1);
var diff = GetNumberOfDigits(v1._unscaledValue) - precision;
if (diff > 0)
{
for (var i = 0; i < diff; i++)
{
v1._unscaledValue = BigInteger.Divide(v1._unscaledValue, 10);
v1.Scale--;
}
if (v1._unscaledValue.Sign > 0)
v1._unscaledValue--;
else
v1._unscaledValue++;
}
return v1;
}
private static BigDecimal RemoveTrailingZeros(BigDecimal value)
{
var v1 = new BigDecimal(value);
BigInteger remainder;
do
{
var shortened = BigInteger.DivRem(v1._unscaledValue, 10, out remainder);
if (remainder == BigInteger.Zero)
{
v1._unscaledValue = shortened;
v1.Scale--;
}
} while (remainder == BigInteger.Zero);
return v1;
}
public BigDecimal Min(BigDecimal value)
{
return CompareTo(value) <= 0 ? this : value;
}
public BigDecimal Max(BigDecimal value)
{
return CompareTo(value) >= 0 ? this : value;
}
public static BigDecimal Sqrt(BigDecimal value)
{
return BigRational.Sqrt(value);
}
[StructLayout(LayoutKind.Explicit)]
internal struct DecimalUInt32
{
[FieldOffset(0)] public decimal dec;
[FieldOffset(0)] public int flags;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment