csharp/EPAM.Deltix.DFP/Decimal64.cs (805 lines of code) (raw):
using System;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Text;
[assembly: InternalsVisibleTo("EPAM.Deltix.DFP.Math")]
namespace EPAM.Deltix.DFP
{
[Serializable()]
public struct Decimal64 : IComparable<Decimal64>, IEquatable<Decimal64>, ISerializable
{
#region Constants
public static readonly Decimal64 Null = new Decimal64(DotNetImpl.Null);
public static readonly Decimal64 NaN = new Decimal64(DotNetImpl.NaN);
public static readonly Decimal64 PositiveInfinity = new Decimal64(DotNetImpl.PositiveInfinity);
public static readonly Decimal64 NegativeInfinity = new Decimal64(DotNetImpl.NegativeInfinity);
public static readonly Decimal64 MinValue = new Decimal64(DotNetImpl.MinValue);
public static readonly Decimal64 MaxValue = new Decimal64(DotNetImpl.MaxValue);
public static readonly Decimal64 MinPositiveValue = new Decimal64(DotNetImpl.MinPositiveValue);
public static readonly Decimal64 MaxNegativeValue = new Decimal64(DotNetImpl.MaxNegativeValue);
public static readonly Decimal64 Zero = new Decimal64(DotNetImpl.Zero);
public static readonly Decimal64 One = new Decimal64(DotNetImpl.One);
public static readonly Decimal64 Two = new Decimal64(DotNetImpl.Two);
public static readonly Decimal64 Ten = new Decimal64(DotNetImpl.Ten);
public static readonly Decimal64 Hundred = new Decimal64(DotNetImpl.Hundred);
public static readonly Decimal64 Thousand = new Decimal64(DotNetImpl.Thousand);
public static readonly Decimal64 Million = new Decimal64(DotNetImpl.Million);
public static readonly Decimal64 OneTenth = new Decimal64(DotNetImpl.OneTenth);
public static readonly Decimal64 OneHundredth = new Decimal64(DotNetImpl.OneHundredth);
public static readonly int MaxSignificandDigits = 16;
public static readonly int MaxExponent = 384;
public static readonly int MinExponent = -383;
public const char DecimalMarkDot = '.';
public const char DecimalMarkComma = ',';
public const char DecimalMarkDefault = DecimalMarkDot;
public static string DecimalMarkAny = "" + DecimalMarkDot + DecimalMarkComma;
#endregion
public UInt64 Bits { get; }
internal Decimal64(UInt64 value)
{
Bits = value;
}
#region Standard overloads
public override String ToString()
{
return DotNetImpl.ToString(Bits, DecimalMarkDefault, false);
}
public String ToString(char decimalMark)
{
return DotNetImpl.ToString(Bits, decimalMark, false);
//return ((Double)this).ToString(CultureInfo.InvariantCulture);
}
public override Boolean Equals(Object obj)
{
return obj is Decimal64 && Equals((Decimal64)obj);
}
public override Int32 GetHashCode()
{
UInt64 bits = Canonize().Bits;
return bits.GetHashCode();
}
#endregion
#region Conversion
public static Decimal64 FromFixedPoint(int mantissa, int numberOfDigits)
{
return new Decimal64(DotNetImpl.FromFixedPoint32(mantissa, numberOfDigits));
}
public static Decimal64 FromFixedPoint(uint mantissa, int numberOfDigits)
{
return new Decimal64(DotNetImpl.FromFixedPoint32(mantissa, numberOfDigits));
}
public static Decimal64 FromFixedPoint(long mantissa, int numberOfDigits)
{
// TODO: More optimizations
return new Decimal64(
0 == (mantissa & (-1L << 53))
? DotNetImpl.FromFixedPointLimitedU64((UInt64)mantissa, numberOfDigits)
: NativeImpl.fromFixedPoint64(mantissa, numberOfDigits));
}
public static Decimal64 FromFixedPoint(int mantissa, uint numberOfDigits)
{
return numberOfDigits < Int32.MaxValue ? FromFixedPoint(mantissa, (int)numberOfDigits) : Decimal64.Zero;
}
public static Decimal64 FromFixedPoint(uint mantissa, uint numberOfDigits)
{
return numberOfDigits < Int32.MaxValue ? FromFixedPoint(mantissa, (int)numberOfDigits) : Decimal64.Zero;
}
public static Decimal64 FromFixedPoint(long mantissa, uint numberOfDigits)
{
return numberOfDigits < Int32.MaxValue ? FromFixedPoint(mantissa, (int)numberOfDigits) : Decimal64.Zero;
}
public Int64 ToFixedPoint(int numberOfDigits)
{
return NativeImpl.toFixedPoint(Bits, numberOfDigits);
}
public static Decimal64 FromLong(long value)
{
return new Decimal64(NativeImpl.fromInt64(value));
}
public long ToLong()
{
return NativeImpl.toInt64(Bits);
}
public static Decimal64 FromULong(ulong value)
{
return new Decimal64(NativeImpl.fromUInt64(value));
}
public ulong ToULong()
{
return NativeImpl.toUInt64(Bits);
}
public static Decimal64 FromInt(int value)
{
return new Decimal64(DotNetImpl.FromInt32(value));
}
public int ToInt()
{
return (int)NativeImpl.toInt64(Bits);
}
public static Decimal64 FromUInt(uint value)
{
return new Decimal64(DotNetImpl.FromUInt32(value));
}
public uint ToUInt()
{
return (uint)NativeImpl.toUInt64(Bits);
}
public short ToShort()
{
return (short)NativeImpl.toInt64(Bits);
}
public ushort ToUShort()
{
return (ushort)NativeImpl.toUInt64(Bits);
}
public sbyte ToSByte()
{
return (sbyte)NativeImpl.toInt64(Bits);
}
public byte ToByte()
{
return (byte)NativeImpl.toUInt64(Bits);
}
public static Decimal64 FromUnderlying(UInt64 bits)
{
return new Decimal64(bits);
}
public UInt64 ToUnderlying()
{
return Bits;
}
public static Decimal64 FromDouble(Double value)
{
return new Decimal64(NativeImpl.fromFloat64(value));
}
public static Decimal64 FromDecimalDouble(Double value)
{
return new Decimal64(DotNetImpl.FromDecimalFloat64(value));
}
public Double ToDouble()
{
return NativeImpl.toFloat64(Bits);
}
public static Decimal64 FromDecimal(Decimal value)
{
return new Decimal64(DotNetImpl.FromDecimal(value));
}
public Decimal ToDecimal()
{
return DotNetImpl.ToDecimal(ToUnderlying());
}
#endregion
#region Conversion(Explicit operators)
public static explicit operator Decimal64(long value)
{
return FromLong(value);
}
public static explicit operator long(Decimal64 decimal64)
{
return decimal64.ToLong();
}
public static explicit operator Decimal64(ulong value)
{
return FromULong(value);
}
public static explicit operator ulong(Decimal64 decimal64)
{
return decimal64.ToULong();
}
public static explicit operator Decimal64(int value)
{
return FromInt(value);
}
public static explicit operator int(Decimal64 decimal64)
{
return decimal64.ToInt();
}
public static explicit operator Decimal64(uint value)
{
return FromUInt(value);
}
public static explicit operator uint(Decimal64 decimal64)
{
return decimal64.ToUInt();
}
public static explicit operator Decimal64(short value)
{
return FromInt(value);
}
public static explicit operator short(Decimal64 decimal64)
{
return decimal64.ToShort();
}
public static explicit operator Decimal64(ushort value)
{
return FromUInt(value);
}
public static explicit operator ushort(Decimal64 decimal64)
{
return decimal64.ToUShort();
}
public static explicit operator Decimal64(sbyte value)
{
return FromInt(value);
}
public static explicit operator sbyte(Decimal64 decimal64)
{
return decimal64.ToSByte();
}
public static explicit operator Decimal64(byte value)
{
return FromUInt(value);
}
public static explicit operator byte(Decimal64 decimal64)
{
return decimal64.ToByte();
}
public static explicit operator Decimal64(Double value)
{
return FromDouble(value);
}
public static explicit operator double(Decimal64 decimal64)
{
return decimal64.ToDouble();
}
public static explicit operator Decimal(Decimal64 decimal64)
{
return decimal64.ToDecimal();
}
public static explicit operator Decimal64(Decimal value)
{
return FromDecimal(value);
}
#endregion
#region Classification
/// <summary>
/// Returns <code>true</code> if the supplied <code>DFP</code> value equals dedicated <code>NULL</code> constant
/// (in the range of the NaN values) that imply null reference of type <see cref="Decimal64"/>.
/// </summary>
/// <returns><code>true</code> for dedicated <code>NULL</code> constant</returns>
public Boolean IsNull()
{
return DotNetImpl.IsNull(Bits);
}
/// <summary>
/// Checks is the <code>DFP</code> value is Not-a-Number.
/// If you need check for all abnormal values use negation of the <see cref="IsFinite"/> function.
/// </summary>
/// <returns><code>true</code> for Not-a-Number values.</returns>
public Boolean IsNaN()
{
return DotNetImpl.IsNaN(Bits);
}
/// <summary>
/// Checks is the <code>DFP</code> value is positive or negative infinity.
/// If you need check for all abnormal values use negation of the <see cref="IsFinite"/> function.
/// </summary>
/// <returns><code>true</code> for positive or negative infinity.</returns>
public Boolean IsInfinity()
{
return DotNetImpl.IsInfinity(Bits);
}
/// <summary>
/// Checks is the <code>DFP</code> value is positive infinity.
/// If you need check for all abnormal values use negation of the <see cref="IsFinite"/> function.
/// </summary>
/// <returns><code>true</code> for positive infinity.</returns>
public Boolean IsPositiveInfinity()
{
return DotNetImpl.IsPositiveInfinity(Bits);
}
/// <summary>
/// Checks is the <code>DFP</code> value is negative infinity.
/// If you need check for all abnormal values use negation of the <see cref="IsFinite"/> function.
/// </summary>
/// <returns><code>true</code> for negative infinity.</returns>
public Boolean IsNegativeInfinity()
{
return DotNetImpl.IsNegativeInfinity(Bits);
}
[Obsolete("IsSigned is deprecated, please use IsNegative instead for actual comparison with 0")]
public Boolean IsSigned()
{
return DotNetImpl.SignBit(Bits);
}
/// <summary>
/// Checks is the <code>DFP</code> value is a finite value: not a NaN, not a positive infinity, not a negative infinity.
/// </summary>
/// <returns><code>true</code> for finite values.</returns>
public Boolean IsFinite()
{
return DotNetImpl.IsFinite(Bits);
}
public Boolean IsNormal()
{
return NativeImpl.isNormal(Bits);
}
#endregion
#region Comparison
public Boolean IsEqual(Decimal64 that)
{
UInt64 aBits = Bits, bBits = that.Bits;
return aBits == bBits || NativeImpl.isEqual(aBits, bBits);
}
public static Boolean operator ==(Decimal64 a, Decimal64 b)
{
return a.IsEqual(b);
}
public Boolean IsIdentical(Decimal64 that)
{
return Bits == that.Bits;
}
public Boolean IsNotEqual(Decimal64 that)
{
UInt64 aBits = Bits, bBits = that.Bits;
return aBits != bBits && NativeImpl.isNotEqual(aBits, bBits);
}
public static Boolean operator !=(Decimal64 a, Decimal64 b)
{
return a.IsNotEqual(b);
}
public Boolean IsGreater(Decimal64 that)
{
return NativeImpl.isGreater(Bits, that.Bits);
}
public static Boolean operator >(Decimal64 a, Decimal64 b)
{
return NativeImpl.isGreater(a.Bits, b.Bits);
}
public Boolean IsLess(Decimal64 that)
{
return NativeImpl.isLess(Bits, that.Bits);
}
public static Boolean operator <(Decimal64 a, Decimal64 b)
{
return NativeImpl.isLess(a.Bits, b.Bits);
}
public Boolean IsGreaterOrEqual(Decimal64 that)
{
return NativeImpl.isGreaterOrEqual(Bits, that.Bits);
}
public static Boolean operator >=(Decimal64 a, Decimal64 b)
{
return NativeImpl.isGreaterOrEqual(a.Bits, b.Bits);
}
public Boolean IsLessOrEqual(Decimal64 that)
{
return NativeImpl.isLessOrEqual(Bits, that.Bits);
}
public static Boolean operator <=(Decimal64 a, Decimal64 b)
{
return NativeImpl.isLessOrEqual(a.Bits, b.Bits);
}
/// <summary>
/// Checks is the <code>DFP</code> value is zero.
/// </summary>
/// <returns><code>true</code> for zero.</returns>
public Boolean IsZero()
{
return DotNetImpl.IsZero(Bits);
}
/// <summary>
/// Checks is the <code>DFP</code> value is not a zero or abnormal: NaN or positive infinity or negative infinity.
/// </summary>
/// <returns><code>true</code> for not a zero or abnormal.</returns>
public Boolean IsNonZero()
{
return !DotNetImpl.IsZero(Bits);
}
/// <summary>
/// Checks is the <code>DFP</code> value is greater than zero.
/// If you need check for values greater or equal to zero use <see cref="IsNonNegative"/> function.
/// </summary>
/// <returns><code>true</code> for values greater than zero.</returns>
public Boolean IsPositive()
{
return DotNetImpl.IsPositive(Bits);
}
/// <summary>
/// Checks is the <code>DFP</code> value is less than zero.
/// If you need check for values less or equal to zero use <see cref="IsNonPositive"/> function.
/// </summary>
/// <returns><code>true</code> for values less than zero.</returns>
public Boolean IsNegative()
{
return DotNetImpl.IsNegative(Bits);
}
/// <summary>
/// Checks is the <code>DFP</code> value is less or equal to zero.
/// If you need check for values strictly less than zero use <see cref="IsNegative"/> function.
/// </summary>
/// <returns><code>true</code> for values less or equal to zero.</returns>
public Boolean IsNonPositive()
{
return DotNetImpl.IsNonPositive(Bits);
}
/// <summary>
/// Checks is the <code>DFP</code> value is greater or equal to zero.
/// If you need check for values strictly greater than zero use <see cref="IsPositive"/> function.
/// </summary>
/// <returns><code>true</code> for values greater or equal to zero.</returns>
public Boolean IsNonNegative()
{
return DotNetImpl.IsNonNegative(Bits);
}
#endregion
#region Minimum & Maximum
public static Decimal64 Max(Decimal64 a, Decimal64 b)
{
return new Decimal64(NativeImpl.max2(a.Bits, b.Bits));
}
public static Decimal64 Max(Decimal64 a, Decimal64 b, Decimal64 c)
{
return new Decimal64(NativeImpl.max3(a.Bits, b.Bits, c.Bits));
}
public static Decimal64 Max(Decimal64 a, Decimal64 b, Decimal64 c, Decimal64 d)
{
return new Decimal64(NativeImpl.max4(a.Bits, b.Bits, c.Bits, d.Bits));
}
public static Decimal64 Min(Decimal64 a, Decimal64 b)
{
return new Decimal64(NativeImpl.min2(a.Bits, b.Bits));
}
public static Decimal64 Min(Decimal64 a, Decimal64 b, Decimal64 c)
{
return new Decimal64(NativeImpl.min3(a.Bits, b.Bits, c.Bits));
}
public static Decimal64 Min(Decimal64 a, Decimal64 b, Decimal64 c, Decimal64 d)
{
return new Decimal64(NativeImpl.min4(a.Bits, b.Bits, c.Bits, d.Bits));
}
public Decimal64 Max(Decimal64 b)
{
return new Decimal64(NativeImpl.max2(Bits, b.Bits));
}
public Decimal64 Min(Decimal64 b)
{
return new Decimal64(NativeImpl.min2(Bits, b.Bits));
}
#endregion
#region Arithmetic
public static Decimal64 operator +(Decimal64 value)
{
return value;
}
public Decimal64 Negate()
{
return new Decimal64(DotNetImpl.Negate(Bits));
}
public static Decimal64 operator -(Decimal64 value)
{
return new Decimal64(DotNetImpl.Negate(value.Bits));
}
public Decimal64 Abs()
{
return new Decimal64(DotNetImpl.Abs(Bits));
}
public Decimal64 Add(Decimal64 b)
{
return new Decimal64(NativeImpl.add2(Bits, b.Bits));
}
public Decimal64 Add(Decimal64 b, Decimal64 c)
{
return new Decimal64(NativeImpl.add3(Bits, b.Bits, c.Bits));
}
public Decimal64 Add(Decimal64 b, Decimal64 c, Decimal64 d)
{
return new Decimal64(NativeImpl.add4(Bits, b.Bits, c.Bits, d.Bits));
}
public static Decimal64 operator +(Decimal64 a, Decimal64 b)
{
return new Decimal64(NativeImpl.add2(a.Bits, b.Bits));
}
public Decimal64 Subtract(Decimal64 b)
{
return new Decimal64(NativeImpl.subtract(Bits, b.Bits));
}
public static Decimal64 operator -(Decimal64 a, Decimal64 b)
{
return new Decimal64(NativeImpl.subtract(a.Bits, b.Bits));
}
public Decimal64 Multiply(Decimal64 b)
{
return new Decimal64(NativeImpl.multiply2(Bits, b.Bits));
}
public Decimal64 Multiply(Decimal64 b, Decimal64 c)
{
return new Decimal64(NativeImpl.multiply3(Bits, b.Bits, c.Bits));
}
public Decimal64 Multiply(Decimal64 b, Decimal64 c, Decimal64 d)
{
return new Decimal64(NativeImpl.multiply4(Bits, b.Bits, c.Bits, d.Bits));
}
public static Decimal64 operator *(Decimal64 a, Decimal64 b)
{
return new Decimal64(NativeImpl.multiply2(a.Bits, b.Bits));
}
public Decimal64 MultiplyByInteger(Int32 b)
{
return new Decimal64(NativeImpl.multiplyByInt32(Bits, b));
}
public Decimal64 MultiplyByInteger(Int64 b)
{
return new Decimal64(NativeImpl.multiplyByInt64(Bits, b));
}
public static Decimal64 operator *(Decimal64 a, Int32 b)
{
return new Decimal64(NativeImpl.multiplyByInt32(a.Bits, b));
}
public static Decimal64 operator *(Int32 a, Decimal64 b)
{
return new Decimal64(NativeImpl.multiplyByInt32(b.Bits, a));
}
public static Decimal64 operator *(Decimal64 a, Int64 b)
{
return new Decimal64(NativeImpl.multiplyByInt64(a.Bits, b));
}
public static Decimal64 operator *(Int64 a, Decimal64 b)
{
return new Decimal64(NativeImpl.multiplyByInt64(b.Bits, a));
}
public Decimal64 Divide(Decimal64 b)
{
return new Decimal64(NativeImpl.divide(Bits, b.Bits));
}
public static Decimal64 operator /(Decimal64 a, Decimal64 b)
{
return new Decimal64(NativeImpl.divide(a.Bits, b.Bits));
}
public Decimal64 DivideByInteger(Int32 b)
{
return new Decimal64(NativeImpl.divideByInt32(Bits, b));
}
public Decimal64 DivideByInteger(Int64 b)
{
return new Decimal64(NativeImpl.divideByInt64(Bits, b));
}
public static Decimal64 operator /(Decimal64 a, Int32 b)
{
return new Decimal64(NativeImpl.divideByInt32(a.Bits, b));
}
public static Decimal64 operator /(Decimal64 a, Int64 b)
{
return new Decimal64(NativeImpl.divideByInt64(a.Bits, b));
}
public Decimal64 MultiplyAndAdd(Decimal64 b, Decimal64 c)
{
return new Decimal64(NativeImpl.multiplyAndAdd(Bits, b.Bits, c.Bits));
}
public Decimal64 ScaleByPowerOfTen(Int32 n)
{
return new Decimal64(NativeImpl.scaleByPowerOfTen(Bits, n));
}
public Decimal64 Mean(Decimal64 b)
{
return new Decimal64(NativeImpl.mean2(Bits, b.Bits));
}
#endregion
#region Rounding
public Decimal64 Ceiling()
{
return new Decimal64(NativeImpl.roundTowardsPositiveInfinity(Bits));
}
public Decimal64 RoundTowardsPositiveInfinity()
{
return new Decimal64(NativeImpl.roundTowardsPositiveInfinity(Bits));
}
public Decimal64 Floor()
{
return new Decimal64(NativeImpl.roundTowardsNegativeInfinity(Bits));
}
public Decimal64 RoundTowardsNegativeInfinity()
{
return new Decimal64(NativeImpl.roundTowardsNegativeInfinity(Bits));
}
public Decimal64 RoundTowardsZero()
{
return new Decimal64(NativeImpl.roundTowardsZero(Bits));
}
/// Identical to RoundToNearestTiesAwayFromZero
public Decimal64 Round()
{
return new Decimal64(NativeImpl.roundToNearestTiesAwayFromZero(Bits));
}
public Decimal64 RoundToNearestTiesAwayFromZero()
{
return new Decimal64(NativeImpl.roundToNearestTiesAwayFromZero(Bits));
}
public Decimal64 RoundToNearestTiesToEven()
{
return new Decimal64(NativeImpl.roundToNearestTiesToEven(Bits));
}
public Decimal64 RoundTowardsPositiveInfinity(Decimal64 multiple)
{
if (!multiple.IsFinite() || multiple.IsNonPositive())
throw new ArgumentException("Multiple must be a positive finite number.");
if (IsNaN())
return this;
UInt64 ratio = NativeImpl.roundTowardsPositiveInfinity(NativeImpl.divide(Bits, multiple.Bits));
return new Decimal64(NativeImpl.multiply2(ratio, multiple.Bits));
}
public Decimal64 RoundTowardsNegativeInfinity(Decimal64 multiple)
{
if (!multiple.IsFinite() || multiple.IsNonPositive())
throw new ArgumentException("Multiple must be a positive finite number.");
if (IsNaN())
return this;
UInt64 ratio = NativeImpl.roundTowardsNegativeInfinity(NativeImpl.divide(Bits, multiple.Bits));
return new Decimal64(NativeImpl.multiply2(ratio, multiple.Bits));
}
public Decimal64 RoundToNearestTiesAwayFromZero(Decimal64 multiple)
{
if (!multiple.IsFinite() || multiple.IsNonPositive())
throw new ArgumentException("Multiple must be a positive finite number.");
if (IsNaN())
return this;
UInt64 ratio = NativeImpl.roundToNearestTiesAwayFromZero(NativeImpl.divide(Bits, multiple.Bits));
return new Decimal64(NativeImpl.multiply2(ratio, multiple.Bits));
}
public Decimal64 RoundToNearestTiesToEven(Decimal64 multiple)
{
if (!multiple.IsFinite() || multiple.IsNonPositive())
throw new ArgumentException("Multiple must be a positive finite number.");
if (IsNaN())
return this;
UInt64 ratio = NativeImpl.roundToNearestTiesToEven(NativeImpl.divide(Bits, multiple.Bits));
return new Decimal64(NativeImpl.multiply2(ratio, multiple.Bits));
}
public Decimal64 Round(int n, RoundingMode roundType)
{
return new Decimal64(DotNetImpl.Round(Bits, n, roundType));
}
public bool IsRounded(int n)
{
return DotNetImpl.IsRounded(Bits, n);
}
public Decimal64 RoundToReciprocal(uint r, RoundingMode roundType)
{
return new Decimal64(DotNetImpl.RoundToReciprocal(Bits, r, roundType));
}
public bool IsRoundedToReciprocal(uint r)
{
return DotNetImpl.IsRoundedToReciprocal(Bits, r);
}
#endregion
#region Parts processing
/// <summary>
/// Returns the unscaled value of the <see cref="Decimal64"/> in the same way as Java's BigDecimal#unscaledValue() do.
/// For abnormal values return <see cref="long.MinValue"/>.
/// </summary>
/// <returns>The unscaled value of the <see cref="Decimal64"/>.</returns>
public long GetUnscaledValue() => GetUnscaledValue(long.MinValue);
/// <summary>
/// Returns the unscaled value of the <see cref="Decimal64"/> in the same way as Java's BigDecimal#unscaledValue() do.
/// </summary>
/// <param name="abnormalReturn">The value returned for abnormal values (NaN, +Inf, -Inf).</param>
/// <returns>The unscaled value of the <see cref="Decimal64"/>.</returns>
public long GetUnscaledValue(long abnormalReturn)
{
var value = Bits;
bool sign = DotNetImpl.SignBit(value);
if ((value & DotNetImpl.SpecialEncodingMask) != DotNetImpl.SpecialEncodingMask)
{
long coefficient = (long)(value & DotNetReImpl.SMALL_COEFF_MASK64);
return sign ? -coefficient : coefficient;
}
else
{
// special encodings
if ((value & DotNetReImpl.INFINITY_MASK64) == DotNetReImpl.INFINITY_MASK64)
{
return abnormalReturn; // NaN or Infinity
}
else
{
ulong coeff = (value & DotNetReImpl.LARGE_COEFF_MASK64) | DotNetReImpl.LARGE_COEFF_HIGH_BIT64;
if (coeff >= 10000000000000000UL)
coeff = 0;
return sign ? -(long)coeff : (long)coeff;
}
}
}
/// <summary>
/// Returns the scale of the <see cref="Decimal64"/> value in the same way as Java's BigDecimal#scale() do.
/// For abnormal values return <see cref="int.MinValue"/>.
/// </summary>
/// <returns>The scale of the <see cref="Decimal64"/>.</returns>
public int GetScale() => GetScale(int.MinValue);
/// <summary>
/// Returns the scale of the <see cref="Decimal64"/> value in the same way as Java's BigDecimal#scale() do.
/// </summary>
/// <param name="abnormalReturn">The value returned for abnormal values (NaN, +Inf, -Inf).</param>
/// <returns>The scale of the <see cref="Decimal64"/>.</returns>
public int GetScale(int abnormalReturn)
{
var value = Bits;
if ((value & DotNetImpl.SpecialEncodingMask) != DotNetImpl.SpecialEncodingMask)
{
return -((int)((value >> DotNetReImpl.EXPONENT_SHIFT_SMALL64) & DotNetReImpl.EXPONENT_MASK64) - DotNetReImpl.DECIMAL_EXPONENT_BIAS);
}
else
{
// special encodings
if ((value & DotNetReImpl.INFINITY_MASK64) == DotNetReImpl.INFINITY_MASK64)
return abnormalReturn;
else
return -((int)((value >> DotNetReImpl.EXPONENT_SHIFT_LARGE64) & DotNetReImpl.EXPONENT_MASK64) - DotNetReImpl.DECIMAL_EXPONENT_BIAS);
}
}
/// endregion
#endregion
#region Special
public Decimal64 NextUp()
{
return new Decimal64(NativeImpl.nextUp(Bits));
}
public Decimal64 NextDown()
{
return new Decimal64(NativeImpl.nextDown(Bits));
}
/// <summary>
/// Returns canonical representation of Decimal.
/// We consider that all binary representations of one arithmetic value have the same canonical binary representation.
/// Canonical representation of zeros = <see cref="Zero"/>>
/// Canonical representation of NaNs = <see cref="NaN"/>
/// Canonical representation of PositiveInfinities = <see cref="PositiveInfinity"/>
/// Canonical representation of NegativeInfinities = <see cref="NegativeInfinity"/>
/// </summary>
/// <returns>Canonical representation of decimal argument.</returns>
public Decimal64 Canonize()
{
if (IsNaN())
{
return NaN;
}
if (IsInfinity())
{
if (IsPositiveInfinity())
{
return PositiveInfinity;
}
else
{
return NegativeInfinity;
}
}
return new Decimal64(DotNetImpl.Canonize(this.Bits));
}
#endregion
#region Formatting & Parsing
public static Decimal64 Parse(String text)
{
uint fpsf;
var ret = DotNetReImpl.bid64_from_string(text, DecimalMarkDot, out fpsf);
if ((fpsf & DotNetReImpl.BID_INVALID_FORMAT) != 0)
throw new FormatException("Input string is not in a correct format.");
//else if ((fpsf & DotNetReImpl.BID_INEXACT_EXCEPTION) != 0)
// throw new FormatException("Can't convert input string to value without precision loss.");
return FromUnderlying(ret);
}
public static Decimal64 Parse(String text, String decimalMarks)
{
uint fpsf;
var ret = DotNetReImpl.bid64_from_string(text, decimalMarks, out fpsf);
if ((fpsf & DotNetReImpl.BID_INVALID_FORMAT) != 0)
throw new FormatException("Input string is not in a correct format.");
//else if ((fpsf & DotNetReImpl.BID_INEXACT_EXCEPTION) != 0)
// throw new FormatException("Can't convert input string to value without precision loss.");
return FromUnderlying(ret);
}
public enum StatusValue
{
Exact = (int)DotNetReImpl.BID_EXACT_STATUS,
Overflow = (int)DotNetReImpl.BID_OVERFLOW_EXCEPTION,
Underflow = (int)DotNetReImpl.BID_UNDERFLOW_EXCEPTION,
Inexact = (int)DotNetReImpl.BID_INEXACT_EXCEPTION,
InvalidFormat = (int)DotNetReImpl.BID_INVALID_FORMAT
}
public static Boolean TryParse(String text, out Decimal64 result, out StatusValue status)
{
uint fpsf;
result = FromUnderlying(DotNetReImpl.bid64_from_string(text, DecimalMarkDot, out fpsf));
status = (StatusValue)fpsf;
return status == StatusValue.Exact;
}
public static Boolean TryParse(String text, String decimalMarks, out Decimal64 result, out StatusValue status)
{
uint fpsf;
result = FromUnderlying(DotNetReImpl.bid64_from_string(text, decimalMarks, out fpsf));
status = (StatusValue)fpsf;
return status == StatusValue.Exact;
}
public static Boolean TryParse(String text, out Decimal64 result)
{
uint fpsf;
var ret = DotNetReImpl.bid64_from_string(text, DecimalMarkDot, out fpsf);
if ((fpsf & DotNetReImpl.BID_INVALID_FORMAT) != 0)
{
result = NaN;
return false;
}
result = FromUnderlying(ret);
return true;
}
public static Boolean TryParse(String text, String decimalMarks, out Decimal64 result)
{
uint fpsf;
var ret = DotNetReImpl.bid64_from_string(text, decimalMarks, out fpsf);
if ((fpsf & DotNetReImpl.BID_INVALID_FORMAT) != 0)
{
result = NaN;
return false;
}
result = FromUnderlying(ret);
return true;
}
public String ToScientificString()
{
return DotNetImpl.ToScientificString(Bits, DecimalMarkDefault);
}
public String ToScientificString(char decimalMark)
{
return DotNetImpl.ToScientificString(Bits, decimalMark);
}
public String ToFloatString()
{
return DotNetImpl.ToString(Bits, DecimalMarkDefault, true);
}
public String ToFloatString(char decimalMark)
{
return DotNetImpl.ToString(Bits, decimalMark, true);
}
public StringBuilder AppendTo(StringBuilder text)
{
return DotNetImpl.AppendTo(Bits, DecimalMarkDefault, false, text);
}
public StringBuilder AppendTo(char decimalMark, StringBuilder text)
{
return DotNetImpl.AppendTo(Bits, decimalMark, false, text);
}
public StringBuilder ScientificAppendTo(StringBuilder text)
{
return DotNetImpl.ScientificAppendTo(Bits, DecimalMarkDefault, text);
}
public StringBuilder ScientificAppendTo(char decimalMark, StringBuilder text)
{
return DotNetImpl.ScientificAppendTo(Bits, decimalMark, text);
}
public StringBuilder FloatAppendTo(StringBuilder text)
{
return DotNetImpl.AppendTo(Bits, DecimalMarkDefault, true, text);
}
public StringBuilder FloatAppendTo(char decimalMark, StringBuilder text)
{
return DotNetImpl.AppendTo(Bits, decimalMark, true, text);
}
#endregion
#region IComparable<> Interface implementation
public Int32 CompareTo(Decimal64 other)
{
return NativeImpl.compare(Bits, other.Bits);
}
#endregion
#region IEquatable<> Interface implementation
public Boolean Equals(Decimal64 other)
{
return Canonize().Bits == other.Canonize().Bits;
}
#endregion
#region ISerializable Interface implementation
public Decimal64(SerializationInfo info, StreamingContext context)
{
Bits = info.GetUInt64("");
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("", Bits);
}
#endregion
}
}