Skip to content

Commit

Permalink
Added BigDecimal trig functions and stuff.
Browse files Browse the repository at this point in the history
  • Loading branch information
SuprDewd committed Aug 6, 2011
1 parent e71aa91 commit aa55bc6
Show file tree
Hide file tree
Showing 4 changed files with 207 additions and 14 deletions.
162 changes: 150 additions & 12 deletions SharpBag/Math/BigDecimal.cs
Expand Up @@ -370,9 +370,19 @@ public static BigDecimal Parse(string value, int precision)
/// <returns>-Left</returns>
public static BigDecimal operator -(BigDecimal value) { return value.Negate(); }

/// <summary>
/// Implements the operator %.
/// </summary>
/// <param name="left">The left number.</param>
/// <param name="right">The right number.</param>
/// <returns>
/// The result of the operator.
/// </returns>
public static BigDecimal operator %(BigDecimal left, BigDecimal right) { return BigDecimal.Remainder(left, right); }

private BigDecimal Add(BigDecimal right, bool normalize)
{
BigDecimal.Normalize(ref this, ref right);
BigDecimal.Align(ref this, ref right);
BigDecimal result = new BigDecimal(this.Mantissa + right.Mantissa, this.Exponent, BigDecimal.PrecisionFor(ref this, ref right), false, this.UsingDefaultPrecision != right.UsingDefaultPrecision || this.UsingDefaultPrecision);

if (normalize)
Expand All @@ -391,7 +401,7 @@ private BigDecimal Add(BigDecimal right)

private BigDecimal Subtract(BigDecimal right, bool normalize)
{
BigDecimal.Normalize(ref this, ref right);
BigDecimal.Align(ref this, ref right);
BigDecimal result = new BigDecimal(this.Mantissa - right.Mantissa, this.Exponent, BigDecimal.PrecisionFor(ref this, ref right), false, this.UsingDefaultPrecision != right.UsingDefaultPrecision || this.UsingDefaultPrecision);

if (normalize)
Expand Down Expand Up @@ -447,6 +457,52 @@ private BigDecimal Divide(BigDecimal right)
return new BigDecimal(pos ? mantissa : -mantissa, exponent, precision - BigDecimal.ExtraPrecision - 2, false, this.UsingDefaultPrecision != right.UsingDefaultPrecision || this.UsingDefaultPrecision);
}

/// <summary>
/// Computes the absolute value of the value.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>The absolute value.</returns>
public static BigDecimal Abs(BigDecimal value)
{
return new BigDecimal(BigInteger.Abs(value.Mantissa), value.Exponent, value.Precision, value.Normalized, value.UsingDefaultPrecision);
}

/// <summary>
/// Computes the left number divided by the right number and the remainder of that divison.
/// </summary>
/// <param name="left">The left number.</param>
/// <param name="right">The right number.</param>
/// <param name="remainder">The remainder.</param>
/// <returns>The result of the division.</returns>
public static BigDecimal DivRem(BigDecimal left, BigDecimal right, out BigDecimal remainder)
{
BigDecimal.Align(ref left, ref right);
int precision = BigDecimal.PrecisionFor(ref left, ref right);

bool leftPos = left.Mantissa >= 0,
rightPos = right.Mantissa >= 0,
pos = !(leftPos ^ rightPos);

BigInteger curRemainder,
mantissa = BigInteger.DivRem(leftPos ? left.Mantissa : -left.Mantissa, rightPos ? right.Mantissa : -right.Mantissa, out curRemainder);

remainder = new BigDecimal(leftPos ? curRemainder : -curRemainder, left.Exponent, precision, false, false);
return new BigDecimal(pos ? mantissa : -mantissa, 0, precision, false, false);
}

/// <summary>
/// Computes the remainder of the division of the two numbers.
/// </summary>
/// <param name="left">The left number.</param>
/// <param name="right">The right number.</param>
/// <returns>The remainder.</returns>
public static BigDecimal Remainder(BigDecimal left, BigDecimal right)
{
BigDecimal rem;
BigDecimal.DivRem(left, right, out rem);
return rem;
}

/// <summary>
/// Raise the BigDecimal to the specified power.
/// </summary>
Expand Down Expand Up @@ -484,7 +540,7 @@ public static BigDecimal Pow(BigDecimal value, BigDecimal power)
if (power < 0) return BigDecimal.Reciprocal(BigDecimal.Pow(value, -power));
if (power == 0) return new BigDecimal(1, 0, value.Precision, true, value.UsingDefaultPrecision);
if (power == 1) return new BigDecimal(value);
return BigDecimal.Exp(BigDecimal.Ln(value) * power);
return BigDecimal.Exp(BigDecimal.Log(value) * power);
}

/// <summary>
Expand All @@ -503,22 +559,21 @@ public static BigDecimal Log10(BigDecimal value)

while (digits < precision)
{
// m = BigDecimal.Pow(new BigDecimal(m, value.Precision).Divide(BigInteger.Pow(10, a)), 10);
m = BigDecimal.Pow(m / BigInteger.Pow(10, a), 10);
a = (int)BigInteger.Log10(m.Mantissa) + m.Exponent;
mantissa = mantissa * 10 + a;
digits++;
}

return new BigDecimal(mantissa, -digits, value.Precision, false, value.UsingDefaultPrecision) /*.RoundLastDigit()*/;
return new BigDecimal(mantissa, -digits, value.Precision, false, value.UsingDefaultPrecision);
}

/// <summary>
/// Calculates the natural logarithm of the value.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>The natural logarithm.</returns>
public static BigDecimal Ln(BigDecimal value)
public static BigDecimal Log(BigDecimal value)
{
return BigDecimal.Log10(value) / Constants.Log10EBig(value.Precision);
}
Expand Down Expand Up @@ -591,6 +646,89 @@ public static BigDecimal Exp(BigDecimal value)
return BigDecimal.Round(result, value.Precision + 1);
}

/// <summary>
/// Computes the sine of the specified value.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>The sine of the specified value.</returns>
public static BigDecimal Sin(BigDecimal value)
{
BigDecimal result = value,
result2 = result * result,
lastResult,
it = BigDecimal.One.WithPrecision(value.Precision),
fact = BigDecimal.One.WithPrecision(value.Precision),
pow = value;

bool alt = false;

do
{
lastResult = result;
pow *= result2;
fact *= (it + 1) * (it + 2);

if (alt) result += pow / fact;
else result -= pow / fact;
alt = !alt;
it += 2;
}
while (result != lastResult);

if (BigDecimal.Abs(result) > 1) throw new ArgumentOutOfRangeException("value must be between -2pi and 2pi");
return result;
}

/// <summary>
/// Computes the cosine of the specified value.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>The cosine of the specified value.</returns>
public static BigDecimal Cos(BigDecimal value)
{
BigDecimal result = BigDecimal.One.WithPrecision(value.Precision),
result2 = value * value,
lastResult,
it = BigDecimal.Zero.WithPrecision(value.Precision),
fact = BigDecimal.One.WithPrecision(value.Precision),
pow = result;

bool alt = false;

do
{
lastResult = result;
pow *= result2;
fact *= (it + 1) * (it + 2);

if (alt) result += pow / fact;
else result -= pow / fact;
alt = !alt;
it += 2;
}
while (result != lastResult);

if (BigDecimal.Abs(result) > 1) throw new ArgumentOutOfRangeException("value must be between -2pi and 2pi");
return result;
}

/// <summary>
/// Computes the tangent of the specified value.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>The tangent of the specified value.</returns>
public static BigDecimal Tan(BigDecimal value)
{
try
{
return BigDecimal.Sin(value) / BigDecimal.Cos(value);
}
catch (ArgumentOutOfRangeException)
{
throw;
}
}

/// <summary>
/// Rounds the BigDecimal.
/// </summary>
Expand Down Expand Up @@ -668,7 +806,7 @@ public static BigDecimal Round(BigDecimal value, int digits = 0)

private bool Equals(BigDecimal other, bool normalize)
{
BigDecimal.Normalize(ref this, ref other);
BigDecimal.Align(ref this, ref other);
bool eq = this.WithoutExtraPrecision().Mantissa.Equals(other.WithoutExtraPrecision().Mantissa);

if (normalize)
Expand Down Expand Up @@ -710,7 +848,7 @@ public int CompareTo(BigDecimal other)
BigDecimal left = this.WithoutExtraPrecision(),
right = other.WithoutExtraPrecision();

BigDecimal.Normalize(ref left, ref right);
BigDecimal.Align(ref left, ref right);
return left.Mantissa.CompareTo(right.Mantissa);
}

Expand Down Expand Up @@ -931,7 +1069,7 @@ private void Normalize()
}
}

private void NormalizeTo(BigDecimal other)
private void AlignWith(BigDecimal other)
{
if (this.Exponent > other.Exponent)
{
Expand All @@ -940,10 +1078,10 @@ private void NormalizeTo(BigDecimal other)
}
}

private static void Normalize(ref BigDecimal a, ref BigDecimal b)
private static void Align(ref BigDecimal a, ref BigDecimal b)
{
if (a.Exponent > b.Exponent) a.NormalizeTo(b);
else b.NormalizeTo(a);
if (a.Exponent > b.Exponent) a.AlignWith(b);
else b.AlignWith(a);
}

private static int PrecisionFor(ref BigDecimal a, ref BigDecimal b)
Expand Down
Binary file modified SharpBag/bin/Release/CodeContracts/SharpBag.Contracts.dll
Binary file not shown.
Binary file modified SharpBag/bin/Release/SharpBag.dll
Binary file not shown.
59 changes: 57 additions & 2 deletions SharpBag/bin/Release/SharpBagDocs.xml
Expand Up @@ -414,6 +414,40 @@
<param name="value">The value.</param>
<returns>-Left</returns>
</member>
<member name="M:SharpBag.Math.BigDecimal.op_Modulus(SharpBag.Math.BigDecimal,SharpBag.Math.BigDecimal)">
<summary>
Implements the operator %.
</summary>
<param name="left">The left number.</param>
<param name="right">The right number.</param>
<returns>
The result of the operator.
</returns>
</member>
<member name="M:SharpBag.Math.BigDecimal.Abs(SharpBag.Math.BigDecimal)">
<summary>
Computes the absolute value of the value.
</summary>
<param name="value">The value.</param>
<returns>The absolute value.</returns>
</member>
<member name="M:SharpBag.Math.BigDecimal.DivRem(SharpBag.Math.BigDecimal,SharpBag.Math.BigDecimal,SharpBag.Math.BigDecimal@)">
<summary>
Computes the left number divided by the right number and the remainder of that divison.
</summary>
<param name="left">The left number.</param>
<param name="right">The right number.</param>
<param name="remainder">The remainder.</param>
<returns>The result of the division.</returns>
</member>
<member name="M:SharpBag.Math.BigDecimal.Remainder(SharpBag.Math.BigDecimal,SharpBag.Math.BigDecimal)">
<summary>
Computes the remainder of the division of the two numbers.
</summary>
<param name="left">The left number.</param>
<param name="right">The right number.</param>
<returns>The remainder.</returns>
</member>
<member name="M:SharpBag.Math.BigDecimal.Pow(SharpBag.Math.BigDecimal,System.Int32)">
<summary>
Raise the BigDecimal to the specified power.
Expand All @@ -437,7 +471,7 @@
<param name="value">The BigDecimal.</param>
<returns>The base-10 logarithm of the BigDecimal.</returns>
</member>
<member name="M:SharpBag.Math.BigDecimal.Ln(SharpBag.Math.BigDecimal)">
<member name="M:SharpBag.Math.BigDecimal.Log(SharpBag.Math.BigDecimal)">
<summary>
Calculates the natural logarithm of the value.
</summary>
Expand Down Expand Up @@ -473,6 +507,27 @@
<param name="value">The BigDecimal.</param>
<returns>e ^ x</returns>
</member>
<member name="M:SharpBag.Math.BigDecimal.Sin(SharpBag.Math.BigDecimal)">
<summary>
Computes the sine of the specified value.
</summary>
<param name="value">The value.</param>
<returns>The sine of the specified value.</returns>
</member>
<member name="M:SharpBag.Math.BigDecimal.Cos(SharpBag.Math.BigDecimal)">
<summary>
Computes the cosine of the specified value.
</summary>
<param name="value">The value.</param>
<returns>The cosine of the specified value.</returns>
</member>
<member name="M:SharpBag.Math.BigDecimal.Tan(SharpBag.Math.BigDecimal)">
<summary>
Computes the tangent of the specified value.
</summary>
<param name="value">The value.</param>
<returns>The tangent of the specified value.</returns>
</member>
<member name="M:SharpBag.Math.BigDecimal.Round(SharpBag.Math.BigDecimal,System.Int32)">
<summary>
Rounds the BigDecimal.
Expand Down Expand Up @@ -4815,7 +4870,7 @@
</member>
<member name="P:SharpBag.Math.Constants.PiDivTwo">
<summary>
Pi divided by 2.
Pi divided by two.
</summary>
<remarks>Pi / 2</remarks>
</member>
Expand Down

0 comments on commit aa55bc6

Please sign in to comment.