Skip to content

Commit

Permalink
Init #38
Browse files Browse the repository at this point in the history
  • Loading branch information
sys27 committed Dec 30, 2016
1 parent a9f5d11 commit 7ef6440
Show file tree
Hide file tree
Showing 5 changed files with 407 additions and 1 deletion.
298 changes: 298 additions & 0 deletions xFunc.Numerics/BigDecimal.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,298 @@
// Copyright 2012-2016 Dmitry Kischenko
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Numerics;

namespace xFunc.Numerics
{

public struct BigDecimal : IComparable, IComparable<BigDecimal>, IEquatable<BigDecimal>
{

public BigDecimal(int value) : this(value, 0) { }

public BigDecimal(double value)
{
var mantissa = (BigInteger)value;
var exponent = 0;
double scaleFactor = 1;

while (Math.Abs(value * scaleFactor - (double)mantissa) > 0)
{
exponent -= 1;
scaleFactor *= 10;
mantissa = (BigInteger)(value * scaleFactor);
}

Mantissa = mantissa;
Exponent = exponent;
Normalize();
}

public BigDecimal(decimal value)
{
var mantissa = (BigInteger)value;
var exponent = 0;
decimal scaleFactor = 1;
while ((decimal)mantissa != value * scaleFactor)
{
exponent -= 1;
scaleFactor *= 10;
mantissa = (BigInteger)(value * scaleFactor);
}

Mantissa = mantissa;
Exponent = exponent;
Normalize();
}

public BigDecimal(BigInteger mantissa, int exponent)
{
Mantissa = mantissa;
Exponent = exponent;
Normalize();
}

public bool Equals(BigDecimal other)
{
return other.Mantissa.Equals(Mantissa) && other.Exponent == Exponent;
}

public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
return false;

return obj is BigDecimal && Equals((BigDecimal)obj);
}

public override int GetHashCode()
{
unchecked
{
return (Mantissa.GetHashCode() * 397) ^ Exponent;
}
}

public override string ToString()
{
return string.Concat(Mantissa.ToString(), "E", Exponent);
}

public int CompareTo(object obj)
{
if (ReferenceEquals(obj, null) || !(obj is BigDecimal))
throw new ArgumentException();

return CompareTo((BigDecimal)obj);
}

public int CompareTo(BigDecimal other)
{
return this < other ? -1 : (this > other ? 1 : 0);
}

/// <summary>
/// Removes trailing zeros on the mantissa
/// </summary>
public void Normalize()
{
if (Mantissa.IsZero)
{
Exponent = 0;
}
else
{
BigInteger remainder = 0;
while (remainder == 0)
{
var shortened = BigInteger.DivRem(Mantissa, 10, out remainder);
if (remainder == 0)
{
Mantissa = shortened;
Exponent++;
}
}
}
}

/// <summary>
/// Truncate the number to the given precision by removing the least significant digits.
/// </summary>
/// <returns>The truncated number</returns>
public BigDecimal Truncate(int precision)
{
// copy this instance (remember its a struct)
var shortened = this;
// save some time because the number of digits is not needed to remove trailing zeros
shortened.Normalize();
// remove the least significant digits, as long as the number of digits is higher than the given Precision
while (NumberOfDigits(shortened.Mantissa) > precision)
{
shortened.Mantissa /= 10;
shortened.Exponent++;
}
// normalize again to make sure there are no trailing zeros left
shortened.Normalize();
return shortened;
}

private static int NumberOfDigits(BigInteger value)
{
return (int)Math.Ceiling(BigInteger.Log10(value * value.Sign));
}

/// <summary>
/// Returns the mantissa of value, aligned to the exponent of reference.
/// Assumes the exponent of value is larger than of reference.
/// </summary>
private static BigInteger AlignMantissa(BigDecimal value, BigDecimal reference)
{
return value.Mantissa * BigInteger.Pow(10, value.Exponent - reference.Exponent);
}

#region Conversions

public static implicit operator BigDecimal(int 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 explicit operator double(BigDecimal value)
{
return (double)value.Mantissa * Math.Pow(10, value.Exponent);
}

public static explicit operator float(BigDecimal value)
{
return Convert.ToSingle((double)value);
}

public static explicit operator decimal(BigDecimal value)
{
return (decimal)value.Mantissa * (decimal)Math.Pow(10, value.Exponent);
}

public static explicit operator int(BigDecimal value)
{
return (int)(value.Mantissa * BigInteger.Pow(10, value.Exponent));
}

#endregion

#region Operators

public static BigDecimal operator +(BigDecimal value)
{
return value;
}

public static BigDecimal operator -(BigDecimal value)
{
value.Mantissa *= -1;
return value;
}

public static BigDecimal operator ++(BigDecimal value)
{
return value + 1;
}

public static BigDecimal operator --(BigDecimal value)
{
return value - 1;
}

public static BigDecimal operator +(BigDecimal left, BigDecimal right)
{
return Add(left, right);
}

public static BigDecimal operator -(BigDecimal left, BigDecimal right)
{
return Add(left, -right);
}

private static BigDecimal Add(BigDecimal left, BigDecimal right)
{
return left.Exponent > right.Exponent
? new BigDecimal(AlignMantissa(left, right) + right.Mantissa, right.Exponent)
: new BigDecimal(AlignMantissa(right, left) + left.Mantissa, left.Exponent);
}

public static BigDecimal operator *(BigDecimal left, BigDecimal right)
{
return new BigDecimal(left.Mantissa * right.Mantissa, left.Exponent + right.Exponent);
}

public static BigDecimal operator /(BigDecimal dividend, BigDecimal divisor)
{
var exponentChange = 50 - NumberOfDigits(dividend.Mantissa) - NumberOfDigits(divisor.Mantissa);
if (exponentChange < 0)
exponentChange = 0;

dividend.Mantissa *= BigInteger.Pow(10, exponentChange);

return new BigDecimal(dividend.Mantissa / divisor.Mantissa, dividend.Exponent - divisor.Exponent - exponentChange);
}

public static bool operator ==(BigDecimal left, BigDecimal right)
{
return left.Exponent == right.Exponent && left.Mantissa == right.Mantissa;
}

public static bool operator !=(BigDecimal left, BigDecimal right)
{
return left.Exponent != right.Exponent || left.Mantissa != right.Mantissa;
}

public static bool operator <(BigDecimal left, BigDecimal right)
{
return left.Exponent > right.Exponent ? AlignMantissa(left, right) < right.Mantissa : left.Mantissa < AlignMantissa(right, left);
}

public static bool operator >(BigDecimal left, BigDecimal right)
{
return left.Exponent > right.Exponent ? AlignMantissa(left, right) > right.Mantissa : left.Mantissa > AlignMantissa(right, left);
}

public static bool operator <=(BigDecimal left, BigDecimal right)
{
return left.Exponent > right.Exponent ? AlignMantissa(left, right) <= right.Mantissa : left.Mantissa <= AlignMantissa(right, left);
}

public static bool operator >=(BigDecimal left, BigDecimal right)
{
return left.Exponent > right.Exponent ? AlignMantissa(left, right) >= right.Mantissa : left.Mantissa >= AlignMantissa(right, left);
}

#endregion

public BigInteger Mantissa { get; private set; }
public int Exponent { get; private set; }

}

}
33 changes: 33 additions & 0 deletions xFunc.Numerics/BigMath.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright 2012-2016 Dmitry Kischenko
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;

namespace xFunc.Numerics
{

public static class BigMath
{

public static readonly BigDecimal E = new BigDecimal();
public static readonly BigDecimal PI = new BigDecimal();

public static BigDecimal Abs(BigDecimal value)
{
return value >= 0 ? value : -value;
}

}

}
15 changes: 15 additions & 0 deletions xFunc.Numerics/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;
using System.Reflection;
using System.Runtime.InteropServices;

[assembly: AssemblyTitle("xFunc.Numerics")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("xFunc.Numerics")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

[assembly: ComVisible(false)]
[assembly: Guid("d6d86bc5-24bc-4ac1-8d30-c0cbddb0087f")]

[assembly: CLSCompliant(true)]
Loading

0 comments on commit 7ef6440

Please sign in to comment.