Skip to content

Commit

Permalink
Merge pull request #61 from epam/master
Browse files Browse the repository at this point in the history
Remove Deprecated annotations
  • Loading branch information
alex-karpovich authored Nov 17, 2022
2 parents 843c398 + 1c1757a commit 0aca05f
Show file tree
Hide file tree
Showing 10 changed files with 535 additions and 210 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import com.epam.deltix.dfp.Decimal64Utils;

## What is under the hood?

DFP relies on [Intel Decimal Floating-Point Math Library](https://software.intel.com/content/www/us/en/develop/articles/intel-decimal-floating-point-math-library.html) that is written in C and provides implementation for IEEE 754-2008. Some operations are re-written in Java to avoid JNI calls.
DFP was inspired on [Intel Decimal Floating-Point Math Library](https://software.intel.com/content/www/us/en/develop/articles/intel-decimal-floating-point-math-library.html) that is written in C and provides implementation for IEEE 754-2008. Early DFP versions used JNI wrappers for this Intel library. Starting from the release 0.12 DFP is 100% Java.

## Supported platforms

Expand Down
35 changes: 35 additions & 0 deletions csharp/EPAM.Deltix.DFP.Test/Decimal64Test.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1178,6 +1178,41 @@ public void TestRoundDiv()
Assert.False(Decimal64.Parse("-Inf").IsRounded(10));
}

[Test]
public void TestToDecimalAndBack()
{
{
var refStr = "-0.00009147639003404085";
var dn = decimal.Parse(refStr + "00000001");
var d64 = Decimal64.FromDecimal(dn);
Assert.AreEqual(refStr, d64.ToString());
}

TestToDecimalAndBackCase(9937272758032147L, -24); // d1(=0.000000009937272758032147) != d2(=0.000000009937272758032149)
TestToDecimalAndBackCase(957877248391343793L, -23); // d1(=0.000009578772483913438) != d2(=0.000009578772483913439)
TestToDecimalAndBackCase(-9147639003404085469L, -23); // d1(=0.00009147639003404085) != d2(=0.00009147639003404083)

var random = new Random();
for (int ri = 0; ri < 1000000; ++ri)
{
long mantissa = ((long)random.Next(int.MinValue, int.MaxValue) << 32) | ((long)random.Next(int.MinValue, int.MaxValue) & 0xFFFFFFFFL);

int exp = random.Next(24) - 12 - Decimal64.MaxSignificandDigits;

TestToDecimalAndBackCase(mantissa, exp);
}
}

private static void TestToDecimalAndBackCase(long mantissa, int exp)
{
var d0 = Decimal64.FromFixedPoint(mantissa, -exp);
var d1 = d0.ToDecimal();
var d2 = Decimal64.FromDecimal(d1);

if (d0 != d2)
throw new Exception($"TestToDecimalAndBackCase({mantissa}L, {exp}); // d1(={d0}) != d2(={d2})");
}

readonly int N = 5000000;

static void Main()
Expand Down
9 changes: 0 additions & 9 deletions csharp/EPAM.Deltix.DFP/Decimal64.cs
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,6 @@ public Decimal64 Ceiling()
return new Decimal64(NativeImpl.roundTowardsPositiveInfinity(Bits));
}

[Obsolete("Call Round(0, RoundingMode.Ceiling) instead.")]
public Decimal64 RoundTowardsPositiveInfinity()
{
return new Decimal64(NativeImpl.roundTowardsPositiveInfinity(Bits));
Expand All @@ -669,13 +668,11 @@ public Decimal64 Floor()
return new Decimal64(NativeImpl.roundTowardsNegativeInfinity(Bits));
}

[Obsolete("Call Round(0, RoundingMode.Floor) instead.")]
public Decimal64 RoundTowardsNegativeInfinity()
{
return new Decimal64(NativeImpl.roundTowardsNegativeInfinity(Bits));
}

[Obsolete("Call Round(0, RoundingMode.Down) instead.")]
public Decimal64 RoundTowardsZero()
{
return new Decimal64(NativeImpl.roundTowardsZero(Bits));
Expand All @@ -687,19 +684,16 @@ public Decimal64 Round()
return new Decimal64(NativeImpl.roundToNearestTiesAwayFromZero(Bits));
}

[Obsolete("Call Round(0, RoundingMode.HalfUp) instead.")]
public Decimal64 RoundToNearestTiesAwayFromZero()
{
return new Decimal64(NativeImpl.roundToNearestTiesAwayFromZero(Bits));
}

[Obsolete("Call Round(0, RoundingMode.HalfEven) instead.")]
public Decimal64 RoundToNearestTiesToEven()
{
return new Decimal64(NativeImpl.roundToNearestTiesToEven(Bits));
}

[Obsolete("Call RoundToReciprocal(r, RoundingMode.Ceiling) instead.")]
public Decimal64 RoundTowardsPositiveInfinity(Decimal64 multiple)
{
if (!multiple.IsFinite() || multiple.IsNonPositive())
Expand All @@ -711,7 +705,6 @@ public Decimal64 RoundTowardsPositiveInfinity(Decimal64 multiple)
return new Decimal64(NativeImpl.multiply2(ratio, multiple.Bits));
}

[Obsolete("Call RoundToReciprocal(r, RoundingMode.Floor) instead.")]
public Decimal64 RoundTowardsNegativeInfinity(Decimal64 multiple)
{
if (!multiple.IsFinite() || multiple.IsNonPositive())
Expand All @@ -723,7 +716,6 @@ public Decimal64 RoundTowardsNegativeInfinity(Decimal64 multiple)
return new Decimal64(NativeImpl.multiply2(ratio, multiple.Bits));
}

[Obsolete("Call RoundToReciprocal(r, RoundingMode.HalfUp) instead.")]
public Decimal64 RoundToNearestTiesAwayFromZero(Decimal64 multiple)
{
if (!multiple.IsFinite() || multiple.IsNonPositive())
Expand All @@ -735,7 +727,6 @@ public Decimal64 RoundToNearestTiesAwayFromZero(Decimal64 multiple)
return new Decimal64(NativeImpl.multiply2(ratio, multiple.Bits));
}

[Obsolete("Call RoundToReciprocal(r, RoundingMode.HalfEven) instead.")]
public Decimal64 RoundToNearestTiesToEven(Decimal64 multiple)
{
if (!multiple.IsFinite() || multiple.IsNonPositive())
Expand Down
55 changes: 44 additions & 11 deletions csharp/EPAM.Deltix.DFP/DotNetImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -202,23 +202,55 @@ public static UInt64 FromFixedPoint32(UInt32 mantissa, int numDigits)
}


public static UInt64 FromDecimalFallback(Decimal dec)
// The internals from the https://referencesource.microsoft.com/#mscorlib/system/decimal.cs
[StructLayout(LayoutKind.Sequential)]
private struct DecimalNet
{
return NativeImpl.fromFloat64((double)dec);
// The lo, mid, hi, and flags fields contain the representation of the
// Decimal value. The lo, mid, and hi fields contain the 96-bit integer
// part of the Decimal. Bits 0-15 (the lower word) of the flags field are
// unused and must be zero; bits 16-23 contain must contain a value between
// 0 and 28, indicating the power of 10 to divide the 96-bit integer part
// by to produce the Decimal value; bits 24-30 are unused and must be zero;
// and finally bit 31 indicates the sign of the Decimal value, 0 meaning
// positive and 1 meaning negative.
//
// NOTE: Do not change the order in which these fields are declared. The
// native methods in this class rely on this particular order.
public uint flags;
public uint hi;
public uint lo;
public uint mid;
}

public static UInt64 FromDecimal(Decimal dec)
{
unsafe
{
UInt64 mantissa64 = ((UInt64*)&dec)[1];
Int32 signAndExp = ((Int16*)&dec)[1];
if (0 == ((UInt32*)&dec)[1] && mantissa64 <= 0x20000000000000)
return ((UInt64)signAndExp & SignMask) + mantissa64 +
((UInt64)(UInt32)(BaseExponent - signAndExp) << 53);
}
DecimalNet* decPtr = (DecimalNet*)&dec;
ulong sign = ((ulong)decPtr->flags & 0x80000000UL) << 32;
int exp = -((int)(decPtr ->flags >> 16) & 0xFF);
ulong mantissa;
if (decPtr->hi == 0)
{
mantissa = (((ulong)decPtr->mid) << 32) | ((ulong)decPtr->lo);
}
else
{
Pair96 pair96 = new Pair96(decPtr->lo, ((ulong)decPtr->mid) | (((ulong)decPtr->hi) << 32));

while (pair96.w21 > int.MaxValue)
{
pair96.Div(10);
exp++;
}

mantissa = (pair96.w21 << 32) | pair96.w0;
}

return FromDecimalFallback(dec);
BID_UINT32 fpsf = DotNetReImpl.BID_EXACT_STATUS;
return DotNetReImpl.get_BID64(sign, exp + DotNetReImpl.DECIMAL_EXPONENT_BIAS, mantissa, DotNetReImpl.BID_ROUNDING_TO_NEAREST, ref fpsf);
}
}

public static Decimal ToDecimalFallback(UInt64 value)
Expand Down Expand Up @@ -525,7 +557,7 @@ public static bool IsRounded(UInt64 value, int n)
BID_UINT64 partsCoefficient;
// DotNetReImpl.unpack_BID64(out partsSignMask, out partsExponent, out partsCoefficient, value);
{ // Copy-paste the toParts method for speedup
// partsSignMask = value & 0x8000000000000000UL;
// partsSignMask = value & 0x8000000000000000UL;

if ((value & DotNetReImpl.SPECIAL_ENCODING_MASK64) == DotNetReImpl.SPECIAL_ENCODING_MASK64)
{
Expand Down Expand Up @@ -1087,7 +1119,8 @@ public static bool IsRoundedToReciprocal(UInt64 value, uint r)
return IsRoundedToReciprocalImpl(addExponent, coefficientMulR, divFactor);
}

static bool IsRoundedToReciprocalImpl(int addExponent, Pair96 coefficientMulR, Factors96 divFactor) {
static bool IsRoundedToReciprocalImpl(int addExponent, Pair96 coefficientMulR, Factors96 divFactor)
{
//case RoundingMode.Unnecessary:
if (addExponent != 0 /*&& partsCoefficient != 0 - always true: checked earlier*/)
return false;
Expand Down
7 changes: 5 additions & 2 deletions docs/FAQ.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
# Frequently Asked Questions

## Why not use `decimal` C# data data type ?

Decimal in C# is just not that good.
Decimal in C# is just not that good.
* It is uses 12 bytes for mantissa (effectively 16)
* It does not have CLR support. i.e. all operators will be working as functions (slower than DFP).TODO: Benchmark proof.

## What are the *Checked functions in Java?
The *Checked functions in Java are not intended to be used directly.
These special functions are required just for ValueTypeAgent support.
Loading

0 comments on commit 0aca05f

Please sign in to comment.