globalizejs / globalize

A JavaScript library for internationalization and localization that leverages the official Unicode CLDR JSON data
https://globalizejs.com
MIT License
4.8k stars 605 forks source link

An unexpected rounding result of a percentage formatted value (floating-point arithmetic issue)    #856

Open dimarudnev opened 5 years ago

dimarudnev commented 5 years ago

To reproduce the issue, call:   Globalize('en').formatNumber(0.145, {style: 'percent', minimumFractionDigits: 0, maximumFractionDigits: 0})    Expected result: “15%”   Actual result: “14%”   The issue can be reproduced in Chrome, IE11, Edge, Mozilla Firefox.      We investigated the issue and found that the reason for unexpected rounding is multiplication by 100 in this line: https://github.com/globalizejs/globalize/blob/b08574ae714f899e50ff6a4852d9b9b8b0bc2ba0/src/number/format.js#L66. The issue is related to floating-point arithmetics. If you evaluate Math.round(0.145 100) in the browser console, you will get 14, because 0.145 100 returns 14.499999999999998.   We found that converting the number to string with the 'toFixed' method and then converting back to the number fixes the issue:   n=+((n*100).toFixed(maximumFractionDigits + 1));       A similar issue was discussed in https://github.com/globalizejs/globalize/pull/386.      Note: the Inlt localization works more predictably in this case:   Number(a).toLocaleString(undefined, { style: 'percent', minimumFractionalDigits: 0,maximumFractionDigits: 0 }) return “15%”