using System;
using System.Text;
namespace Org.BouncyCastle.Math.EC.Abc
{
/**
* Class representing a simple version of a big decimal. A
* SimpleBigDecimal
is basically a
* {@link java.math.BigInteger BigInteger} with a few digits on the right of
* the decimal point. The number of (binary) digits on the right of the decimal
* point is called the scale
of the SimpleBigDecimal
.
* Unlike in {@link java.math.BigDecimal BigDecimal}, the scale is not adjusted
* automatically, but must be set manually. All SimpleBigDecimal
s
* taking part in the same arithmetic operation must have equal scale. The
* result of a multiplication of two SimpleBigDecimal
s returns a
* SimpleBigDecimal
with double scale.
*/
internal class SimpleBigDecimal
// : Number
{
// private static final long serialVersionUID = 1L;
private readonly BigInteger bigInt;
private readonly int scale;
/**
* Returns a SimpleBigDecimal
representing the same numerical
* value as value
.
* @param value The value of the SimpleBigDecimal
to be
* created.
* @param scale The scale of the SimpleBigDecimal
to be
* created.
* @return The such created SimpleBigDecimal
.
*/
public static SimpleBigDecimal GetInstance(BigInteger val, int scale)
{
return new SimpleBigDecimal(val.ShiftLeft(scale), scale);
}
/**
* Constructor for SimpleBigDecimal
. The value of the
* constructed SimpleBigDecimal
Equals bigInt /
* 2scale
.
* @param bigInt The bigInt
value parameter.
* @param scale The scale of the constructed SimpleBigDecimal
.
*/
public SimpleBigDecimal(BigInteger bigInt, int scale)
{
if (scale < 0)
throw new ArgumentException("scale may not be negative");
this.bigInt = bigInt;
this.scale = scale;
}
private SimpleBigDecimal(SimpleBigDecimal limBigDec)
{
bigInt = limBigDec.bigInt;
scale = limBigDec.scale;
}
private void CheckScale(SimpleBigDecimal b)
{
if (scale != b.scale)
throw new ArgumentException("Only SimpleBigDecimal of same scale allowed in arithmetic operations");
}
public SimpleBigDecimal AdjustScale(int newScale)
{
if (newScale < 0)
throw new ArgumentException("scale may not be negative");
if (newScale == scale)
return this;
return new SimpleBigDecimal(bigInt.ShiftLeft(newScale - scale), newScale);
}
public SimpleBigDecimal Add(SimpleBigDecimal b)
{
CheckScale(b);
return new SimpleBigDecimal(bigInt.Add(b.bigInt), scale);
}
public SimpleBigDecimal Add(BigInteger b)
{
return new SimpleBigDecimal(bigInt.Add(b.ShiftLeft(scale)), scale);
}
public SimpleBigDecimal Negate()
{
return new SimpleBigDecimal(bigInt.Negate(), scale);
}
public SimpleBigDecimal Subtract(SimpleBigDecimal b)
{
return Add(b.Negate());
}
public SimpleBigDecimal Subtract(BigInteger b)
{
return new SimpleBigDecimal(bigInt.Subtract(b.ShiftLeft(scale)), scale);
}
public SimpleBigDecimal Multiply(SimpleBigDecimal b)
{
CheckScale(b);
return new SimpleBigDecimal(bigInt.Multiply(b.bigInt), scale + scale);
}
public SimpleBigDecimal Multiply(BigInteger b)
{
return new SimpleBigDecimal(bigInt.Multiply(b), scale);
}
public SimpleBigDecimal Divide(SimpleBigDecimal b)
{
CheckScale(b);
BigInteger dividend = bigInt.ShiftLeft(scale);
return new SimpleBigDecimal(dividend.Divide(b.bigInt), scale);
}
public SimpleBigDecimal Divide(BigInteger b)
{
return new SimpleBigDecimal(bigInt.Divide(b), scale);
}
public SimpleBigDecimal ShiftLeft(int n)
{
return new SimpleBigDecimal(bigInt.ShiftLeft(n), scale);
}
public int CompareTo(SimpleBigDecimal val)
{
CheckScale(val);
return bigInt.CompareTo(val.bigInt);
}
public int CompareTo(BigInteger val)
{
return bigInt.CompareTo(val.ShiftLeft(scale));
}
public BigInteger Floor()
{
return bigInt.ShiftRight(scale);
}
public BigInteger Round()
{
SimpleBigDecimal oneHalf = new SimpleBigDecimal(BigInteger.One, 1);
return Add(oneHalf.AdjustScale(scale)).Floor();
}
public int IntValue
{
get { return Floor().IntValue; }
}
public long LongValue
{
get { return Floor().LongValue; }
}
// public double doubleValue()
// {
// return new Double(ToString()).doubleValue();
// }
//
// public float floatValue()
// {
// return new Float(ToString()).floatValue();
// }
public int Scale
{
get { return scale; }
}
public override string ToString()
{
if (scale == 0)
return bigInt.ToString();
BigInteger floorBigInt = Floor();
BigInteger fract = bigInt.Subtract(floorBigInt.ShiftLeft(scale));
if (bigInt.SignValue < 0)
{
fract = BigInteger.One.ShiftLeft(scale).Subtract(fract);
}
if ((floorBigInt.SignValue == -1) && (!(fract.Equals(BigInteger.Zero))))
{
floorBigInt = floorBigInt.Add(BigInteger.One);
}
string leftOfPoint = floorBigInt.ToString();
char[] rightOfPoint = new char[scale];
string fractStr = fract.ToString(2);
int fractLen = fractStr.Length;
int zeroes = scale - fractLen;
for (int i = 0; i < zeroes; i++)
{
rightOfPoint[i] = '0';
}
for (int j = 0; j < fractLen; j++)
{
rightOfPoint[zeroes + j] = fractStr[j];
}
StringBuilder sb = new StringBuilder(leftOfPoint);
sb.Append(".");
sb.Append(rightOfPoint);
return sb.ToString();
}
public override bool Equals(
object obj)
{
if (this == obj)
return true;
SimpleBigDecimal other = obj as SimpleBigDecimal;
if (other == null)
return false;
return bigInt.Equals(other.bigInt)
&& scale == other.scale;
}
public override int GetHashCode()
{
return bigInt.GetHashCode() ^ scale;
}
}
}