Open uzuki-P opened 1 year ago
I think it was not intended, as the type of the format
method was intentionally kept to be dynamic
and not num
to also allow other numeric types such as BigInt
to be a valid input.
However, the logic inside the _formatFixed
method called by format
in your example relies on the argument supporting things like multiplication with a double
using the *
operator, which BigInt
does not do. So effectively, BigInt
is not supported for all cases.
A possible solution would be to refactor the code to accept any class supporting a tbd interface with all necessary methods. This would enable users to pass in their own preferred numeric type, provided it implements this interface. This interface could also be implemented by int
and double
or num
to avoid having to wrap those classes.
Unfortunately, such logic can become quite verbose, as many cases have to be considered.
It is possible to write a wrapper class that provides the required operations with the types used by the algorithm. (I know of one case where a BigInt is wrapped in a class that makes it look like the value, but scaled to 'micro-units', e.g. 1234567 represents 1.234567). This is a fairly heavy-weight solution since there can be many intermediate objects of this class in the formatting computation.
It is unlikely that an interface will be added to int
.
An easier to-use option is to make the formatting work with a string of digits.
One way this could happen is for the format
method to accept a string and optional scale.
This permits the formatting of 'numeric' data from any source:
final f1 = NumberFormat("###,###.00", "en_US");
print(f1.format('123456789')); // 123,456,789.00
print(f1.format('123456789', scale: -6)); // 123.46
final f2 = NumberFormat("###,###.00", "my");
print(f2.format('123456789', scale: -6)); // ၁၂၃.၄၆
The rounding arithmetic would have to happen on the digits.
As a convenience we could add an interface that some classes implement that return the digits and scale.
abstract interface class NumberFormatDigits {
(String, int) digitsAndScale(/*some parameters TBD*/);
}
If the input to format
is not a num
or String
, but implements this interface, the results are used as if the format
method is passed the digits and scale.
This interface would probably have to be parts of dart:core
so that classes like Int64
, BigInt
, BigDecimal
, WeirdTenDigitNumber
don't have a dependency on Intl.
digitsAndScale
may require some parameters to help generate digits. The there are an infinite number of digits in the decimal expansion of the rational number 2/3
, but only a few are required for format "#.00"
. The returned records ("666", -3)
and ("666666", -6)
would give the same formatted result (0.67
). The design of these parameters requires more work, but should be such that many cases can ignore them.
/cc @lrhn What do you think about dart:core
having some minimal support like this abstract interface?
AFAIK, treating any input as a (List<int> digits, int scale, bool sign)
is how ICU4X is solving the problem. Thus the upcoming package:intl4x
will hopefully be able to format any kind of number. This solution is also possible for the current package:intl
, but would require rewriting all formatting operations in terms of this new interface, which would be a large change.
The (bool negative, List<int> digits, int exponent)
representation is equivalent to toString
, so you could just use that. The only difference would be that you can omit trailing zeros, moving them into the exponent, which may be a significant number of digits for a BigInt
, and don't have to search backwards from the end looking for an e
, to see if there is an exponent or not.
But that's cheap compared to creating the string to begin with.
If you can ask for a specific number of significant digits, it becomes more interesting. A big part of double
's toString
is figuring out how many digits are needed to be unique.
For integers, it's probably not that big a deal, since you have to do all the divisions by 10 to get to the high digits anyway.
Any updates? We have to format numbers with large digits.
Any updates? We have to format numbers with large digits.
This is a planned functionality for package:intl4x
.
Describe the bug Formatting
BigInt
value returntype 'int' is not a subtype of type 'BigInt' of 'bigInt'
. Is it intended?To Reproduce Add a minimal working example or, if not possible or available, any code which might help to reproduce the problem
System info
System Info
``` Dart SDK 3.0.6 Flutter SDK 3.10.6 bigint 1.0.0+1 dependencies: - cupertino_icons 1.0.5 - flutter 0.0.0 [characters collection js material_color_utilities meta vector_math sky_engine] - intl 0.18.1 [clock meta path] dev dependencies: - flutter_lints 2.0.2 [lints] - flutter_test 0.0.0 [flutter test_api path fake_async clock stack_trace vector_math async boolean_selector characters collection js matcher material_color_utilities meta source_span stream_channel string_scanner term_glyph] transitive dependencies: - async 2.11.0 [collection meta] - boolean_selector 2.1.1 [source_span string_scanner] - characters 1.3.0 - clock 1.1.1 - collection 1.17.1 - fake_async 1.3.1 [clock collection] - js 0.6.7 [meta] - lints 2.1.1 - matcher 0.12.15 [async meta stack_trace term_glyph test_api] - material_color_utilities 0.2.0 - meta 1.9.1 - path 1.8.3 - sky_engine 0.0.99 - source_span 1.9.1 [collection path term_glyph] - stack_trace 1.11.0 [path] - stream_channel 2.1.1 [async] - string_scanner 1.2.0 [source_span] - term_glyph 1.2.1 - test_api 0.5.1 [async boolean_selector collection meta source_span stack_trace stream_channel string_scanner term_glyph matcher] - vector_math 2.1.4 ```