From 6735da1a3dc3ae1d34568532e00a96f021e697a4 Mon Sep 17 00:00:00 2001 From: Alexandr Gorshenin Date: Tue, 1 Oct 2024 18:21:25 +0100 Subject: [PATCH] Fix decimal INF, NEG_INF, NAN values --- .../tech/ydb/table/values/DecimalValue.java | 39 +++++++----- .../ydb/table/values/DecimalValueTest.java | 60 ++++++++++++++----- 2 files changed, 69 insertions(+), 30 deletions(-) diff --git a/table/src/main/java/tech/ydb/table/values/DecimalValue.java b/table/src/main/java/tech/ydb/table/values/DecimalValue.java index b85c729ac..3f528bab3 100644 --- a/table/src/main/java/tech/ydb/table/values/DecimalValue.java +++ b/table/src/main/java/tech/ydb/table/values/DecimalValue.java @@ -60,15 +60,15 @@ public long getLow() { } public boolean isInf() { - return this == INF; + return this.high == INF.high && this.low == INF.low; } public boolean isNegativeInf() { - return this == NEG_INF; + return this.high == NEG_INF.high && this.low == NEG_INF.low; } public boolean isNan() { - return this == NAN; + return this.high == NAN.high && this.low == NAN.low; } public boolean isZero() { @@ -273,19 +273,28 @@ private static long getLongBe(byte[] buf, int from, int to) { } private static boolean isNan(long high, long low) { - return NAN.getHigh() == high && NAN.getLow() == low; + return NAN.high == high && NAN.low == low; } private static boolean isInf(long high, long low) { - return high > INF.getHigh() || - (high == INF.getHigh() && Long.compareUnsigned(low, INF.getLow()) >= 0); + return high > INF.high || (high == INF.high && Long.compareUnsigned(low, INF.low) >= 0); } private static boolean isNegInf(long high, long low) { - return high < NEG_INF.getHigh() || - (high == NEG_INF.getHigh() && Long.compareUnsigned(low, NEG_INF.getLow()) <= 0); + return high < NEG_INF.high || (high == NEG_INF.high && Long.compareUnsigned(low, NEG_INF.low) <= 0); } + private static DecimalValue newNan(DecimalType type) { + return new DecimalValue(type, NAN.high, NAN.low); + } + + private static DecimalValue newInf(DecimalType type) { + return new DecimalValue(type, INF.high, INF.low); + } + + private static DecimalValue newNegInf(DecimalType type) { + return new DecimalValue(type, NEG_INF.high, NEG_INF.low); + } static DecimalValue fromUnscaledLong(DecimalType type, long value) { if (value == 0) { return new DecimalValue(type, 0, 0); @@ -300,15 +309,15 @@ static DecimalValue fromBits(DecimalType type, long high, long low) { } if (isNan(high, low)) { - return NAN; + return newNan(type); } if (isInf(high, low)) { - return INF; + return newInf(type); } if (isNegInf(high, low)) { - return NEG_INF; + return newNegInf(type); } return new DecimalValue(type, high, low); @@ -322,7 +331,7 @@ static DecimalValue fromUnscaledBigInteger(DecimalType type, BigInteger value) { boolean negative = value.signum() < 0; if (bitLength > 128) { - return negative ? DecimalValue.NEG_INF : DecimalValue.INF; + return negative ? newNegInf(type) : newInf(type); } byte[] buf = value.abs().toByteArray(); @@ -358,7 +367,7 @@ private static DecimalValue fromUnsignedLong(DecimalType type, boolean positive, lowHi = lowHi & HALF_LONG_MASK; if ((high & LONG_SIGN_BIT) != 0) { // number is too big, return infinite - return positive ? INF : NEG_INF; + return positive ? newInf(type) : newNegInf(type); } } @@ -408,11 +417,11 @@ static DecimalValue fromString(DecimalType type, String value) { char c3 = value.charAt(cursor + 2); if ((c1 == 'i' || c1 == 'I') && (c2 == 'n' || c2 == 'N') || (c3 == 'f' || c3 == 'F')) { - return negative ? DecimalValue.NEG_INF : DecimalValue.INF; + return negative ? newNegInf(type) : newInf(type); } if ((c1 == 'n' || c1 == 'N') && (c2 == 'a' || c2 == 'A') || (c3 == 'n' || c3 == 'N')) { - return DecimalValue.NAN; + return new DecimalValue(type, NAN.high, NAN.low); } } diff --git a/table/src/test/java/tech/ydb/table/values/DecimalValueTest.java b/table/src/test/java/tech/ydb/table/values/DecimalValueTest.java index 3dfd02f52..a11fbe0bb 100644 --- a/table/src/test/java/tech/ydb/table/values/DecimalValueTest.java +++ b/table/src/test/java/tech/ydb/table/values/DecimalValueTest.java @@ -80,7 +80,22 @@ public void inf() { DecimalValue value = type.newValue(inf); Assert.assertTrue(value.isInf()); Assert.assertFalse(value.isNegative()); - Assert.assertSame(DecimalValue.INF, value); + Assert.assertEquals(DecimalValue.INF, value); + inf = inf.add(k); + } + } + + @Test + public void infDefaulttype() { + DecimalType type = DecimalType.getDefault(); + BigInteger inf = BigInteger.TEN.pow(DecimalType.MAX_PRECISION); + BigInteger k = BigInteger.valueOf(0x10000000_00000000L); + + for (int i = 0; i < 100; i++) { + DecimalValue value = type.newValue(inf); + Assert.assertTrue(value.isInf()); + Assert.assertFalse(value.isNegative()); + Assert.assertNotEquals(DecimalValue.INF, value); inf = inf.add(k); } } @@ -95,7 +110,22 @@ public void negativeInf() { DecimalValue value = type.newValue(inf); Assert.assertTrue(value.isNegativeInf()); Assert.assertTrue(value.isNegative()); - Assert.assertSame(DecimalValue.NEG_INF, value); + Assert.assertEquals(DecimalValue.NEG_INF, value); + inf = inf.subtract(k); + } + } + + @Test + public void negativeInfDefaultType() { + DecimalType type = DecimalType.getDefault(); + BigInteger inf = BigInteger.TEN.negate().pow(DecimalType.MAX_PRECISION); + BigInteger k = BigInteger.valueOf(0x10000000_00000000L); + + for (int i = 0; i < 100; i++) { + DecimalValue value = type.newValue(inf); + Assert.assertTrue(value.isNegativeInf()); + Assert.assertTrue(value.isNegative()); + Assert.assertNotEquals(DecimalValue.NEG_INF, value); inf = inf.subtract(k); } } @@ -126,19 +156,19 @@ public void zero() { public void ofString() { DecimalType t = DecimalType.getDefault(); - Assert.assertSame(DecimalValue.INF, t.newValue("inf")); - Assert.assertSame(DecimalValue.INF, t.newValue("Inf")); - Assert.assertSame(DecimalValue.INF, t.newValue("INF")); - Assert.assertSame(DecimalValue.INF, t.newValue("+inf")); - Assert.assertSame(DecimalValue.INF, t.newValue("+Inf")); - Assert.assertSame(DecimalValue.INF, t.newValue("+INF")); - Assert.assertSame(DecimalValue.NEG_INF, t.newValue("-inf")); - Assert.assertSame(DecimalValue.NEG_INF, t.newValue("-Inf")); - Assert.assertSame(DecimalValue.NEG_INF, t.newValue("-INF")); - Assert.assertSame(DecimalValue.NAN, t.newValue("nan")); - Assert.assertSame(DecimalValue.NAN, t.newValue("Nan")); - Assert.assertSame(DecimalValue.NAN, t.newValue("NaN")); - Assert.assertSame(DecimalValue.NAN, t.newValue("NAN")); + Assert.assertTrue(t.newValue("inf").isInf()); + Assert.assertTrue(t.newValue("Inf").isInf()); + Assert.assertTrue(t.newValue("INF").isInf()); + Assert.assertTrue(t.newValue("+inf").isInf()); + Assert.assertTrue(t.newValue("+Inf").isInf()); + Assert.assertTrue(t.newValue("+INF").isInf()); + Assert.assertTrue(t.newValue("-inf").isNegativeInf()); + Assert.assertTrue(t.newValue("-Inf").isNegativeInf()); + Assert.assertTrue(t.newValue("-INF").isNegativeInf()); + Assert.assertTrue(t.newValue("nan").isNan()); + Assert.assertTrue(t.newValue("Nan").isNan()); + Assert.assertTrue(t.newValue("NaN").isNan()); + Assert.assertTrue(t.newValue("NAN").isNan()); Assert.assertTrue(t.newValue("0").isZero()); Assert.assertTrue(t.newValue("00").isZero());