eval: loss of Precision in Arithmetic Operations on 35-Digit Integers
What version of CUE are you using (cue version)?
$ cue version
cue version v0.12.0
go version go1.23.5
-buildmode exe
-compiler gc
-trimpath true
DefaultGODEBUG asynctimerchan=1,gotypesalias=0,httpservecontentkeepheaders=1,tls3des=1,tlskyber=0,x509keypairleaf=0,x509negativeserial=1
CGO_ENABLED 1
GOARCH arm64
GOOS darwin
GOARM64 v8.0
cue.lang.version v0.12.0
Does this issue reproduce with the latest stable release?
Yes
What did you do?
exec cue eval
cmp stdout stdout.golden
-- x.cue --
package x
a: 10000000000000000000000000000000001
b: 10000000000000000000000000000000000 + 1
c: 10000000000000000000000000000000002 - 1
// 34-digit integer works
x: 9999999999999999999999999999999998
y: 9999999999999999999999999999999997 + 1
z: 9999999999999999999999999999999999 - 1
-- stdout.golden --
a: 10000000000000000000000000000000001
b: 10000000000000000000000000000000001
c: 10000000000000000000000000000000001
x: 9999999999999999999999999999999998
y: 9999999999999999999999999999999998
z: 9999999999999999999999999999999998
What did you expect to see?
I expected the test to pass. According to https://cuelang.org/docs/reference/spec/#numeric-values, I expected arithmetic operations on integer values to be performed with at least 256-bit precision.
What did you see instead?
$ testscript test.txtar
> exec cue eval
[stdout]
a: 10000000000000000000000000000000001
b: 1.000000000000000000000000000000000e+34
c: 1.000000000000000000000000000000000e+34
x: 9999999999999999999999999999999998
y: 9999999999999999999999999999999998
z: 9999999999999999999999999999999998
> cmp stdout stdout.golden
diff stdout stdout.golden
--- stdout
+++ stdout.golden
@@ -1,6 +1,6 @@
a: 10000000000000000000000000000000001
-b: 1.000000000000000000000000000000000e+34
-c: 1.000000000000000000000000000000000e+34
+b: 10000000000000000000000000000000001
+c: 10000000000000000000000000000000001
x: 9999999999999999999999999999999998
y: 9999999999999999999999999999999998
z: 9999999999999999999999999999999998
FAIL: test.txtar:2: stdout and stdout.golden differ
failed run
Thanks for the report @takonomura. Please can you provide some context in which you are running into this? For example, is this a financial application?
I will let @mpvl reply here in the first instance regarding CUE's choice to drop down to float here.
But for now just link https://github.com/cue-lang/cue/issues/1883. And further note that at least I have wondered if there is a place for a mode of CUE which use math/big or similar for all computations, with an acceptance in such a mode that performance will be impacted.
Please can you provide some context in which you are running into this?
I am trying to perform arithmetic operations on IP addresses by adapting the method described at https://github.com/cue-lang/cue/issues/3142#issuecomment-2110995389. The approach works well for IPv4 addresses (32-bit, 10 digits), but I encountered an issue when applying the same method to IPv6 addresses (128-bit, 39 digits).
@takonomura I see. I have replied in https://github.com/cue-lang/cue/issues/3142#issuecomment-2708228748. Happy to help move forward getting something added to the standard library if we can agree on a sensible API.
Here's an example that demonstrates that the + operator really does inappropriately drop down to float precision: it's not just an artifact of the export/display logic:
exec cue export x.cue
cmp stdout stdout.golden
-- x.cue --
import "strconv"
strconv.FormatInt(10000000000000000000000000000000000 + 1, 10)
-- stdout.golden --
"10000000000000000000000000000000001"
The above example fails with:
> exec cue export x.cue
[stderr]
error in call to strconv.FormatInt: cue: exponent should always be nil for integer types:
./x.cue:3:1
[exit status 1]
FAIL: /tmp/x.txtar:1: unexpected command failure