Skip to content

Conversation

@petrosagg
Copy link
Contributor

This PR fixes a regression introduced in #83 which started serializing floats using their scientific notation, which is much shorter than the decimal notation and therefore faster.

It turns out that conversion from string to decimal is syntactic instead of semantic. This means that the strings "12" and "1.2E2", which are semantically the same number, parse into a different Decimal instance.

This PR fixes the regression by serializing to the decimal representation.

The overall improvement from 0.4.9 is much more mild as a result.

parse_decimal           time:   [2.4036 µs 2.4180 µs 2.4389 µs]
                        change: [-22.670% -21.979% -21.336%] (p = 0.00 < 0.05)
                        Performance has improved.

This PR fixes a regression introduced in #83 which started serializing
floats using their scientific notation, which is much shorter than the
decimal notation and therefore faster.

It turns out that conversion from string to decimal is syntactic
instead of semantic. This means that the strings "12" and "1.2E2", which
are semantically the same number, parse into a different Decimal
instance.

This PR fixes the regression by serializing to the decimal
representation.

The overall improvement from 0.4.9 is much more mild as a result.

```
parse_decimal           time:   [2.4036 µs 2.4180 µs 2.4389 µs]
                        change: [-22.670% -21.979% -21.336%] (p = 0.00 < 0.05)
                        Performance has improved.
```

Signed-off-by: Petros Angelatos <petrosagg@gmail.com>
@petrosagg petrosagg requested a review from ParkMyCar May 7, 2025 10:53
// NOTE: The code is generic over any T: LowerExp but passing something like f128 wouldn't
// always work since there are f128 values that don't fit in 24 bytes.
pub fn from_float<T: LowerExp>(&mut self, n: T) -> Decimal<N> {
pub fn from_float<T: LowerExp + Display>(&mut self, n: T) -> Decimal<N> {

Choose a reason for hiding this comment

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

We should probably mark this #[inline(never)] like std does, wdyt?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

std marks it as such because the entry point of the user facing interface (i.e the Display impl on f64) goes through this function that only conditionally calls float_to_decimal_common_exact. So #[inline(never)] serves as a means to not use the large stack space if fmt.options.precision is None.

In our case we call from_float uncoditionally so the stackspace will be used no matter what, which makes inlining not problematic.

Choose a reason for hiding this comment

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

Makes sense! Thanks for double checking!

@petrosagg petrosagg merged commit 30bd51d into master May 7, 2025
6 checks passed
@petrosagg petrosagg deleted the decimal branch May 7, 2025 14:46
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.

3 participants