Skip to content

Commit

Permalink
Daml-LF: change Numeric max scale from 38 to 37 (digital-asset#2969)
Browse files Browse the repository at this point in the history
* daml-lf: numeric maxScale change from 38 to 37

* daml-lf: update spec

* udpate protobuf comments
  • Loading branch information
remyhaemmerle-da authored and mergify[bot] committed Sep 23, 2019
1 parent 7a2e12d commit d540f7a
Show file tree
Hide file tree
Showing 12 changed files with 96 additions and 92 deletions.
4 changes: 2 additions & 2 deletions daml-lf/archive/da/daml_lf_1.proto
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ message Type {
Forall forall = 5;
Tuple tuple = 7;
// *Available in versions >= 1.dev*
// *Must be between 0 and 38 (bounds inclusive)*
// *Must be between 0 and 37 (bounds inclusive)*
// use standard signed long for future usage.
sint64 nat = 11;
}
Expand Down Expand Up @@ -501,7 +501,7 @@ message PrimLit {

// Numeric literal ('LitNumeric')
//
// Serialization of number with precision 38 and scale between 0 and 38
// Serialization of number with precision 38 and scale between 0 and 37
//
// *Must be a string that matched
// `-?([0-1]\d*|0)\.(\d*)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ class DecodeV1Spec

def buildNat(i: Long) = DamlLf1.Type.newBuilder().setNat(i).build()

val validNatTypes = List(0, 1, 2, 5, 11, 35, 37, 38)
val invalidNatTypes = List(Long.MinValue, -100, -2, -1, 39, 40, 200, Long.MaxValue)
val validNatTypes = List(0, 1, 2, 5, 11, 35, 36, 37)
val invalidNatTypes = List(Long.MinValue, -100, -2, -1, 38, 39, 200, Long.MaxValue)

"reject nat type if lf version < 1.dev" in {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import scala.util.Try

/** The model of our floating point decimal numbers.
*
* These are numbers of precision 38 (38 decimal digits), and variable scale (from 0 to 38 bounds
* These are numbers of precision 38 (38 decimal digits), and variable scale (from 0 to 37 bounds
* included).
*/
abstract class NumericModule {
Expand All @@ -38,7 +38,8 @@ abstract class NumericModule {
val Scale: ScaleModule = new ScaleModule {
override type Scale = Int
override val MinValue: Scale = 0
override val MaxValue: Scale = maxPrecision
// We want 1 be representable at any scale, so we have to prevent (Numeric 38).
override val MaxValue: Scale = maxPrecision - 1
override private[NumericModule] def cast(x: Int): Scale = x
}

Expand Down Expand Up @@ -231,7 +232,10 @@ abstract class NumericModule {
case validScaledFormat(intPart, decPart) =>
val scale = decPart.length
val precision = if (intPart == "0") scale else intPart.length + scale
Either.cond(precision <= maxPrecision, cast(new BigDecimal(s).setScale(scale)), errMsg)
Either.cond(
precision <= maxPrecision && scale <= Scale.MaxValue,
cast(new BigDecimal(s).setScale(scale)),
errMsg)
case _ =>
Left(errMsg)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ class NumericSpec
(1, "0.0000"),
(10, "10.01234567890000000"),
(10, "9999999999999999999999999999.9999999999"),
(37, "0.0000000000000000000000000000000000001"),
(38, "0.99999999999999999999999999999999999999"),
(38, "0.00000000000000000000016180339887499677"),
(38, "-0.99999999999999999999999999999999999999")
(36, "0.000000000000000000000000000000000001"),
(37, "9.9999999999999999999999999999999999999"),
(37, "9.0000000000000000000016180339887499677"),
(37, "-9.9999999999999999999999999999999999999")
)

forEvery(testCases) { (scale, bigDec) =>
Expand All @@ -52,8 +52,8 @@ class NumericSpec
(0, "-100000000000000000000000000000000000000."),
(17, "10000000000000000000000.0000000000000000"),
(3, "8284590452353602874713526624977572470."),
(38, "1.00000000000000000000000000000000000000"),
(38, "-1.00000000000000000000000000000000000001"),
(37, "10.0000000000000000000000000000000000000"),
(37, "-10.0000000000000000000000000000000000001"),
)

forEvery(testCases) { (scale, bigDec) =>
Expand All @@ -68,8 +68,8 @@ class NumericSpec
(0, "-0.1"),
(17, "10000000000000000.000000000000000001"),
(3, "0.82845"),
(38, "0.00000000000000000000000000000000000000000100"),
(38, "-0.000000000000000000000000000000000000001"),
(37, "0.0000000000000000000000000000000000000000100"),
(37, "-0.00000000000000000000000000000000000001"),
)

forEvery(testCases) { (scale, bigDec) =>
Expand All @@ -88,8 +88,8 @@ class NumericSpec
("input1", "input2"),
("99999999999999999999999999999999999999.", "1."),
("-1.", "-99999999999999999999999999999999999999."),
("0.99999999999999999999999999999999999999", "0.00000000000000000000000000000000000001"),
("-0.99999999999999999999999999999999999999", "-0.00000000000000000000000000000000000001"),
("9.9999999999999999999999999999999999999", "0.0000000000000000000000000000000000001"),
("-9.9999999999999999999999999999999999999", "-0.0000000000000000000000000000000000001"),
("9999999999999999999999.0000000000000000", "1.0000000000000000"),
("5678901234567890.1234567890123456789012", "5678901234567890.1234567890123456789012")
)
Expand All @@ -106,9 +106,9 @@ class NumericSpec
("input1", "input2", "result"),
("0.00000", "0.00000", "0.00000"),
(
"0.99999999999999999999999999999999999999",
"-0.00000000000000000000000000000000000001",
"0.99999999999999999999999999999999999998"),
"9.9999999999999999999999999999999999999",
"-0.0000000000000000000000000000000000001",
"9.9999999999999999999999999999999999998"),
(
"3.1415926535897932384626433832795028842",
"2.7182818284590452353602874713526624978",
Expand Down Expand Up @@ -143,8 +143,8 @@ class NumericSpec
("input1", "input2"),
("-99999999999999999999999999999999999999.", "1."),
("-1.", "99999999999999999999999999999999999999."),
("0.99999999999999999999999999999999999999", "-0.00000000000000000000000000000000000001"),
("0.99999999999999999999999999999999999999", "-0.00000000000000000000000000000000000001"),
("9.9999999999999999999999999999999999999", "-0.0000000000000000000000000000000000001"),
("9.9999999999999999999999999999999999999", "-0.0000000000000000000000000000000000001"),
("9999999999999999999999.0000000000000000", "-1.0000000000000000"),
("567890123456789012345.67890123456789012", "-567890123456789012345.67890123456789012")
)
Expand All @@ -161,9 +161,9 @@ class NumericSpec
("input1", "input2", "result"),
("0.00000", "0.00000", "0.00000"),
(
"0.99999999999999999999999999999999999999",
"0.00000000000000000000000000000000000001",
"0.99999999999999999999999999999999999998"),
"9.9999999999999999999999999999999999999",
"0.0000000000000000000000000000000000001",
"9.9999999999999999999999999999999999998"),
(
"3.1415926535897932384626433832795028842",
"2.7182818284590452353602874713526624978",
Expand Down Expand Up @@ -217,16 +217,16 @@ class NumericSpec
("scale", "input1", "input2", "result"),
(5, "0.00000", "0.00000", "0.00000"),
(
38,
"0.00000000000000000010000000000000000000",
"0.00000000000000000010000000000000000000",
"0.00000000000000000000000000000000000001"
37,
"0.0000000000000000001000000000000000000",
"0.0000000000000000010000000000000000000",
"0.0000000000000000000000000000000000001"
),
(
37,
"1.0000000000000000000000000000000000000",
"-0.0000000000000000000000000000000000001",
"-0.0000000000000000000000000000000000001"
36,
"1.000000000000000000000000000000000000",
"-0.000000000000000000000000000000000001",
"-0.000000000000000000000000000000000001"
),
(
18,
Expand All @@ -235,10 +235,10 @@ class NumericSpec
"-1.000000000000000000"
),
(
37,
"3.1415926535897932384626433832795028842",
"2.7182818284590452353602874713526624978",
"8.5397342226735670654635508695465744952"
36,
"3.141592653589793238462643383279502884",
"2.718281828459045235360287471352662498",
"8.539734222673567065463550869546574495"
),
(
1,
Expand Down Expand Up @@ -290,9 +290,9 @@ class NumericSpec
(10, "1000000000000000000.0000000000", "0.0000000001"),
(1, "-1000000000000000000000000000000000000.0", "0.1"),
(
38,
"0.10000000000000000000000000000000000000",
"-0.10000000000000000000000000000000000000",
37,
"1.000000000000000000000000000000000000",
"-0.1000000000000000000000000000000000000",
),
(14, "5678901234567890.12345678901234", "-0.00000000001234"),
)
Expand All @@ -309,16 +309,16 @@ class NumericSpec
("scale", "input1", "input2", "result"),
(5, "0.00000", "1.00000", "0.00000"),
(
38,
"0.00000000000000000010000000000000000000",
"-0.00000000000000000100000000000000000000",
"-0.10000000000000000000000000000000000000"
37,
"0.0000000000000000001000000000000000000",
"-0.0000000000000000010000000000000000000",
"-0.1000000000000000000000000000000000000"
),
(
37,
"0.0000000000000000000000000000000000001",
"-0.1000000000000000000000000000000000001",
"-0.0000000000000000000000000000000000010"
36,
"0.000000000000000000000000000000000001",
"-0.100000000000000000000000000000000001",
"-0.000000000000000000000000000000000010"
),
(
18,
Expand All @@ -327,10 +327,10 @@ class NumericSpec
"-1000000000000000000.000000000000000000",
),
(
37,
"3.1415926535897932384626433832795028842",
"2.7182818284590452353602874713526624978",
"1.1557273497909217179100931833126962991"
36,
"3.141592653589793238462643383279502884",
"2.718281828459045235360287471352662498",
"1.155727349790921717910093183312696299"
),
(
1,
Expand Down Expand Up @@ -373,10 +373,10 @@ class NumericSpec
"return an error in case of overflow" in {
val testCases = Table[Long, Numeric](
("targetScale", "input"),
(37, "0.99999999999999999999999999999999999999"),
(36, "9.9999999999999999999999999999999999999"),
(1, "99999999999999999999999999999999.950000"),
(-38, "50000000000000000000000000000000000000."),
(36, "-0.99999999999999999999999999999999999996"),
(35, "-9.9999999999999999999999999999999999996"),
(-9, "-9999999999999999999950000000.0000000000"),
(0, "-99999999999999999999.678900000000000000"),
)
Expand Down Expand Up @@ -472,12 +472,12 @@ class NumericSpec
val testCases = Table(
"numerics",
Table[Numeric](
"(Numeric 38)",
"0.99999999999999999999999999999999999999",
"0.00000000000000000000000000000000000001",
"0.00000000000000000000000000000000000000",
"-0.00000000000000000000000000000000000001",
"-0.99999999999999999999999999999999999999"
"(Numeric 37)",
"9.9999999999999999999999999999999999999",
"0.0000000000000000000000000000000000001",
"0.0000000000000000000000000000000000000",
"-0.0000000000000000000000000000000000001",
"-9.9999999999999999999999999999999999999"
),
Table[Numeric](
"(Numeric 0)",
Expand Down Expand Up @@ -554,7 +554,7 @@ class NumericSpec
"string",
"999999999999999999999999999999999999999.",
"82845904523536028.7471352662497757247012",
"0.314159265358979323846264338327950288421",
"0.31415926535897932384626433832795028842",
"1E10",
"00.0",
"+0.1",
Expand All @@ -576,12 +576,12 @@ class NumericSpec
"string",
"99999999999999999999999999999999999999.",
"82845904523536028.747135266249775724701",
"0.31415926535897932384626433832795028842",
"0.3141592653589793238462643383279502884",
"0.0",
"-0.1",
"9876543210.0123456789",
"-0.99999999999999999999999999999999999999",
"-0.00000000000000000000000000000000000001",
"-9.9999999999999999999999999999999999999",
"-0.0000000000000000000000000000000000001",
)

forEvery(testCases) { x =>
Expand Down
2 changes: 1 addition & 1 deletion daml-lf/encoder/src/test/lf/Numeric_1.dev_.lf
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ module Numeric {
x0: Numeric 0,
x10: Numeric 10,
x17: Numeric 17,
x38: Numeric 38,
x37: Numeric 37,
party: Party
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,11 +227,11 @@ class SBuiltinTest extends FreeSpec with Matchers with TableDrivenPropertyChecks
"ADD_NUMERIC" - {
val builtin = "ADD_NUMERIC"

"throw exception in case of overflow" in {
"throws an exception in case of overflow" in {
eval(e"$builtin @0 ${"9" * 38}. -1.") shouldBe 'right
eval(e"$builtin @0 ${"9" * 38}. 1.") shouldBe 'left
eval(e"$builtin @38 0.${"9" * 38} -0.${"0" * 37}1") shouldBe 'right
eval(e"$builtin @38 0.${"9" * 38} 0.${"0" * 37}1") shouldBe 'left
eval(e"$builtin @37 9.${"9" * 37} -0.${"0" * 36}1") shouldBe 'right
eval(e"$builtin @37 9.${"9" * 37} 0.${"0" * 36}1") shouldBe 'left
eval(e"$builtin @10 ${s(10, bigBigDecimal)} ${s(10, two)}") shouldBe Right(
SNumeric(n(10, bigBigDecimal + 2)))
eval(e"$builtin @10 ${s(10, maxDecimal)} ${s(10, minPosDecimal)}") shouldBe 'left
Expand All @@ -244,11 +244,12 @@ class SBuiltinTest extends FreeSpec with Matchers with TableDrivenPropertyChecks

"SUB_NUMERIC" - {
val builtin = "SUB_NUMERIC"
"throws exception in case of overflow" in {

"throws an exception in case of overflow" in {
eval(e"$builtin @0 -${"9" * 38}. -1.") shouldBe 'right
eval(e"$builtin @0 -${"9" * 38}. 1.") shouldBe 'left
eval(e"$builtin @38 -0.${"9" * 38} -0.${"0" * 37}1") shouldBe 'right
eval(e"$builtin @38 -0.${"9" * 38} 0.${"0" * 37}1") shouldBe 'left
eval(e"$builtin @37 -9.${"9" * 37} -0.${"0" * 36}1") shouldBe 'right
eval(e"$builtin @37 -9.${"9" * 37} 0.${"0" * 36}1") shouldBe 'left
eval(e"$builtin @10 $bigBigDecimal ${s(10, two)}") shouldBe Right(
SNumeric(n(10, bigBigDecimal - 2)))
eval(e"$builtin @10 ${s(10, maxDecimal)} -$minPosDecimal") shouldBe 'left
Expand All @@ -264,7 +265,7 @@ class SBuiltinTest extends FreeSpec with Matchers with TableDrivenPropertyChecks
val underSqrtOfTen = "3.1622776601683793319988935444327185337"
val overSqrtOfTen = "3.1622776601683793319988935444327185338"

"throws exception in case of overflow" in {
"throws an exception in case of overflow" in {
eval(e"$builtin @0 @0 @0 1${"0" * 18}. 1${"0" * 19}.") shouldBe 'right
eval(e"$builtin @0 @0 @0 1${"0" * 19}. 1${"0" * 19}.") shouldBe 'left
eval(e"$builtin @37 @37 @37 $underSqrtOfTen $underSqrtOfTen") shouldBe 'right
Expand All @@ -283,9 +284,10 @@ class SBuiltinTest extends FreeSpec with Matchers with TableDrivenPropertyChecks

"DIV_NUMERIC" - {
val builtin = "DIV_NUMERIC"
"throws exception in case of overflow" in {
eval(e"$builtin @38 @38 @38 ${s(38, "1E-18")} ${s(38, "-1E-17")}") shouldBe 'right
eval(e"$builtin @38 @38 @38 ${s(38, "1E-18")} ${s(38, "-1E-18")}") shouldBe 'left

"throws an exception in case of overflow" in {
eval(e"$builtin @37 @37 @37 ${s(37, "1E-18")} ${s(37, "-1E-18")}") shouldBe 'right
eval(e"$builtin @37 @37 @37 ${s(37, "1E-18")} ${s(37, "-1E-19")}") shouldBe 'left
eval(e"$builtin @1 @1 @1 ${s(1, "1E36")} 0.2") shouldBe 'right
eval(e"$builtin @1 @1 @1 ${s(1, "1E36")} 0.1") shouldBe 'left
eval(e"$builtin @10 @10 @10 1.1000000000 2.2000000000") shouldBe Right(SNumeric(n(10, 0.5)))
Expand All @@ -298,7 +300,7 @@ class SBuiltinTest extends FreeSpec with Matchers with TableDrivenPropertyChecks
)
}

"throws exception when divided by 0" in {
"throws an exception when divided by 0" in {
eval(e"$builtin @10 @10 @10 ${s(10, one)} ${tenPowerOf(-10)}") shouldBe Right(
SNumeric(n(10, tenPowerOf(10))))
eval(e"$builtin @10 @10 @10 ${s(10, one)} ${s(10, zero)}") shouldBe 'left
Expand Down
4 changes: 2 additions & 2 deletions daml-lf/spec/daml-lf-1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ The literals represent actual DAML-LF values:
in base-10 without loss of precision with at most 38 digits
(ignoring possible leading 0 and with a scale (the number of
significant digits on the right of the decimal point) between ``0``
and ``38`` (bounds inclusive). In the following, we will use
and ``37`` (bounds inclusive). In the following, we will use
``scale(LitNumeric)`` to denote the scale of the decimal number.
* A ``LitDate`` represents the number of day since
``1970-01-01`` with allowed range from ``0001-01-01`` to
Expand Down Expand Up @@ -519,7 +519,7 @@ Then we can define our kinds, types, and expressions::
BuiltinType
::= 'TArrow' -- BTArrow: Arrow type
| 'Int64' -- BTyInt64: 64-bit integer
| 'Numeric' -- BTyNumeric: numeric, precision 38, parametric scale between 0 and 38
| 'Numeric' -- BTyNumeric: numeric, precision 38, parametric scale between 0 and 37
| 'Text' -- BTyText: UTF-8 string
| 'Date' -- BTyDate
| 'Timestamp' -- BTyTime: UTC timestamp
Expand Down
Loading

0 comments on commit d540f7a

Please sign in to comment.