Cannot represent 2.4000000000000004 as (Numeric 10) without lost of precision

Hi all,

we ran into this issue yesterday for the first time since we’re using Daml:

io.grpc.StatusRuntimeException: INVALID_ARGUMENT: Command interpretation error in LF-DAMLe: Cannot represent 2.4000000000000004 as (Numeric 10) without lost of precision

we get this while trying to store the value of an off-ledger computation in a numeric field in a contract. we’re using the gRPC API. I am a bit surprised that Daml has this restriction.

so I guess my question is if anyone has seen this before and how you have handled it if so - or if there is a best practice DA can recommend to handle this generically across the code.

best regards,
Emil

1 Like

I recommend that you use a type in your client language that corresponds as closely to the Daml type as possible, e.g, use a java BigDecimal instead of a floating point number. If there is an exact correspondence than whatever conversions/rounding are done on the client side. In some cases, there may not be a direct equivalent (e.g. BigDecimal does not enforce the limited precision Numeric does). In those cases, you have to add some manual rounds/truncation when you’re building the values.

1 Like

Adding a little bit of background to @cocreature’s answer: Daml does not currently have a representation for floating-point numbers. This is by design: floating-point numbers are very hard to predict, and Daml is all about predictable results.

Instead, Daml uses fixed-precision numbers. Those are a lot easier to reason about and thus lead to more robust applications, at the cost of some convenience.

That’s what the 10 in Numeric 10 means: it’s a fixed-precision number with 10 decimals. The number you are trying to represent has 15 decimals, so that doesn’t fit and the last 4 would be truncated; you’d end up with 2.4. It’s very likely, in this case, that 2.4 is actually the value you want, but you’ll have to make that truncation explicitly yourself.

Alternatively, if you really do want that extra 4.10^-15, you could try working with Numeric 16 (or more) in your Daml code. Decimal (which may be what you’re using) is defined as an alias for Numeric 10.

3 Likes

Thanks guys. We did not expect these restrictions but we can make the necessary adjustment, there’s no problem.

just to clarity we’ve gotten into this not because we needed to, it’s one of those cases where some numbers (such as the result of 12 * 0.2 in this case) cannot be exactly represented using the IEEE 754 standard and are approximated to the value that got us into trouble.

regards
e/

1 Like

This is exactly why Daml doesn’t support floating-points:

$ python3
Python 3.9.10 (main, Jan 15 2022, 11:48:04) 
[Clang 13.0.0 (clang-1300.0.29.3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 0.1 + 0.2 == 0.3
False
>>> 
$ daml repl
daml> 0.1 + 0.2 == (0.3 : Decimal)
True
daml> 
Goodbye.
$ 
3 Likes