Skip to content

Instantly share code, notes, and snippets.

@AmrAlSayed0
Created July 29, 2015 22:51
Show Gist options
  • Save AmrAlSayed0/23e60be6c5d1a56e3f08 to your computer and use it in GitHub Desktop.
Save AmrAlSayed0/23e60be6c5d1a56e3f08 to your computer and use it in GitHub Desktop.
A class that represents an arbitrarily large decimal number.
namespace ArbitraryPrecision
{
#region Usings
using System;
using System.Linq;
using System.Numerics;
using System.Text.RegularExpressions;
#endregion
/// <summary>Represents an arbitrarily large decimal number.</summary>
public struct BigDecimal : IFormattable , IComparable , IComparable < BigDecimal > , IEquatable < BigDecimal >
{
#region Fields
/// <summary>Specifies whether the significant digits should be truncated to the given precision after each operation.</summary>
private static bool _alwaysTruncate;
/// <summary>Regex pattern used to match a number in a text.</summary>
private static readonly Regex _parsePattern = new Regex ( @"^(?<LeadingSpaces>[ \t]*)(?<NumberSign>[-+ \t]*[-+])?(?<SignSpaces>[ \t]*)(?<LeadingRedundantZeros>[0,]*)(?<BeforeDecimal>[\d,]*)(?:\.(?<AfterDecimal>\d*?)(?<TrailingRedundantZeros>(?<!0)0*))?(?<NumberSpaces>[ \t]*)(?:[Ee](?<ESpaces>[ \t]*)(?<ExponentSign>[-+ ]*?)(?<EponentSignSpaces>[ \t]*)(?<ExponentRedundantZeros>[0,]*)(?<ExponentNumber>[\d,]*))?(?<TrailingSpaces>[ \t]*)$" );
/// <summary>A decimal whose value is zero (0).</summary>
private static readonly BigDecimal _zero = new BigDecimal ( 0 , 0 );
/// <summary>A decimal whose value is one (1).</summary>
private static readonly BigDecimal _one = new BigDecimal ( 1 , 0 );
/// <summary>A decimal whose value is negative one (-1).</summary>
private static readonly BigDecimal _minusOne = new BigDecimal ( -1 , 0 );
/// <summary>Specifies the maximum precision the number could be. If _alwaysTruncate is set to true all operations are affected.</summary>
private int _precision;
/// <summary>The integer part of the number.</summary>
private BigInteger _mantissa;
/// <summary>The exponent part of the number.</summary>
private int _exponent;
/// <summary>A number that indicates the sign of the BigDecimal object, as shown in the following table. Number Description -1 The value of this object is negative. 0 The value of this object is 0 (zero). 1 The value of this object is positive.</summary>
private int _sign;
#endregion
#region Properties
/// <summary>Gets or sets whether the significant digits should be truncated to the given precision after each operation.</summary>
/// <returns><c>true</c> if the significant digits should be truncated to the given precision after each operation; otherwise, <c>false</c></returns>
public static bool AlwaysTruncate
{
get
{
return _alwaysTruncate;
}
set
{
_alwaysTruncate = value;
}
}
/// <summary>Gets or sets the maximum precision the number could be. If _alwaysTruncate is set to true all operations are affected.</summary>
/// <returns>The maximum precision the number could be.</returns>
public int Precision
{
get
{
return this._precision;
}
set
{
if ( value < 28 )
{
this._precision = 28;
}
else
{
this._precision = value;
}
}
}
/// <summary>Gets the regex pattern used to match a number in a text.</summary>
/// <returns>The Regex pattern used to match a number in a text.</returns>
private static Regex ParsePattern
{
get
{
return _parsePattern;
}
}
/// <summary>Gets a value that represents the number 0 (zero).</summary>
/// <returns>A decimal whose value is zero (0).</returns>
public static BigDecimal Zero
{
get
{
return _zero;
}
}
/// <summary>Gets a value that represents the number one (1).</summary>
/// <returns>A decimal whose value is one (1).</returns>
public static BigDecimal One
{
get
{
return _one;
}
}
/// <summary>Gets a value that represents the number negative one (-1).</summary>
/// <returns>A decimal whose value is negative one (-1).</returns>
public static BigDecimal MinusOne
{
get
{
return _minusOne;
}
}
/// <summary>Gets or sets the integer part of the number.</summary>
/// <returns>The integer part of the number.</returns>
public BigInteger Mantissa
{
get
{
return this._mantissa;
}
set
{
this._mantissa = value;
this.Sign = this._mantissa.Sign;
}
}
/// <summary>Gets or sets the exponent part of the number.</summary>
/// <returns>The exponent part of the number</returns>
public int Exponent
{
get
{
return this._exponent;
}
set
{
this._exponent = value;
}
}
/// <summary>Gets a number that indicates the sign (negative, positive, or zero) of the current <see cref = "BigDecimal" /> object.</summary>
/// <returns>A number that indicates the sign of the BigDecimal object, as shown in the following table. Number Description -1 The value of this object is negative. 0 The value of this object is 0 (zero). 1 The value of this object is positive.</returns>
public int Sign
{
get
{
return this._sign;
}
private set
{
this._sign = value;
}
}
/// <summary>Indicates whether the value of the current <see cref = "BigDecimal" /> object is <seealso cref = "BigDecimal.One" />.</summary>
/// <returns><c>true</c> if the value of the <see cref = "BigDecimal" /> object is <seealso cref = "BigDecimal.One" />; otherwise, <c>false</c>.</returns>
public bool IsOne
{
get
{
return this.Equals ( One );
}
}
/// <summary>Indicates whether the value of the current <see cref = "BigDecimal" /> object is <seealso cref = "BigDecimal.Zero" />.</summary>
/// <returns><c>true</c> if the value of the <see cref = "BigDecimal" /> object is <seealso cref = "BigDecimal.Zero" />; otherwise, <c>false</c>.</returns>
public bool IsZero
{
get
{
return this.Equals ( Zero );
}
}
#endregion
#region Constructors
/// <summary>Initializes a new instance of the <see cref = "BigDecimal" /> structure using a <paramref name = "mantissa" /> and an <paramref name = "exponent" />.</summary>
/// <param name = "mantissa" >The integer part of the number.</param>
/// <param name = "exponent" >The exponent part of the number.</param>
/// <param name = "precision" >The maximum precision the number could be.</param>
public BigDecimal ( BigInteger mantissa ,
int exponent ,
int precision = 1024 ) : this ()
{
this.Mantissa = mantissa;
this.Exponent = exponent;
this.Precision = precision;
this.Normalize ();
if ( AlwaysTruncate )
{
this = this.Truncate ();
}
}
/// <summary>Initializes a new instance of the <see cref = "BigDecimal" /> structure using an 8-bit signed integer value.</summary>
/// <param name = "value" >An 8-bit signed integer.</param>
public BigDecimal ( sbyte value ) : this ()
{
this.Mantissa = value;
this.Exponent = 0;
this.Precision = 1024;
}
/// <summary>Initializes a new instance of the <see cref = "BigDecimal" /> structure using an 8-bit unsigned integer value.</summary>
/// <param name = "value" >An 8-bit unsigned integer.</param>
public BigDecimal ( byte value ) : this ()
{
this.Mantissa = value;
this.Exponent = 0;
this.Precision = 1024;
}
/// <summary>Initializes a new instance of the <see cref = "BigDecimal" /> structure using a 16-bit unicode character.</summary>
/// <param name = "value" >A 16-bit Unicode character.</param>
public BigDecimal ( char value ) : this ()
{
this.Mantissa = value;
this.Exponent = 0;
this.Precision = 1024;
}
/// <summary>Initializes a new instance of the <see cref = "BigDecimal" /> structure using a 16-bit signed integer value.</summary>
/// <param name = "value" >A 16-bit signed integer.</param>
public BigDecimal ( short value ) : this ()
{
this.Mantissa = value;
this.Exponent = 0;
this.Precision = 1024;
}
/// <summary>Initializes a new instance of the <see cref = "BigDecimal" /> structure using a 16-bit unsigned integer value.</summary>
/// <param name = "value" >A 16-bit unsigned integer.</param>
public BigDecimal ( ushort value ) : this ()
{
this.Mantissa = value;
this.Exponent = 0;
this.Precision = 1024;
}
/// <summary>Initializes a new instance of the <see cref = "BigDecimal" /> structure using a 32-bit signed integer value.</summary>
/// <param name = "value" >A 32-bit signed integer.</param>
public BigDecimal ( int value ) : this ()
{
this.Mantissa = value;
this.Exponent = 0;
this.Precision = 1024;
}
/// <summary>Initializes a new instance of the <see cref = "BigDecimal" /> structure using an unsigned 32-bit integer value.</summary>
/// <param name = "value" >A 32-bit unsigned integer value.</param>
public BigDecimal ( uint value ) : this ()
{
this.Mantissa = value;
this.Exponent = 0;
this.Precision = 1024;
}
/// <summary>Initializes a new instance of the <see cref = "BigDecimal" /> structure using a 64-bit signed integer value.</summary>
/// <param name = "value" >A 64-bit signed integer.</param>
public BigDecimal ( long value ) : this ()
{
this.Mantissa = value;
this.Exponent = 0;
this.Precision = 1024;
}
/// <summary>Initializes a new instance of the <see cref = "BigDecimal" /> structure with a 64-bit unsigned integer value.</summary>
/// <param name = "value" >A 64-bit unsigned integer.</param>
public BigDecimal ( ulong value ) : this ()
{
this.Mantissa = value;
this.Exponent = 0;
this.Precision = 1024;
}
/// <summary>Initializes a new instance of the <see cref = "BigDecimal" /> structure using a single-precision floating-point value.</summary>
/// <param name = "value" >A single-precision floating-point value.</param>
public BigDecimal ( float value ) : this ()
{
this = value;
this.Precision = 1024;
}
/// <summary>Initializes a new instance of the <see cref = "BigDecimal" /> structure using a double-precision floating-point value.</summary>
/// <param name = "value" >A double-precision floating-point value.</param>
public BigDecimal ( double value ) : this ()
{
this = value;
this.Precision = 1024;
}
/// <summary>Initializes a new instance of the <see cref = "BigDecimal" /> structure using a <see cref = "System.Decimal" /> value.</summary>
/// <param name = "value" >A decimal number.</param>
public BigDecimal ( decimal value ) : this ()
{
this = value;
this.Precision = 1024;
}
/// <summary>Initializes a new instance of the <see cref = "BigDecimal" /> structure using a <see cref = "System.String" /> value.</summary>
/// <param name = "value" >A string representation of the number.</param>
public BigDecimal ( string value ) : this ()
{
TryParse ( value , out this );
}
#endregion
#region IComparable Members
/// <summary>Compares this instance to a specified object and returns an integer that indicates whether the value of this instance is less than, equal to, or greater than the value of the specified object.</summary>
/// <param name = "comparedTo" >The object to compare.</param>
/// <returns>A value that indicates the relative order of the objects being compared. The return value has these meanings:
/// <list type = "bullet" >
/// <item>Less than zero - This instance precedes <paramref name = "comparedTo" /> in the sort order.</item>
/// <item>Zero - This instance occurs in the same position in the sort order as <paramref name = "comparedTo" />.</item>
/// <item>Greater than zero - This instance follows <paramref name = "comparedTo" /> in the sort order.</item>
/// </list>
/// </returns>
/// <exception cref = "T:System.ArgumentException" ><paramref name = "comparedTo" /> is not the same type as this instance. </exception>
/// <exception cref = "T:System.ArgumentNullException" ><paramref name = "comparedTo" /> is null. </exception>
int IComparable.CompareTo ( object comparedTo )
{
return this.CompareTo ( comparedTo );
}
#endregion
#region IComparable<BigDecimal> Members
/// <summary>Compares this instance to a second <see cref = "BigDecimal" /> and returns an integer that indicates whether the value of this instance is less than, equal to, or greater than the value of the specified object.</summary>
/// <returns>A value that indicates the relative order of the <see cref = "BigDecimal" />s being compared. The return value has these meanings:
/// <list type = "bullet" >
/// <item>Less than zero - This <see cref = "BigDecimal" /> precedes <paramref name = "comparedTo" /> in the sort order.</item>
/// <item>Zero - This <see cref = "BigDecimal" /> occurs in the same position in the sort order as <paramref name = "comparedTo" />.</item>
/// <item>Greater than zero - This <see cref = "BigDecimal" /> follows <paramref name = "comparedTo" /> in the sort order.</item>
/// </list>
/// </returns>
/// <param name = "comparedTo" >A <see cref = "BigDecimal" /> to compare with this <see cref = "BigDecimal" />.</param>
/// <exception cref = "T:System.ArgumentException" ><paramref name = "comparedTo" /> is not of type <see cref = "BigDecimal" />. </exception>
/// <exception cref = "T:System.ArgumentNullException" ><paramref name = "comparedTo" /> is null. </exception>
int IComparable < BigDecimal >.CompareTo ( BigDecimal comparedTo )
{
return this.CompareTo ( comparedTo );
}
#endregion
#region IEquatable<BigDecimal> Members
/// <summary>Returns a value that indicates whether the current <see cref = "BigDecimal" /> and a specified <see cref = "BigDecimal" /> object have the same value.</summary>
/// <returns>
/// <c>true</c> if the current <see cref = "BigDecimal" /> is equal to the <paramref name = "other" /> parameter; otherwise, <c>false</c>.</returns>
/// <param name = "other" >A <see cref = "BigDecimal" /> to compare with this <see cref = "BigDecimal" />.</param>
bool IEquatable < BigDecimal >.Equals ( BigDecimal other )
{
return this.Equals ( other );
}
#endregion
#region IFormattable Members
/// <summary>Formats the value of the current instance using the specified format.</summary>
/// <returns>The value of the current instance in the specified format.</returns>
/// <param name = "format" >The format to use.-or- A null reference (Nothing in Visual Basic) to use the default format defined for the type of the <see cref = "T:System.IFormattable" /> implementation. </param>
/// <param name = "formatProvider" >The provider to use to format the value.-or- A null reference (Nothing in Visual Basic) to obtain the numeric format information from the current locale setting of the operating system. </param>
string IFormattable.ToString ( string format ,
IFormatProvider formatProvider )
{
return this.ToString ( format , formatProvider );
}
#endregion
#region Static Methods
/// <summary>Compares two <see cref = "BigDecimal" /> values and returns an integer that indicates whether the first value is less than, equal to, or greater than the second value.</summary>
/// <param name = "left" >The first value to compare.</param>
/// <param name = "right" >The second value to compare.</param>
/// <returns>A signed integer that indicates the relative values of <paramref name = "left" /> and <paramref name = "right" />.</returns>
public static int Compare ( BigDecimal left ,
BigDecimal right )
{
return left.CompareTo ( right );
}
/// <summary>Counts the number of digits in a BigInteger.</summary>
/// <param name = "value" >The BigInteger to be counted.</param>
/// <returns>The number of Digits in the BigInteger</returns>
private static int NumberOfDigits ( BigInteger value )
{
// Doesn't count the sign.
return ( value * value.Sign ).ToString ().Length;
}
/// <summary>Adds two <see cref = "BigDecimal" /> values and returns the result.</summary>
/// <param name = "left" >The first value to add.</param>
/// <param name = "right" >The second value to add.</param>
/// <returns>The sum of left and right.</returns>
public static BigDecimal Add ( BigDecimal left ,
BigDecimal right )
{
return left + right;
}
/// <summary>Subtracts one <see cref = "BigDecimal" /> value from another and returns the result.</summary>
/// <param name = "left" >The value to subtract from (the minuend).</param>
/// <param name = "right" >The value to subtract (the subtrahend).</param>
/// <returns>The result of subtracting right from left.</returns>
public static BigDecimal Subtract ( BigDecimal left ,
BigDecimal right )
{
return left - right;
}
/// <summary>Returns the product of two <see cref = "BigDecimal" /> values.</summary>
/// <param name = "left" >The first number to multiply.</param>
/// <param name = "right" >The second number to multiply.</param>
/// <returns>The product of the left and right parameters.</returns>
public static BigDecimal Multiply ( BigDecimal left ,
BigDecimal right )
{
return left * right;
}
/// <summary>Divides one <see cref = "BigDecimal" /> value by another and returns the result.</summary>
/// <param name = "dividend" >The value to be divided.</param>
/// <param name = "divisor" >The value to divide by.</param>
/// <returns>The value of the division.</returns>
/// <exception cref = "DivideByZeroException" >Dividing by zero attempted.</exception>
public static BigDecimal Divide ( BigDecimal dividend ,
BigDecimal divisor )
{
return dividend / divisor;
}
/// <summary>Negates a specified <see cref = "BigDecimal" /> value.</summary>
/// <param name = "value" >The value to negate.</param>
/// <returns>The result of the <paramref name = "value" /> parameter multiplied by negative one (-1).</returns>
public static BigDecimal Negate ( BigDecimal value )
{
return -value;
}
/// <summary>Raises a BigDecimal value to the power of a specified value.</summary>
/// <param name = "basis" >The number to raise to the exponent power.</param>
/// <param name = "exponent" >The exponent to raise value by.</param>
/// <returns>The result of raising value to the exponent power.</returns>
public static BigDecimal Pow ( BigDecimal basis ,
double exponent )
{
throw new NotImplementedException ();
}
/// <summary>Gets the absolute value of a BigDecimal object.</summary>
/// <param name = "value" >A number.</param>
/// <returns>The absolute value of value.</returns>
public static BigDecimal Abs ( BigDecimal value )
{
return 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>
/// <param name = "value" >The value to align.</param>
/// <param name = "reference" >The reference to align to.</param>
/// <returns>Returns the mantissa of value, aligned to the exponent of reference.</returns>
private static BigInteger AlignExponent ( BigDecimal value ,
BigDecimal reference )
{
if ( value.Exponent - reference.Exponent > 0 )
{
return value.Mantissa * BigInteger.Pow ( 10 , value.Exponent - reference.Exponent );
}
throw new ArgumentOutOfRangeException ( "reference" , "reference's exponent is higher than value's exponent." );
}
/// <summary></summary>
/// <param name = "number" ></param>
/// <param name = "parsedBigDecimal" ></param>
/// <returns></returns>
/// <exception cref = "ArgumentException" ></exception>
public static bool TryParse ( string number ,
out BigDecimal parsedBigDecimal )
{
if ( ParsePattern.IsMatch ( number ) )
{
parsedBigDecimal = Parse ( number );
return true;
}
parsedBigDecimal = Zero;
return false;
}
/// <summary>Parses a string of text into a BigDecimal.</summary>
/// <param name = "number" >The number to be parsed.</param>
/// <returns>The <paramref name = "number" /> as a BigDecimal.</returns>
/// <exception cref = "ArgumentException" >The string entered doesn't represent a number.</exception>
public static BigDecimal Parse ( string number )
{
if ( ParsePattern.IsMatch ( number ) )
{
Match numberMatch = ParsePattern.Match ( number );
string sign = FilterSign ( numberMatch.Groups [ "NumberSign" ].Value );
string beforeDecimal = FilterInteger ( numberMatch.Groups [ "BeforeDecimal" ].Value );
string afterDecimal = FilterInteger ( numberMatch.Groups [ "AfterDecimal" ].Value );
string exponentSign = FilterSign ( numberMatch.Groups [ "ExponentSign" ].Value );
string exponentNum = FilterInteger ( numberMatch.Groups [ "ExponentNumber" ].Value );
return RadixNormalize ( beforeDecimal , afterDecimal , sign , exponentSign , exponentNum );
}
//throw new ArgumentException ( "Argument is not in the correct format" , "number" );
return Zero;
}
private static BigDecimal RadixNormalize ( string beforeDecimal ,
string afterDecimal ,
string sign ,
string exponentSign ,
string exponentNum )
{
BigInteger mantissa;
int exponent;
if ( beforeDecimal != string.Empty && afterDecimal != string.Empty )
{
mantissa = BigInteger.Parse ( sign + beforeDecimal + afterDecimal );
if ( exponentNum == string.Empty )
{
exponent = int.Parse ( exponentSign + "0" ) - afterDecimal.Length;
}
else
{
exponent = int.Parse ( exponentSign + exponentNum ) - afterDecimal.Length;
}
return new BigDecimal ( mantissa , exponent );
}
if ( beforeDecimal == string.Empty && afterDecimal == string.Empty )
{
return Zero;
}
if ( beforeDecimal != string.Empty && afterDecimal == string.Empty )
{
string zerosRemoved = beforeDecimal.TrimEnd ( '0' );
mantissa = BigInteger.Parse ( sign + zerosRemoved );
if ( exponentNum == string.Empty )
{
exponent = int.Parse ( exponentSign + "0" ) - afterDecimal.Length;
}
else
{
exponent = int.Parse ( exponentSign + exponentNum ) + ( beforeDecimal.Length - zerosRemoved.Length );
}
return new BigDecimal ( mantissa , exponent );
}
if ( beforeDecimal == string.Empty && afterDecimal != string.Empty )
{
string zerosRemoved = afterDecimal.TrimStart ( '0' );
mantissa = BigInteger.Parse ( sign + zerosRemoved );
if ( exponentNum == string.Empty )
{
exponent = int.Parse ( exponentSign + "0" ) - afterDecimal.Length;
}
else
{
exponent = int.Parse ( exponentSign + exponentNum ) - afterDecimal.Length;
}
return new BigDecimal ( mantissa , exponent );
}
return Zero;
}
/// <summary>Filters numbers before the decimal point.</summary>
/// <param name = "toBeFiltered" >The numbers to be filtered.</param>
/// <returns>The filtered numbers.</returns>
private static string FilterInteger ( string toBeFiltered )
{
string finalString = toBeFiltered;
if ( finalString == string.Empty )
{
return string.Empty;
}
if ( toBeFiltered.Contains ( "," ) )
{
finalString = finalString.Replace ( "," , string.Empty );
if ( finalString == string.Empty )
{
return string.Empty;
}
}
return finalString;
}
/// <summary>Filters the sign string into a single sign.</summary>
/// <param name = "toBeFiltered" >The sign string to be filtered.</param>
/// <returns>A positive or negative sign.</returns>
private static string FilterSign ( string toBeFiltered )
{
string finalstring = toBeFiltered;
if ( finalstring == string.Empty )
{
return string.Empty;
}
if ( finalstring.Contains ( " " ) || finalstring.Contains ( "\t" ) )
{
finalstring = finalstring.Replace ( " " , "" ).Replace ( "\t" , "" );
if ( finalstring == string.Empty )
{
return string.Empty;
}
}
if ( finalstring.Contains ( "-" ) )
{
int minusCount = finalstring.Count ( ch => ch == '-' );
if ( minusCount % 2 == 0 )
{
return string.Empty;
}
if ( minusCount % 2 != 0 )
{
return "-";
}
}
return string.Empty;
}
#endregion
#region Normal Methods
/// <summary>Compares this instance to a specified object and returns an integer that indicates whether the value of this instance is less than, equal to, or greater than the value of the specified object.</summary>
/// <returns>A value that indicates the relative order of the <see cref = "BigDecimal" />s being compared. The return value has the following meanings: Value Meaning Less than zero This <see cref = "BigDecimal" /> is less than the <paramref name = "comparedTo" /> parameter.Zero This <see cref = "BigDecimal" /> is equal to <paramref name = "comparedTo" />. Greater than zero This <see cref = "BigDecimal" /> is greater than <paramref name = "comparedTo" />.</returns>
/// <param name = "comparedTo" >A <see cref = "BigDecimal" /> to compare with this <see cref = "BigDecimal" />.</param>
/// <exception cref = "T:System.ArgumentException" ><paramref name = "comparedTo" /> is not of type <see cref = "BigDecimal" />. </exception>
/// <exception cref = "T:System.ArgumentNullException" ><paramref name = "comparedTo" /> is null. </exception>
public int CompareTo ( object comparedTo )
{
if ( ReferenceEquals ( comparedTo , null ) )
{
throw new ArgumentNullException ( "comparedTo" , "Passed argument is null" );
}
if ( !( comparedTo is BigDecimal ) )
{
throw new ArithmeticException ( "Passed argument is not of type System.Numerics.BigDecimal." );
}
return this.CompareTo ( ( BigDecimal ) comparedTo );
}
/// <summary>Compares this instance to a second <see cref = "BigDecimal" /> and returns an integer that indicates whether the value of this instance is less than, equal to, or greater than the value of the specified object.</summary>
/// <returns>A value that indicates the relative order of the <see cref = "BigDecimal" />s being compared. The return value has the following meanings: Value Meaning Less than zero This <see cref = "BigDecimal" /> is less than the <paramref name = "comparedTo" /> parameter.Zero This <see cref = "BigDecimal" /> is equal to <paramref name = "comparedTo" />. Greater than zero This <see cref = "BigDecimal" /> is greater than <paramref name = "comparedTo" />.</returns>
/// <param name = "comparedTo" >A <see cref = "BigDecimal" /> to compare with this <see cref = "BigDecimal" />.</param>
/// <exception cref = "T:System.ArgumentException" ><paramref name = "comparedTo" /> is not of type <see cref = "BigDecimal" />. </exception>
/// <exception cref = "T:System.ArgumentNullException" ><paramref name = "comparedTo" /> is null. </exception>
public int CompareTo ( BigDecimal comparedTo )
{
if ( this < comparedTo )
{
return -1;
}
if ( this > comparedTo )
{
return 1;
}
return 0;
}
/// <summary>Returns a value that indicates whether the current instance and a specified <see cref = "BigDecimal" /> object have the same value.</summary>
/// <returns>true if the current <see cref = "BigDecimal" /> is equal to the <paramref name = "other" /> parameter; otherwise, false.</returns>
/// <param name = "other" >A <see cref = "BigDecimal" /> to compare with this <see cref = "BigDecimal" />.</param>
public bool Equals ( BigDecimal other )
{
return other.Mantissa.Equals ( this.Mantissa ) && other.Exponent == this.Exponent;
}
/// <summary>Formats the value of the current <see cref = "BigDecimal" /> using the specified format.</summary>
/// <returns>The value of the current instance in the specified format.</returns>
/// <param name = "format" >The format to use.-or- A null reference (Nothing in Visual Basic) to use the default format defined for the type of the <see cref = "T:System.IFormattable" /> implementation. </param>
/// <param name = "formatProvider" >The provider to use to format the value.-or- A null reference (Nothing in Visual Basic) to obtain the numeric format information from the current locale setting of the operating system. </param>
public string ToString ( string format ,
IFormatProvider formatProvider )
{
return string.Concat ( this.Mantissa.ToString () , "E" , this.Exponent );
}
/// <summary>Removes trailing zeros on the mantissa.</summary>
private void Normalize ()
{
if ( this.Mantissa.IsZero )
{
this.Exponent = 0;
}
else
{
BigInteger remainder = BigInteger.Zero;
while ( remainder == BigInteger.Zero )
{
BigInteger shortened = BigInteger.DivRem ( this.Mantissa , 10 , out remainder );
if ( remainder == BigInteger.Zero )
{
this.Mantissa = shortened;
this.Exponent++;
}
}
}
}
/// <summary>Truncate the <see cref = "BigDecimal" /> to the given precision by removing the least significant digits.</summary>
/// <param name = "precision" >The number of least significant figures needed.</param>
/// <returns>The truncated <see cref = "BigDecimal" /></returns>
private BigDecimal Truncate ( int precision )
{
// Copying "this" instance (It is a "Structure").
BigDecimal shortened = this;
// Removes trailing zeros to save time.
shortened.Normalize ();
// Removes the least significant digits according to the precision value.
while ( NumberOfDigits ( shortened.Mantissa ) > precision )
{
shortened.Mantissa /= 10;
shortened.Exponent++;
}
return shortened;
}
/// <summary>Truncate the <see cref = "BigDecimal" /> to the set precision by removing the least significant digits.</summary>
/// <returns>The truncated <see cref = "BigDecimal" /></returns>
private BigDecimal Truncate ()
{
return this.Truncate ( this.Precision );
}
#endregion
#region Operator Overloads
/// <summary>Implicit conversion from <see cref = "System.SByte" /> type to <see cref = "BigDecimal" />.</summary>
/// <param name = "value" ><see cref = "System.SByte" /> value to be converted.</param>
/// <returns>The converted <see cref = "BigDecimal" />.</returns>
public static implicit operator BigDecimal ( sbyte value )
{
return new BigDecimal ( value , 0 );
}
/// <summary>Implicit conversion from <see cref = "System.Byte" /> type to <see cref = "BigDecimal" />.</summary>
/// <param name = "value" ><see cref = "System.Byte" /> value to be converted.</param>
/// <returns>The converted <see cref = "BigDecimal" />.</returns>
public static implicit operator BigDecimal ( byte value )
{
return new BigDecimal ( value , 0 );
}
/// <summary>Implicit conversion from <see cref = "System.Int16" /> type to <see cref = "BigDecimal" />.</summary>
/// <param name = "value" ><see cref = "System.Int16" /> value to be converted.</param>
/// <returns>The converted <see cref = "BigDecimal" />.</returns>
public static implicit operator BigDecimal ( short value )
{
return new BigDecimal ( value , 0 );
}
/// <summary>Implicit conversion from <see cref = "System.UInt16" /> type to <see cref = "BigDecimal" />.</summary>
/// <param name = "value" ><see cref = "System.UInt16" /> value to be converted.</param>
/// <returns>The converted <see cref = "BigDecimal" />.</returns>
public static implicit operator BigDecimal ( ushort value )
{
return new BigDecimal ( value , 0 );
}
/// <summary>Implicit conversion from <see cref = "System.Int32" /> type to <see cref = "BigDecimal" />.</summary>
/// <param name = "value" ><see cref = "System.Int32" /> value to be converted.</param>
/// <returns>The converted <see cref = "BigDecimal" />.</returns>
public static implicit operator BigDecimal ( int value )
{
return new BigDecimal ( value , 0 );
}
/// <summary>Implicit conversion from <see cref = "System.UInt32" /> type to <see cref = "BigDecimal" />.</summary>
/// <param name = "value" ><see cref = "System.UInt32" /> value to be converted.</param>
/// <returns>The converted <see cref = "BigDecimal" />.</returns>
public static implicit operator BigDecimal ( uint value )
{
return new BigDecimal ( value , 0 );
}
/// <summary>Implicit conversion from <see cref = "System.Int64" /> type to <see cref = "BigDecimal" />.</summary>
/// <param name = "value" ><see cref = "System.Int64" /> value to be converted.</param>
/// <returns>The converted <see cref = "BigDecimal" />.</returns>
public static implicit operator BigDecimal ( long value )
{
return new BigDecimal ( value , 0 );
}
/// <summary>Implicit conversion from <see cref = "System.UInt64" /> type to <see cref = "BigDecimal" />.</summary>
/// <param name = "value" ><see cref = "System.UInt64" /> value to be converted.</param>
/// <returns>The converted <see cref = "BigDecimal" />.</returns>
public static implicit operator BigDecimal ( ulong value )
{
return new BigDecimal ( value , 0 );
}
/// <summary>Implicit conversion from <see cref = "System.Single" /> type to <see cref = "BigDecimal" />.</summary>
/// <param name = "value" ><see cref = "System.Single" /> value to be converted.</param>
/// <returns>The converted <see cref = "BigDecimal" />.</returns>
public static implicit operator BigDecimal ( float value )
{
BigInteger mantissa = ( BigInteger ) value;
int exponent = 0;
float scaleFactor = 1;
while ( Math.Abs ( value * scaleFactor - ( float ) mantissa ) > 0 )
{
exponent--;
scaleFactor *= 10;
mantissa = ( BigInteger ) ( value * scaleFactor );
}
return new BigDecimal ( mantissa , exponent );
}
/// <summary>Implicit conversion from <see cref = "System.Double" /> type to <see cref = "BigDecimal" />.</summary>
/// <param name = "value" ><see cref = "System.Double" /> value to be converted.</param>
/// <returns>The converted <see cref = "BigDecimal" />.</returns>
public static implicit operator BigDecimal ( double value )
{
BigInteger mantissa = ( BigInteger ) value;
int exponent = 0;
double scaleFactor = 1;
while ( Math.Abs ( value * scaleFactor - ( double ) mantissa ) > 0 )
{
exponent--;
scaleFactor *= 10;
mantissa = ( BigInteger ) ( value * scaleFactor );
}
return new BigDecimal ( mantissa , exponent );
}
/// <summary>Implicit conversion from <see cref = "System.Decimal" /> type to <see cref = "BigDecimal" />.</summary>
/// <param name = "value" ><see cref = "System.Decimal" /> value to be converted.</param>
/// <returns>The converted <see cref = "BigDecimal" />.</returns>
public static implicit operator BigDecimal ( decimal value )
{
BigInteger mantissa = ( BigInteger ) value;
int exponent = 0;
decimal scaleFactor = 1;
//while ( ( decimal ) mantissa != value * scaleFactor )
while ( Math.Abs ( value * scaleFactor - ( decimal ) mantissa ) > 0 )
{
exponent--;
scaleFactor *= 10;
mantissa = ( BigInteger ) ( value * scaleFactor );
}
return new BigDecimal ( mantissa , exponent );
}
/// <summary>Explicit conversion from <see cref = "System.SByte" /> type to <see cref = "BigDecimal" />.</summary>
/// <param name = "value" ><see cref = "System.SByte" /> value to be converted.</param>
/// <returns>The converted <see cref = "BigDecimal" />.</returns>
public static explicit operator sbyte ( BigDecimal value )
{
return ( sbyte ) ( value.Mantissa * BigInteger.Pow ( 10 , value.Exponent ) );
}
/// <summary>Explicit conversion from <see cref = "System.Byte" /> type to <see cref = "BigDecimal" />.</summary>
/// <param name = "value" ><see cref = "System.Byte" /> value to be converted.</param>
/// <returns>The converted <see cref = "BigDecimal" />.</returns>
public static explicit operator byte ( BigDecimal value )
{
return ( byte ) ( value.Mantissa * BigInteger.Pow ( 10 , value.Exponent ) );
}
/// <summary>Explicit conversion from <see cref = "System.Int16" /> type to <see cref = "BigDecimal" />.</summary>
/// <param name = "value" ><see cref = "System.Int16" /> value to be converted.</param>
/// <returns>The converted <see cref = "BigDecimal" />.</returns>
public static explicit operator short ( BigDecimal value )
{
return ( short ) ( value.Mantissa * BigInteger.Pow ( 10 , value.Exponent ) );
}
/// <summary>Explicit conversion from <see cref = "System.UInt16" /> type to <see cref = "BigDecimal" />.</summary>
/// <param name = "value" ><see cref = "System.UInt16" /> value to be converted.</param>
/// <returns>The converted <see cref = "BigDecimal" />.</returns>
public static explicit operator ushort ( BigDecimal value )
{
return ( ushort ) ( value.Mantissa * BigInteger.Pow ( 10 , value.Exponent ) );
}
/// <summary>Explicit conversion from <see cref = "System.Int32" /> type to <see cref = "BigDecimal" />.</summary>
/// <param name = "value" ><see cref = "System.Int32" /> value to be converted.</param>
/// <returns>The converted <see cref = "BigDecimal" />.</returns>
public static explicit operator int ( BigDecimal value )
{
return ( int ) ( value.Mantissa * BigInteger.Pow ( 10 , value.Exponent ) );
}
/// <summary>Explicit conversion from <see cref = "System.UInt32" /> type to <see cref = "BigDecimal" />.</summary>
/// <param name = "value" ><see cref = "System.UInt32" /> value to be converted.</param>
/// <returns>The converted <see cref = "BigDecimal" />.</returns>
public static explicit operator uint ( BigDecimal value )
{
return ( uint ) ( value.Mantissa * BigInteger.Pow ( 10 , value.Exponent ) );
}
/// <summary>Explicit conversion from <see cref = "System.Int64" /> type to <see cref = "BigDecimal" />.</summary>
/// <param name = "value" ><see cref = "System.Int64" /> value to be converted.</param>
/// <returns>The converted <see cref = "BigDecimal" />.</returns>
public static explicit operator long ( BigDecimal value )
{
return ( long ) ( value.Mantissa * BigInteger.Pow ( 10 , value.Exponent ) );
}
/// <summary>Explicit conversion from <see cref = "System.UInt64" /> type to <see cref = "BigDecimal" />.</summary>
/// <param name = "value" ><see cref = "System.UInt64" /> value to be converted.</param>
/// <returns>The converted <see cref = "BigDecimal" />.</returns>
public static explicit operator ulong ( BigDecimal value )
{
return ( ulong ) ( value.Mantissa * BigInteger.Pow ( 10 , value.Exponent ) );
}
/// <summary>Explicit conversion from <see cref = "System.Single" /> type to <see cref = "BigDecimal" />.</summary>
/// <param name = "value" ><see cref = "System.Single" /> value to be converted.</param>
/// <returns>The converted <see cref = "BigDecimal" />.</returns>
public static explicit operator float ( BigDecimal value )
{
return Convert.ToSingle ( ( double ) value );
}
/// <summary>Explicit conversion from <see cref = "System.Double" /> type to <see cref = "BigDecimal" />.</summary>
/// <param name = "value" ><see cref = "System.Double" /> value to be converted.</param>
/// <returns>The converted <see cref = "BigDecimal" />.</returns>
public static explicit operator double ( BigDecimal value )
{
return ( double ) value.Mantissa * Math.Pow ( 10 , value.Exponent );
}
/// <summary>Explicit conversion from <see cref = "System.Decimal" /> type to <see cref = "BigDecimal" />.</summary>
/// <param name = "value" ><see cref = "System.Decimal" /> value to be converted.</param>
/// <returns>The converted <see cref = "BigDecimal" />.</returns>
public static explicit operator decimal ( BigDecimal value )
{
return ( decimal ) value.Mantissa * ( decimal ) Math.Pow ( 10 , value.Exponent );
}
/// <summary>Returns the value of the <see cref = "BigDecimal" /> operand. (The sign of the operand is unchanged.)</summary>
/// <param name = "value" >A decimal value.</param>
/// <returns>The value of the value operand.</returns>
public static BigDecimal operator + ( BigDecimal value )
{
return value;
}
/// <summary>Negates a specified BigDecimal value.</summary>
/// <param name = "value" >The value to negate.</param>
/// <returns>The result of the value parameter multiplied by negative one (-1).</returns>
public static BigDecimal operator - ( BigDecimal value )
{
if ( value.Mantissa.Sign > 0 || value.Mantissa.Sign < 0 )
{
value.Mantissa *= -1;
}
return value;
}
/// <summary>Increments a <see cref = "BigDecimal" /> value by 1.</summary>
/// <param name = "value" >The value to increment.</param>
/// <returns>The value of the value parameter incremented by 1.</returns>
public static BigDecimal operator ++ ( BigDecimal value )
{
return value + One;
}
/// <summary>Decrements a <see cref = "BigDecimal" /> value by 1.</summary>
/// <param name = "value" >The value to decrement.</param>
/// <returns>The value of the value parameter decremented by 1.</returns>
public static BigDecimal operator -- ( BigDecimal value )
{
return value - One;
}
/// <summary>Adds the values of two specified BigDecimal objects.</summary>
/// <param name = "left" >The first value to add.</param>
/// <param name = "right" >The second value to add.</param>
/// <returns>The sum of left and right.</returns>
public static BigDecimal operator + ( BigDecimal left ,
BigDecimal right )
{
if ( left.Exponent > right.Exponent )
{
return new BigDecimal ( AlignExponent ( left , right ) + right.Mantissa , right.Exponent );
}
if ( right.Exponent > left.Exponent )
{
return new BigDecimal ( AlignExponent ( right , left ) + left.Mantissa , left.Exponent );
}
return new BigDecimal ( left.Mantissa + right.Mantissa , right.Exponent );
}
/// <summary>Subtracts a BigDecimal value from another BigDecimal value.</summary>
/// <param name = "left" >The value to subtract from (the minuend).</param>
/// <param name = "right" >The value to subtract (the subtrahend).</param>
/// <returns>The result of subtracting right from left.</returns>
public static BigDecimal operator - ( BigDecimal left ,
BigDecimal right )
{
return left + ( -right );
}
/// <summary>Multiplies two specified BigDecimal values.</summary>
/// <param name = "left" >The first value to multiply.</param>
/// <param name = "right" >The second value to multiply.</param>
/// <returns>The product of left and right.</returns>
public static BigDecimal operator * ( BigDecimal left ,
BigDecimal right )
{
return new BigDecimal ( left.Mantissa * right.Mantissa , left.Exponent + right.Exponent );
}
/// <summary>Divides a specified BigDecimal value by another specified BigDecimal value.</summary>
/// <param name = "dividend" >The value to be divided.</param>
/// <param name = "divisor" >The value to divide by.</param>
/// <returns>The integral result of the division.</returns>
/// <exception cref = "System.DivideByZeroException" ><paramref name = "divisor" /> is 0 (zero).</exception>
public static BigDecimal operator / ( BigDecimal dividend ,
BigDecimal divisor )
{
if ( divisor.IsZero )
{
throw new DivideByZeroException ();
}
int prec;
if ( dividend.Precision > divisor.Precision )
{
prec = dividend.Precision;
}
else
{
prec = divisor.Precision;
}
var exponentChange = prec - ( 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 );
}
/// <summary>Returns a value that indicates whether the values of two BigDecimal objects are equal.</summary>
/// <param name = "left" >The first value to compare.</param>
/// <param name = "right" >The second value to compare.</param>
/// <returns><c>true</c> if the left and right parameters have the same value; otherwise, <c>false</c>.</returns>
public static bool operator == ( BigDecimal left ,
BigDecimal right )
{
return left.Exponent == right.Exponent && left.Mantissa == right.Mantissa;
}
/// <summary>Returns a value that indicates whether two BigDecimal objects have different values.</summary>
/// <param name = "left" >The first value to compare.</param>
/// <param name = "right" >The second value to compare.</param>
/// <returns><c>true</c> if the left and right are not equal; otherwise, <c>false</c>.</returns>
public static bool operator != ( BigDecimal left ,
BigDecimal right )
{
return left.Exponent != right.Exponent || left.Mantissa != right.Mantissa;
}
/// <summary>Returns a value that indicates whether a BigDecimal value is less than another BigDecimal value.</summary>
/// <param name = "left" >The first value to compare.</param>
/// <param name = "right" >The second value to compare.</param>
/// <returns><c>true</c> if left is less than right; otherwise, <c>false</c>.</returns>
public static bool operator < ( BigDecimal left ,
BigDecimal right )
{
if ( left.Exponent > right.Exponent )
{
return AlignExponent ( left , right ) < right.Mantissa;
}
if ( right.Exponent > left.Exponent )
{
return left.Mantissa < AlignExponent ( right , left );
}
return left.Mantissa < right.Mantissa;
}
/// <summary>Returns a value that indicates whether a BigDecimal value is greater than another BigDecimal value.</summary>
/// <param name = "left" >The first value to compare.</param>
/// <param name = "right" >The second value to compare.</param>
/// <returns><c>true</c> if left is greater than right; otherwise, <c>false</c>.</returns>
public static bool operator > ( BigDecimal left ,
BigDecimal right )
{
if ( left.Exponent > right.Exponent )
{
return AlignExponent ( left , right ) > right.Mantissa;
}
if ( right.Exponent > left.Exponent )
{
return left.Mantissa > AlignExponent ( right , left );
}
return left.Mantissa > right.Mantissa;
}
/// <summary>Returns a value that indicates whether a BigDecimal value is less than or equal to another BigDecimal value.</summary>
/// <param name = "left" >The first value to compare.</param>
/// <param name = "right" >The second value to compare.</param>
/// <returns><c>true</c> if left is less than or equal to right; otherwise, <c>false</c>.</returns>
public static bool operator <= ( BigDecimal left ,
BigDecimal right )
{
if ( left.Exponent > right.Exponent )
{
return AlignExponent ( left , right ) <= right.Mantissa;
}
if ( right.Exponent > left.Exponent )
{
return left.Mantissa <= AlignExponent ( right , left );
}
return left.Mantissa <= right.Mantissa;
}
/// <summary>Returns a value that indicates whether a BigDecimal value is greater than or equal to another BigDecimal value.</summary>
/// <param name = "left" >The first value to compare.</param>
/// <param name = "right" >The second value to compare.</param>
/// <returns><c>true</c> if left is greater than right; otherwise, <c>false</c>.</returns>
public static bool operator >= ( BigDecimal left ,
BigDecimal right )
{
if ( left.Exponent > right.Exponent )
{
return AlignExponent ( left , right ) >= right.Mantissa;
}
if ( right.Exponent > left.Exponent )
{
return left.Mantissa >= AlignExponent ( right , left );
}
return left.Mantissa >= right.Mantissa;
}
#endregion
#region Override Methods
/// <summary>Converts the numeric value of the current BigDecimal object to its equivalent string representation.</summary>
/// <returns>The string representation of the current BigDecimal value.</returns>
public override string ToString ()
{
return this.ToString ( string.Empty , null );
}
/// <summary>Returns a value that indicates whether the current instance and a specified object have the same value.</summary>
/// <param name = "obj" >The object to compare.</param>
/// <returns><c>true</c> if the obj parameter is a <see cref = "BigDecimal" /> object or a type capable of implicit conversion to a <see cref = "BigDecimal" /> value, and its value is equal to the value of the current <see cref = "BigDecimal" /> object; otherwise, <c>false</c>.</returns>
public override bool Equals ( object obj )
{
if ( ReferenceEquals ( null , obj ) )
{
return false;
}
if ( obj is BigDecimal )
{
return this.Equals ( ( BigDecimal ) obj );
}
return false;
}
/// <summary>Returns the hash code for the current <see cref = "BigDecimal" /> object.</summary>
/// <returns>A 32-bit signed integer hash code.</returns>
public override int GetHashCode ()
{
unchecked
{
return ( this.Mantissa.GetHashCode () * 13 ) ^ this.Exponent;
}
}
#endregion
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment