From bca1604c12262b66ce3b8004994fb4841fb8b87d Mon Sep 17 00:00:00 2001 From: Braden Shepherdson Date: Fri, 19 Oct 2012 14:29:37 -0400 Subject: [PATCH] fix(currency): Handle not-quite-zero values IEEE 754 floating point sometimes results in values that are very small, rather than zero. One example is 1.0 + 1.07 - 2.07, which returns 4.440892098500626e-16 instead of 0. This change tweaks the number formatting logic so that an exponential value with a negative exponent that is larger than the precision+1 returns 0 instead. For example: with precision 2, anything with an exponent of -4, -5 or more would become 0. 9e-3 = 0.009 = 0.01, but 9e-4 = 0.0009 = 0.001 = 0.00. This detail is unlikely to matter since this quirk is usually only triggered with values very close to zero. Closes #1469 --- src/ng/filter/filters.js | 13 +++++++++++-- test/ng/filter/filtersSpec.js | 7 +++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/ng/filter/filters.js b/src/ng/filter/filters.js index 376afd85b09b..57186981f075 100644 --- a/src/ng/filter/filters.js +++ b/src/ng/filter/filters.js @@ -117,9 +117,18 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) { formatedText = '', parts = []; + var hasExponent = false; if (numStr.indexOf('e') !== -1) { - formatedText = numStr; - } else { + var match = numStr.match(/([\d\.]+)e(-?)(\d+)/); + if (match && match[2] == '-' && match[3] > fractionSize + 1) { + numStr = '0'; + } else { + formatedText = numStr; + hasExponent = true; + } + } + + if (!hasExponent) { var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length; // determine fractionSize if it is not specified diff --git a/test/ng/filter/filtersSpec.js b/test/ng/filter/filtersSpec.js index 883e91f6579c..cbb4184129a2 100644 --- a/test/ng/filter/filtersSpec.js +++ b/test/ng/filter/filtersSpec.js @@ -91,6 +91,13 @@ describe('filters', function() { expect(currency()).toBe(''); expect(currency('abc')).toBe(''); }); + + it('should handle zero and nearly-zero values properly', function() { + // This expression is known to yield 4.440892098500626e-16 instead of 0.0. + expect(currency(1.07 + 1 - 2.07)).toBe('$0.00'); + expect(currency(0.008)).toBe('$0.01'); + expect(currency(0.003)).toBe('$0.00'); + }); });