Fraction-Significant Rounding: Add a few more options
Description
I'm still trying to puzzle through all of the possible combinations of fraction digits and significant digits that affect rounding. The FractionPrecision class handles some but not all of the cases.
Here are more possibilities for rounding strategies that we could add somehow:
Strategy | In ICU? | 3.1 | 3.01 | 0.03333 | 32.1 | 65432 |
---|---|---|---|---|---|---|
integer() | Y | 3 | 3 | 0 | 32 | 65432 |
integer().withMinDigits(2) | Y | 3.1 | 3 | 0.033 | 32 | 65432 |
? | N | 3.1 | 3.0 | 0.033 | 32 | 65432 |
integer().withMinMaxDigits(2, 3) | N | 3.1 | 3 | 0.033 | 32 | 65400 |
? | N | 3.1 | 3.0 | 0.033 | 32 | 65400 |
maxSignificantDigits(3) | Y | 3.1 | 3.01 | 0.0333 | 32.1 | 65400 |
maxSignificantDigits(3).withMaxFraction(1) | N | 3.1 | 3 | 0 | 32.1 | 65400 |
minMaxSignificantDigits(2, 3).withMaxFraction(1) | N | 3.1 | 3.0 | 0.0 | 32.1 | 65400 |
? | N | 3.1 | 3 | 0 | 32 | 65400 |
? | N | 3.1 | 3.0 | 0.0 | 32 | 65400 |
This came up with a Google team who appears to be interested in something that does not show as many digits in the big number (65432) but has expected behavior for small numbers.
Activity
See the PR for the fix.
Another way of looking at it is that Precision basically implements the following function.
Input: magnitude of most significant digit, # of significant digits
Output: rounding magnitude, display magnitude always, display magnitude if rounded
A very early version of my API had a lambda function. Maybe we could just re-introduce the lambda function again with this signature.
So there are really two concepts at play here: the rounding magnitude and the display magnitude.
The three versions of withMinDigits all affect the rounding magnitude in the same way, and they are just three different ways of affecting the display magnitude.
The current version of withMaxDigits only affects the rounding magnitude. Maybe another version that also overrides display magnitude would be useful?
Or maybe make the trailing zeros a separate setting, either on the top level or on the Precision object?
One more thought on withMinDigitsZeros(). A user might want to customize whether to show zeros only if digits existed but were "rounded off". For example, display 0.033 as 0.0 but 0 as just 0. This could go as two API methods, named something like:
withMinDigitsZerosAlways()
withMinDigitsZerosIfRounded()
These two would be instead of withMinDigitsZeros(). The existing method withMinDigits() would have the current behavior of not adding any trailing zeros.
Here are APIs that could work maybe.
Strategy | 3.1 | 3.01 | 0.03333 | 32.1 | 65432 |
---|---|---|---|---|---|
integer() | 3 | 3 | 0 | 32 | 65432 |
integer().withMinDigits(2) | 3.1 | 3 | 0.033 | 32 | 65432 |
integer().withMinDigitsZeros(2) | 3.1 | 3.0 | 0.033 | 32 | 65432 |
integer().withMinDigits(2).withMaxDigits(3) | 3.1 | 3 | 0.033 | 32 | 65400 |
integer().withMinDigitsZeros(2).withMaxDigits(3) | 3.1 | 3.0 | 0.033 | 32 | 65400 |
maxSignificantDigits(3) | 3.1 | 3.01 | 0.0333 | 32.1 | 65400 |
maxSignificantDigits(3).withMaxFraction(1) | 3.1 | 3 | 0 | 32.1 | 65400 |
maxSignificantDigits(3).withMinDigitsZeros(2).withMaxFraction(1) | 3.1 | 3.0 | 0.0 | 32.1 | 65400 |
integer().withMinDigits(2).withMaxDigits(3).withMaxFraction(1) | 3.1 | 3 | 0 | 32 | 65400 |
integer().withMinDigitsZeros(2).withMaxDigits(3).withMaxFraction(1) | 3.1 | 3.0 | 0.0 | 32 | 65400 |
Basically, start at the left, then apply minima or maxima as you walk down the chain.
Only two API methods need to be added:
withMinDigitsZeros() – same as withMinDigits() but it adds trailing zeros.
withMaxFraction() – enforces a maximum number of digits after the decimal separator after other operations have been applied.