Skip to content

Commit 189cd06

Browse files
committed
fix(numberFilter): correctly round fractions despite floating-point arithmetics issues in JS
Closes angular#7870 Closes angular#7878
1 parent ceaea86 commit 189cd06

File tree

2 files changed

+11
-2
lines changed

2 files changed

+11
-2
lines changed

src/ng/filter/filters.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
131131
var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
132132
if (match && match[2] == '-' && match[3] > fractionSize + 1) {
133133
numStr = '0';
134+
number = 0;
134135
} else {
135136
formatedText = numStr;
136137
hasExponent = true;
@@ -145,8 +146,11 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
145146
fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac);
146147
}
147148

148-
var pow = Math.pow(10, fractionSize + 1);
149-
number = Math.floor(number * pow + 5) / pow;
149+
// safely round numbers in JS without hitting imprecisions of floating-point arithmetics
150+
// inspired by:
151+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
152+
number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize);
153+
150154
var fraction = ('' + number).split(DECIMAL_SEP);
151155
var whole = fraction[0];
152156
fraction = fraction[1] || '';

test/ng/filter/filtersSpec.js

+5
Original file line numberDiff line numberDiff line change
@@ -147,13 +147,18 @@ describe('filters', function() {
147147
expect(number(.99, 2)).toEqual("0.99");
148148
expect(number(.999, 3)).toEqual("0.999");
149149
expect(number(.9999, 3)).toEqual("1.000");
150+
expect(number(1.9, 2)).toEqual("1.90");
151+
expect(number(1.99, 2)).toEqual("1.99");
152+
expect(number(1.999, 3)).toEqual("1.999");
153+
expect(number(1.9999, 3)).toEqual("2.000");
150154
expect(number(1234.567, 0)).toEqual("1,235");
151155
expect(number(1234.567, 1)).toEqual("1,234.6");
152156
expect(number(1234.567, 2)).toEqual("1,234.57");
153157
expect(number(1.255, 0)).toEqual("1");
154158
expect(number(1.255, 1)).toEqual("1.3");
155159
expect(number(1.255, 2)).toEqual("1.26");
156160
expect(number(1.255, 3)).toEqual("1.255");
161+
expect(number(0, 8)).toEqual("0.00000000");
157162
});
158163

159164
it('should filter exponentially large numbers', function() {

0 commit comments

Comments
 (0)