Skip to content

Move integer/float parsing/formatting into a decimal-based package#697

Open
mcy wants to merge 3 commits intomainfrom
mcy/dec
Open

Move integer/float parsing/formatting into a decimal-based package#697
mcy wants to merge 3 commits intomainfrom
mcy/dec

Conversation

@mcy
Copy link
Copy Markdown
Member

@mcy mcy commented Apr 7, 2026

This PR adds a new decimal (aka base-10 floats) to the compiler, which very carefully parses all of the formats we care about while retaining exact precision.

This fixes what was essentially a workaround for using big.Float, which cannot exactly represent most floating-point literals. For example,0.1 has no exact representation. Previously, I implemented a hacky workaround which handled most cases where we only cared about float64 (53 bits) of precision, but not always. Instead of layering on more hacks, I implemented this abstraction.

The new type does not currently support arithmetic, although we will eventually need to implement it. Decimal arithmetic is very painful. I have already spent a week chasing bugs in this PR and do not want to spend even more time on fussy multi-base arithmetic.

Also worth noting that a few tests have changed, because we are able to get more precise results. In particular, this fixes a conformance error where 1e-10 in one of our tests would lose more precision than if we used float64 as the internal representation.

@mcy mcy requested review from ckoutsidi-b and doriable April 7, 2026 01:21
} else {
meta.Word = math.Float64bits(f64)
l.scratchFloat.SetUint64(0)
fmt.Println(digits)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: ^^" leftover debug message, maybe?

l.scratchFloat.SetUint64(0)
case v.IsFloat():
f, acc := v.Float().Float64()
fmt.Println(digits, f)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: same ^^"

braces []token.ID
scratch []byte
scratchFloat *big.Float
scratchInt big.Int
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: ... should we also store the pointer here?

return z
}

// IsInt returns whether this value is representable as a base 2 float.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: IsInt -> IsFloat

return f
}

// SetInt sets this decimal's value to x.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: SetInt -> SetFloat64 ^^"

Comment on lines +84 to +85
prec = 6
havePrec = true
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Is it worth having a comment that this corresponds to the defaults in fmt? Or is this a universal kind of default?

{in: "1.2.3", invalid: true},
// Invalid: exponent with no digits.
{in: "1e", invalid: true},
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have an invalid test case for 0x0.fe+4 (e.g. mixing bases in scientific notation)?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants