dart-lang / sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
https://dart.dev
BSD 3-Clause "New" or "Revised" License
10.2k stars 1.57k forks source link

truncateAsFixed() idea #56039

Open shmink opened 4 months ago

shmink commented 4 months ago

Hello, I ran into an issue today at work (using flutter at work) where I was receiving a double from the backend that was 116.41666666. I wanted to display this value as an amount of money, such as £116.41 and I didn't expect any rounding to occur.

Unfortunately, I found out that toStringAsFixed() does appear to round as I was getting £116.42 on the display. I searched but I didn't see any kind of way to effectively truncate a double to a fixed amount.

In the end, I created a function to do it for me. I don't think it's great but maybe a jumping-off point for a feature that I think would be useful to have in the SDK.

https://dartpad.dev/?id=e8ab76b086cbd79b212491b38bf58a7f


Only now of writing this do I see on the docs the example line toStringAsFixed()

(4321.12345678).toStringAsFixed(5);  // 4321.12346

where it shows rounding but my personal opinion is that it's not obvious enough. Perhaps instead

(1.118).toStringAsFixed(2);  // 1.12

maybe it's the 1, 2, 3, ... it doesn't stand out.

Either way, kind regards, Tom.

dart-github-bot commented 4 months ago

Labels: area-core-library, type-enhancement

Summary: The user proposes a new function truncateAsFixed() to truncate a double to a fixed number of decimal places without rounding, as toStringAsFixed() currently rounds the value. The user believes the rounding behavior of toStringAsFixed() is not sufficiently clear in the documentation.

lrhn commented 3 months ago

I'm not sure that functionality is available in JavaScript, and it's something we'd have to fix manually. It's also unclear what truncation should do, fx for the double value written as 10.43. That is, what string is 10.43.truncateAsFixed(2). It looks like it should give "10.43", obviously, but the actual value for that double is slightly less than the rational number 10.43 (it's 10.42999999999999971578290569595992565155029296875 to be precise). What is printed by 10.43.toString() is itself rounded. So realistically, you'd probably see 10.43.truncateAsFixed(2) being "10.42". Quite surprising and probably not what you want. So you do want rounding. You just want "the right rounding", which is actually quite hard to define.

The only way to win is not to play. Use integers for computations, then format them when you're done.

(Generally, it's just not recommended to use floating point numbers for money. Truncating may do what you want here, if defined in some way, or it may not, but since doubles can't correctly represent all multiples of 1/100, they're not necessarily well suited for anything where the precise value is important, and where rounding wrong can cost someone money. There are definitely places where using floating point numbers for money transactions is downright illegal.)