Skip to content

float64 addition/subtraction returns wrong results for some operands #5806

@jubnzv

Description

@jubnzv

gno run and go run disagree on float64 + and - for certain operands. The divergence appears when the result underflows to a subnormal.

I found it by an arithmetic identity synthesized by my tool. I haven't checked deployed contracts for this pattern.

MRE

package main

import "math"

func main() {
	a := math.Float64frombits(9333378022939403091) // -2.662107816930723e-301
	b := math.Float64frombits(110005986185704326)  //  2.662107858822336e-301
	println(math.Float64bits(a + b))
}
$ go run main.go
847895691526144
$ gno run main.go
202154086

847895691526144 is correct (4.189161324398747e-309); gno returns 202154086 (9.98e-316).

Subtraction is affected too:

package main

import "math"

func main() {
	p := math.Float64frombits(110005986185704326)
	q := math.Float64frombits(110005986084627283)
	println(math.Float64bits(p - q))
}
$ go run main.go
847895691526144
$ gno run main.go
202154086

Notes

  • Triggers when two near-equal, opposite-sign normal float64 cancel into a subnormal result (|result| < 2.2e-308).
  • * and / are not affected; direct subnormal operands are not affected.
  • Output uses math.Float64bits because builtin println formats floats differently in gno and go; the underlying values differ regardless of formatting.

Environment

  • gno: 991200c
  • go: go1.24.4 linux/amd64

Metadata

Metadata

Assignees

Labels

🐞 bugSomething isn't working

Type

No type
No fields configured for issues without a type.

Projects

Status
Triage

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions