747 lines
24 KiB
C#
747 lines
24 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Numerics;
|
|
|
|
namespace LibAC
|
|
{
|
|
[Serializable]
|
|
public class BigFloat : IComparable, IComparable<BigFloat>, IEquatable<BigFloat>
|
|
{
|
|
private BigInteger numerator;
|
|
private BigInteger denominator;
|
|
|
|
public static readonly BigFloat One = new BigFloat(1);
|
|
public static readonly BigFloat Zero = new BigFloat(0);
|
|
public static readonly BigFloat MinusOne = new BigFloat(-1);
|
|
public static readonly BigFloat OneHalf = new BigFloat(1, 2);
|
|
|
|
public int Sign
|
|
{
|
|
get
|
|
{
|
|
switch (numerator.Sign + denominator.Sign)
|
|
{
|
|
case 2:
|
|
case -2:
|
|
return 1;
|
|
case 0:
|
|
return -1;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//constructors
|
|
public BigFloat()
|
|
{
|
|
numerator = BigInteger.Zero;
|
|
denominator = BigInteger.One;
|
|
}
|
|
public BigFloat(string value)
|
|
{
|
|
BigFloat bf = Parse(value);
|
|
this.numerator = bf.numerator;
|
|
this.denominator = bf.denominator;
|
|
}
|
|
public BigFloat(BigInteger numerator, BigInteger denominator)
|
|
{
|
|
this.numerator = numerator;
|
|
if (denominator == 0)
|
|
throw new ArgumentException("denominator equals 0");
|
|
this.denominator = BigInteger.Abs(denominator);
|
|
}
|
|
public BigFloat(BigInteger value)
|
|
{
|
|
this.numerator = value;
|
|
this.denominator = BigInteger.One;
|
|
}
|
|
public BigFloat(BigFloat value)
|
|
{
|
|
if (BigFloat.Equals(value, null))
|
|
{
|
|
this.numerator = BigInteger.Zero;
|
|
this.denominator = BigInteger.One;
|
|
}
|
|
else
|
|
{
|
|
|
|
this.numerator = value.numerator;
|
|
this.denominator = value.denominator;
|
|
}
|
|
}
|
|
public BigFloat(ulong value)
|
|
{
|
|
numerator = new BigInteger(value);
|
|
denominator = BigInteger.One;
|
|
}
|
|
public BigFloat(long value)
|
|
{
|
|
numerator = new BigInteger(value);
|
|
denominator = BigInteger.One;
|
|
}
|
|
public BigFloat(uint value)
|
|
{
|
|
numerator = new BigInteger(value);
|
|
denominator = BigInteger.One;
|
|
}
|
|
public BigFloat(int value)
|
|
{
|
|
numerator = new BigInteger(value);
|
|
denominator = BigInteger.One;
|
|
}
|
|
public BigFloat(float value) : this(value.ToString("N99"))
|
|
{
|
|
}
|
|
public BigFloat(double value) : this(value.ToString("N99"))
|
|
{
|
|
}
|
|
public BigFloat(decimal value) : this(value.ToString("N99"))
|
|
{
|
|
}
|
|
|
|
//non-static methods
|
|
public BigFloat Add(BigFloat other)
|
|
{
|
|
if (BigFloat.Equals(other, null))
|
|
throw new ArgumentNullException("other");
|
|
|
|
this.numerator = this.numerator * other.denominator + other.numerator * this.denominator;
|
|
this.denominator *= other.denominator;
|
|
return this;
|
|
}
|
|
public BigFloat Subtract(BigFloat other)
|
|
{
|
|
if (BigFloat.Equals(other, null))
|
|
throw new ArgumentNullException("other");
|
|
|
|
this.numerator = this.numerator * other.denominator - other.numerator * this.denominator;
|
|
this.denominator *= other.denominator;
|
|
return this;
|
|
}
|
|
public BigFloat Multiply(BigFloat other)
|
|
{
|
|
if (BigFloat.Equals(other, null))
|
|
throw new ArgumentNullException("other");
|
|
|
|
this.numerator *= other.numerator;
|
|
this.denominator *= other.denominator;
|
|
return this;
|
|
}
|
|
public BigFloat Divide(BigFloat other)
|
|
{
|
|
if (BigInteger.Equals(other, null))
|
|
throw new ArgumentNullException("other");
|
|
if (other.numerator == 0)
|
|
throw new System.DivideByZeroException("other");
|
|
|
|
this.numerator *= other.denominator;
|
|
this.denominator *= other.numerator;
|
|
return this;
|
|
}
|
|
public BigFloat Remainder(BigFloat other)
|
|
{
|
|
if (BigInteger.Equals(other, null))
|
|
throw new ArgumentNullException("other");
|
|
|
|
//b = a mod n
|
|
//remainder = a - floor(a/n) * n
|
|
|
|
BigFloat result = this - Floor(this / other) * other;
|
|
|
|
this.numerator = result.numerator;
|
|
this.denominator = result.denominator;
|
|
|
|
|
|
return this;
|
|
}
|
|
public BigFloat DivideRemainder(BigFloat other, out BigFloat remainder)
|
|
{
|
|
this.Divide(other);
|
|
|
|
remainder = BigFloat.Remainder(this, other);
|
|
|
|
return this;
|
|
}
|
|
public BigFloat Pow(int exponent)
|
|
{
|
|
if (numerator.IsZero)
|
|
{
|
|
// Nothing to do
|
|
}
|
|
else if (exponent < 0)
|
|
{
|
|
BigInteger savedNumerator = numerator;
|
|
numerator = BigInteger.Pow(denominator, -exponent);
|
|
denominator = BigInteger.Pow(savedNumerator, -exponent);
|
|
}
|
|
else
|
|
{
|
|
numerator = BigInteger.Pow(numerator, exponent);
|
|
denominator = BigInteger.Pow(denominator, exponent);
|
|
}
|
|
|
|
return this;
|
|
}
|
|
public BigFloat Abs()
|
|
{
|
|
numerator = BigInteger.Abs(numerator);
|
|
return this;
|
|
}
|
|
public BigFloat Negate()
|
|
{
|
|
numerator = BigInteger.Negate(numerator);
|
|
return this;
|
|
}
|
|
public BigFloat Inverse()
|
|
{
|
|
BigInteger temp = numerator;
|
|
numerator = denominator;
|
|
denominator = temp;
|
|
return this;
|
|
}
|
|
public BigFloat Increment()
|
|
{
|
|
numerator += denominator;
|
|
return this;
|
|
}
|
|
public BigFloat Decrement()
|
|
{
|
|
numerator -= denominator;
|
|
return this;
|
|
}
|
|
public BigFloat Ceil()
|
|
{
|
|
if (numerator < 0)
|
|
numerator -= BigInteger.Remainder(numerator, denominator);
|
|
else
|
|
numerator += denominator - BigInteger.Remainder(numerator, denominator);
|
|
|
|
Factor();
|
|
return this;
|
|
}
|
|
public BigFloat Floor()
|
|
{
|
|
if (numerator < 0)
|
|
numerator += denominator - BigInteger.Remainder(numerator, denominator);
|
|
else
|
|
numerator -= BigInteger.Remainder(numerator, denominator);
|
|
|
|
Factor();
|
|
return this;
|
|
}
|
|
public BigFloat Round()
|
|
{
|
|
//get remainder. Over divisor see if it is > new BigFloat(0.5)
|
|
BigFloat value = BigFloat.Decimals(this);
|
|
|
|
if (value.CompareTo(OneHalf) >= 0)
|
|
this.Ceil();
|
|
else
|
|
this.Floor();
|
|
|
|
return this;
|
|
}
|
|
public BigFloat Truncate()
|
|
{
|
|
numerator -= BigInteger.Remainder(numerator, denominator);
|
|
Factor();
|
|
return this;
|
|
}
|
|
public BigFloat Decimals()
|
|
{
|
|
BigInteger result = BigInteger.Remainder(numerator, denominator);
|
|
|
|
return new BigFloat(result, denominator);
|
|
}
|
|
public BigFloat ShiftDecimalLeft(int shift)
|
|
{
|
|
if (shift < 0)
|
|
return ShiftDecimalRight(-shift);
|
|
|
|
numerator *= BigInteger.Pow(10, shift);
|
|
return this;
|
|
}
|
|
public BigFloat ShiftDecimalRight(int shift)
|
|
{
|
|
if (shift < 0)
|
|
return ShiftDecimalLeft(-shift);
|
|
denominator *= BigInteger.Pow(10, shift);
|
|
return this;
|
|
}
|
|
public double Sqrt()
|
|
{
|
|
return Math.Pow(10, BigInteger.Log10(numerator) / 2) / Math.Pow(10, BigInteger.Log10(denominator) / 2);
|
|
}
|
|
public double Log10()
|
|
{
|
|
return BigInteger.Log10(numerator) - BigInteger.Log10(denominator);
|
|
}
|
|
public double Log(double baseValue)
|
|
{
|
|
return BigInteger.Log(numerator, baseValue) - BigInteger.Log(numerator, baseValue);
|
|
}
|
|
public override string ToString()
|
|
{
|
|
//default precision = 100
|
|
return ToString(100);
|
|
}
|
|
|
|
public int GetActualDecimalCount()
|
|
{
|
|
Factor();
|
|
BigInteger remain;
|
|
BigInteger res = BigInteger.DivRem(numerator, denominator, out remain);
|
|
if (remain == 0) return 0;
|
|
|
|
BigInteger decimals = (numerator * BigInteger.Pow(10, 100)) / denominator;
|
|
if (decimals == 0) return 0;
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
while (decimals > 0)
|
|
{
|
|
sb.Append(decimals % 10);
|
|
decimals /= 10;
|
|
}
|
|
return sb.Length;
|
|
}
|
|
public string ToString(int precision, bool trailingZeros = false)
|
|
{
|
|
Factor();
|
|
|
|
BigInteger remainder;
|
|
BigInteger result = BigInteger.DivRem(numerator, denominator, out remainder);
|
|
|
|
if (remainder == 0 && trailingZeros)
|
|
return result + ".0";
|
|
else if (remainder == 0)
|
|
return result.ToString();
|
|
|
|
|
|
BigInteger decimals = (numerator * BigInteger.Pow(10, precision)) / denominator;
|
|
|
|
if (decimals == 0 && trailingZeros)
|
|
return result + ".0";
|
|
else if (decimals == 0)
|
|
return result.ToString();
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
while (precision-- > 0 && decimals > 0)
|
|
{
|
|
sb.Append(decimals % 10);
|
|
decimals /= 10;
|
|
}
|
|
|
|
if (trailingZeros)
|
|
return result + "." + new string(sb.ToString().Reverse().ToArray());
|
|
else
|
|
return result + "." + new string(sb.ToString().Reverse().ToArray()).TrimEnd(new char[] { '0' });
|
|
|
|
|
|
}
|
|
public string ToMixString()
|
|
{
|
|
Factor();
|
|
|
|
BigInteger remainder;
|
|
BigInteger result = BigInteger.DivRem(numerator, denominator, out remainder);
|
|
|
|
if (remainder == 0)
|
|
return result.ToString();
|
|
else
|
|
return result + ", " + remainder + "/" + denominator;
|
|
}
|
|
|
|
public string ToRationalString()
|
|
{
|
|
Factor();
|
|
|
|
return numerator + " / " + denominator;
|
|
}
|
|
public int CompareTo(BigFloat other)
|
|
{
|
|
if (BigFloat.Equals(other, null))
|
|
throw new ArgumentNullException("other");
|
|
|
|
//Make copies
|
|
BigInteger one = this.numerator;
|
|
BigInteger two = other.numerator;
|
|
|
|
//cross multiply
|
|
one *= other.denominator;
|
|
two *= this.denominator;
|
|
|
|
//test
|
|
return BigInteger.Compare(one, two);
|
|
}
|
|
public int CompareTo(object other)
|
|
{
|
|
if (other == null)
|
|
throw new ArgumentNullException("other");
|
|
|
|
if (!(other is BigFloat))
|
|
throw new System.ArgumentException("other is not a BigFloat");
|
|
|
|
return CompareTo((BigFloat)other);
|
|
}
|
|
public override bool Equals(object other)
|
|
{
|
|
if (other == null || GetType() != other.GetType())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return this.numerator == ((BigFloat)other).numerator && this.denominator == ((BigFloat)other).denominator;
|
|
}
|
|
public bool Equals(BigFloat other)
|
|
{
|
|
return (other.numerator == this.numerator && other.denominator == this.denominator);
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
return base.GetHashCode();
|
|
}
|
|
|
|
//static methods
|
|
public static bool Equals(object left, object right)
|
|
{
|
|
if (left == null && right == null) return true;
|
|
else if (left == null || right == null) return false;
|
|
else if (left.GetType() != right.GetType()) return false;
|
|
else
|
|
return (((BigInteger)left).Equals((BigInteger)right));
|
|
}
|
|
public static string ToString(BigFloat value)
|
|
{
|
|
return value.ToString();
|
|
}
|
|
|
|
public static BigFloat Inverse(BigFloat value)
|
|
{
|
|
return (new BigFloat(value)).Inverse();
|
|
}
|
|
public static BigFloat Decrement(BigFloat value)
|
|
{
|
|
return (new BigFloat(value)).Decrement();
|
|
}
|
|
public static BigFloat Negate(BigFloat value)
|
|
{
|
|
return (new BigFloat(value)).Negate();
|
|
}
|
|
public static BigFloat Increment(BigFloat value)
|
|
{
|
|
return (new BigFloat(value)).Increment();
|
|
}
|
|
public static BigFloat Abs(BigFloat value)
|
|
{
|
|
return (new BigFloat(value)).Abs();
|
|
}
|
|
public static BigFloat Add(BigFloat left, BigFloat right)
|
|
{
|
|
return (new BigFloat(left)).Add(right);
|
|
}
|
|
public static BigFloat Subtract(BigFloat left, BigFloat right)
|
|
{
|
|
return (new BigFloat(left)).Subtract(right);
|
|
}
|
|
public static BigFloat Multiply(BigFloat left, BigFloat right)
|
|
{
|
|
return (new BigFloat(left)).Multiply(right);
|
|
}
|
|
public static BigFloat Divide(BigFloat left, BigFloat right)
|
|
{
|
|
return (new BigFloat(left)).Divide(right);
|
|
}
|
|
public static BigFloat Pow(BigFloat value, int exponent)
|
|
{
|
|
return (new BigFloat(value)).Pow(exponent);
|
|
}
|
|
public static BigFloat Remainder(BigFloat left, BigFloat right)
|
|
{
|
|
return (new BigFloat(left)).Remainder(right);
|
|
}
|
|
public static BigFloat DivideRemainder(BigFloat left, BigFloat right, out BigFloat remainder)
|
|
{
|
|
return (new BigFloat(left)).DivideRemainder(right, out remainder);
|
|
}
|
|
public static BigFloat Decimals(BigFloat value)
|
|
{
|
|
return value.Decimals();
|
|
}
|
|
public static BigFloat Truncate(BigFloat value)
|
|
{
|
|
return (new BigFloat(value)).Truncate();
|
|
}
|
|
public static BigFloat Ceil(BigFloat value)
|
|
{
|
|
return (new BigFloat(value)).Ceil();
|
|
}
|
|
public static BigFloat Floor(BigFloat value)
|
|
{
|
|
return (new BigFloat(value)).Floor();
|
|
}
|
|
public static BigFloat Round(BigFloat value)
|
|
{
|
|
return (new BigFloat(value)).Round();
|
|
}
|
|
public static BigFloat Parse(string value)
|
|
{
|
|
if (value == null)
|
|
throw new ArgumentNullException("value");
|
|
|
|
value.Trim();
|
|
value = value.Replace(",", "");
|
|
int pos = value.IndexOf('.');
|
|
value = value.Replace(".", "");
|
|
|
|
if (pos < 0)
|
|
{
|
|
//no decimal point
|
|
BigInteger numerator = BigInteger.Parse(value);
|
|
return (new BigFloat(numerator)).Factor();
|
|
}
|
|
else
|
|
{
|
|
//decimal point (length - pos - 1)
|
|
BigInteger numerator = BigInteger.Parse(value);
|
|
BigInteger denominator = BigInteger.Pow(10, value.Length - pos);
|
|
|
|
return (new BigFloat(numerator, denominator)).Factor();
|
|
}
|
|
}
|
|
public static BigFloat ShiftDecimalLeft(BigFloat value, int shift)
|
|
{
|
|
return (new BigFloat(value)).ShiftDecimalLeft(shift);
|
|
}
|
|
public static BigFloat ShiftDecimalRight(BigFloat value, int shift)
|
|
{
|
|
return (new BigFloat(value)).ShiftDecimalRight(shift);
|
|
}
|
|
public static bool TryParse(string value, out BigFloat result)
|
|
{
|
|
try
|
|
{
|
|
result = BigFloat.Parse(value);
|
|
return true;
|
|
}
|
|
catch (ArgumentNullException)
|
|
{
|
|
result = null;
|
|
return false;
|
|
}
|
|
catch (FormatException)
|
|
{
|
|
result = null;
|
|
return false;
|
|
}
|
|
}
|
|
public static int Compare(BigFloat left, BigFloat right)
|
|
{
|
|
if (BigFloat.Equals(left, null))
|
|
throw new ArgumentNullException("left");
|
|
if (BigFloat.Equals(right, null))
|
|
throw new ArgumentNullException("right");
|
|
|
|
return (new BigFloat(left)).CompareTo(right);
|
|
}
|
|
public static double Log10(BigFloat value)
|
|
{
|
|
return (new BigFloat(value)).Log10();
|
|
}
|
|
public static double Log(BigFloat value, double baseValue)
|
|
{
|
|
return (new BigFloat(value)).Log(baseValue);
|
|
}
|
|
public static double Sqrt(BigFloat value)
|
|
{
|
|
return (new BigFloat(value)).Sqrt();
|
|
}
|
|
|
|
public static BigFloat operator -(BigFloat value)
|
|
{
|
|
return (new BigFloat(value)).Negate();
|
|
}
|
|
public static BigFloat operator -(BigFloat left, BigFloat right)
|
|
{
|
|
return (new BigFloat(left)).Subtract(right);
|
|
}
|
|
public static BigFloat operator --(BigFloat value)
|
|
{
|
|
return value.Decrement();
|
|
}
|
|
public static BigFloat operator +(BigFloat left, BigFloat right)
|
|
{
|
|
return (new BigFloat(left)).Add(right);
|
|
}
|
|
public static BigFloat operator +(BigFloat value)
|
|
{
|
|
return (new BigFloat(value)).Abs();
|
|
}
|
|
public static BigFloat operator ++(BigFloat value)
|
|
{
|
|
return value.Increment();
|
|
}
|
|
public static BigFloat operator %(BigFloat left, BigFloat right)
|
|
{
|
|
return (new BigFloat(left)).Remainder(right);
|
|
}
|
|
public static BigFloat operator *(BigFloat left, BigFloat right)
|
|
{
|
|
return (new BigFloat(left)).Multiply(right);
|
|
}
|
|
public static BigFloat operator /(BigFloat left, BigFloat right)
|
|
{
|
|
return (new BigFloat(left)).Divide(right);
|
|
}
|
|
public static BigFloat operator >>(BigFloat value, int shift)
|
|
{
|
|
return (new BigFloat(value)).ShiftDecimalRight(shift);
|
|
}
|
|
public static BigFloat operator <<(BigFloat value, int shift)
|
|
{
|
|
return (new BigFloat(value)).ShiftDecimalLeft(shift);
|
|
}
|
|
public static BigFloat operator ^(BigFloat left, int right)
|
|
{
|
|
return (new BigFloat(left)).Pow(right);
|
|
}
|
|
public static BigFloat operator ~(BigFloat value)
|
|
{
|
|
return (new BigFloat(value)).Inverse();
|
|
}
|
|
|
|
public static bool operator !=(BigFloat left, BigFloat right)
|
|
{
|
|
return Compare(left, right) != 0;
|
|
}
|
|
public static bool operator ==(BigFloat left, BigFloat right)
|
|
{
|
|
return Compare(left, right) == 0;
|
|
}
|
|
public static bool operator <(BigFloat left, BigFloat right)
|
|
{
|
|
return Compare(left, right) < 0;
|
|
}
|
|
public static bool operator <=(BigFloat left, BigFloat right)
|
|
{
|
|
return Compare(left, right) <= 0;
|
|
}
|
|
public static bool operator >(BigFloat left, BigFloat right)
|
|
{
|
|
return Compare(left, right) > 0;
|
|
}
|
|
public static bool operator >=(BigFloat left, BigFloat right)
|
|
{
|
|
return Compare(left, right) >= 0;
|
|
}
|
|
|
|
public static bool operator true(BigFloat value)
|
|
{
|
|
return value != 0;
|
|
}
|
|
public static bool operator false(BigFloat value)
|
|
{
|
|
return value == 0;
|
|
}
|
|
|
|
public static explicit operator decimal(BigFloat value)
|
|
{
|
|
if (decimal.MinValue > value) throw new System.OverflowException("value is less than System.decimal.MinValue.");
|
|
if (decimal.MaxValue < value) throw new System.OverflowException("value is greater than System.decimal.MaxValue.");
|
|
|
|
return (decimal)value.numerator / (decimal)value.denominator;
|
|
}
|
|
public static explicit operator double(BigFloat value)
|
|
{
|
|
if (double.MinValue > value) throw new System.OverflowException("value is less than System.double.MinValue.");
|
|
if (double.MaxValue < value) throw new System.OverflowException("value is greater than System.double.MaxValue.");
|
|
|
|
return (double)value.numerator / (double)value.denominator;
|
|
}
|
|
public static explicit operator float(BigFloat value)
|
|
{
|
|
if (float.MinValue > value) throw new System.OverflowException("value is less than System.float.MinValue.");
|
|
if (float.MaxValue < value) throw new System.OverflowException("value is greater than System.float.MaxValue.");
|
|
|
|
return (float)value.numerator / (float)value.denominator;
|
|
}
|
|
|
|
//byte, sbyte,
|
|
public static implicit operator BigFloat(byte value)
|
|
{
|
|
return new BigFloat((uint)value);
|
|
}
|
|
public static implicit operator BigFloat(sbyte value)
|
|
{
|
|
return new BigFloat((int)value);
|
|
}
|
|
public static implicit operator BigFloat(short value)
|
|
{
|
|
return new BigFloat((int)value);
|
|
}
|
|
public static implicit operator BigFloat(ushort value)
|
|
{
|
|
return new BigFloat((uint)value);
|
|
}
|
|
public static implicit operator BigFloat(int value)
|
|
{
|
|
return new BigFloat(value);
|
|
}
|
|
public static implicit operator BigFloat(long value)
|
|
{
|
|
return new BigFloat(value);
|
|
}
|
|
public static implicit operator BigFloat(uint value)
|
|
{
|
|
return new BigFloat(value);
|
|
}
|
|
public static implicit operator BigFloat(ulong value)
|
|
{
|
|
return new BigFloat(value);
|
|
}
|
|
public static implicit operator BigFloat(decimal value)
|
|
{
|
|
return new BigFloat(value);
|
|
}
|
|
public static implicit operator BigFloat(double value)
|
|
{
|
|
return new BigFloat(value);
|
|
}
|
|
public static implicit operator BigFloat(float value)
|
|
{
|
|
return new BigFloat(value);
|
|
}
|
|
public static implicit operator BigFloat(BigInteger value)
|
|
{
|
|
return new BigFloat(value);
|
|
}
|
|
public static explicit operator BigFloat(string value)
|
|
{
|
|
return new BigFloat(value);
|
|
}
|
|
|
|
private BigFloat Factor()
|
|
{
|
|
//factoring can be very slow. So use only when neccessary (ToString, and comparisons)
|
|
|
|
if (denominator == 1)
|
|
return this;
|
|
|
|
//factor numerator and denominator
|
|
BigInteger factor = BigInteger.GreatestCommonDivisor(numerator, denominator);
|
|
|
|
numerator /= factor;
|
|
denominator /= factor;
|
|
|
|
return this;
|
|
}
|
|
|
|
}
|
|
|
|
}
|