-
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
407 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; } | ||
|
||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
|
||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)] |
Oops, something went wrong.