logo To Foot
© J R Stockton, ≥ 2012-11-20

JavaScript Rounding 1.

No-Frame * Framed Index * Frame This
Links within this site :-

See "About This JavaScript Site" in JavaScript Index and Introduction.

Rounding a Number to a Number

Rounding to an Integer

The standard methods of Math are not always adequate.

To integer, towards zero :-

Alternatively, with ((0 < X) - (X < 0)) for the sign.


To integer, towards zero, for |X| < 231 :-

General Rounding

These methods are not substantially dependent on what the rounded number is to be a multiple of.

Signed, to a multiple of Q, for any Q != 0 :-

Signed, to a multiple of 1/R, for any R != 0 :-

The second of the above methods seems less susceptible to internal rounding error, in the common case where R = 1/Q is integer. Try rounding 3.315 to hundredths.


Signed, to 2 decimal places :-

Signed, to N decimal places (N of either sign) :-

Formatting a Number to a Decimal String

Normal convention, outside JavaScript, is to present a string using a fixed number of decimal places, with trailing zeroes shown. For tabulation, a fixed number of characters before the decimal point is usually needed. Thousands separators, for which see in and near JavaScript Maths, may be called for.

Generally, a number held in a string should either have no decimal point or have at least one digit on each side of its decimal point (see, for example, IUPAP SUNAMCO red book (1987).

The Status Quo

The Default Conversion

The simple automatic JavaScript conversion, by using a number in a string context, as here, often does not give the format needed.

The Needs

Options that may be provided include whether :-

Sign Functions

To return a sign character; alternatives may be preferred :-
 function Sign(X) { return (X<0 ? '-' : '') }

A definite indication of positive sign, with a fixed length, may be needed :-

Function Sygn always gives a sign, and discriminates between +0 and -0.

The Native Methods

JavaScript ought to provide reliable native Number-to-String routines with the power of those of more mature languages, including fixed-length output.

All browsers have Number.toString(). All modern browsers have Number.toFixed(), Number.toExponential() and Number.toPrecision().

toString

On its own, Number.toString() is not sufficient in this context, since the format is variable; it is the same as for the "automatic" conversions such as in new String(number).

toFixed

Native Number.toFixed(N) is not wholly reliable. It gives errors in Microsoft JScript and Windows Script Host. I have seen none in FireFox, Safari, or Chrome.

As specified, X.toFixed() and X.toFixed(0) round half-integers away from zero ; Math.round(X) towards +∞. IE 8, Firefox 3.0.12, Safari 4.0, Chrome 2.0 comply; Opera 9.64 does Bankers' Rounding for X.toFixed(0), but Opera 10.0 is correct.

In JScript (at least including IE 8 with JScript 5.8.18702), X.toFixed(A) wrongly rounds towards zero when |X|×10A is in the range [0.50, 0.95). For example, (-0.7).toFixed(0) gives 0 instead of -1 and (0.007).toFixed(2) gives 0.00 instead of 0.01. Preview IE9 on Vista is apparently correct.

To determine where the value changes : go to Find Zero, enter an expression such as +X.toFixed(0) ± 0.5 and limits of, say, -1 and +1, and press Find.

If toFixedexists, compare results for MSIE with those for other browsers

MS IE 8, at least, does Bankers' Rounding.

A Replacement

A method toFixed can be added if the system does not already have it, or can replace the original.

A toFixed() of my own, based on other general functions, results possibly differing from those for ECMA-262 and/or in correct browsers, can be loaded by file inc-cmmn.js. The currently-loaded routine is tested here and below. If the first box contains a reference to StrS then toFixed is the substitute; if it contains [native] or similar then it is the browser's.

Note that a leading or trailing decimal point is deprecated in technical and scientific circles; but StrS gives what it is asked to give.

Another Replacement

Another (seemingly OK; much as posted by DA in news:m.p.s.j 20031106; described as "follows ECMA-262, step-by-step") is specifically an implementation of toFixed without the errors.

toExponential, toPrecision

There is now Number.toExponential() and Number.toPrecision() - the latter uses either the former or Number.toFixed, as necessary. If the browser knows them, tests follow.

   # = 

 X =   N =   

    X.toFixed(N)
 My      StrU :  

    X.toExponential(N)
 My SigFigExp :  

    X.toPrecision(N)
 My SigFigFxd :  

 
Results are compared numerically; a difference of 1 in the last place may be ignored.
Firefox 3.0.12 allows N=100, contrary to specification.

Using the Native Converter, Indirectly

Some methods have an upper limit where the native JavaScript number-to-string switches to e-format.

Methods need to be tested to ensure correct rounding into the final place, and to ensure that numbers requiring a first digit of zero are correctly handled.

"Defective Conversions to String", "Satisfactory Conversions to String", "Another Conversion to String", "Other Good? Conversions to String" are in Rounding 2.

Good Conversions to String

For a version to handle the results of approximate calculation of nominally-exact values, such as 1.345 to be rounded to two decimal places, see also Rounding of Approximate Quantities.

The sign function used should be chosen in accord with circumstances.

StrC etc.

These seem to be good functions, all returning strings. The input X is expected, but not obliged, to be of type Number. Providing a function, an object, or an array of length not 1 is not recommended.

Sign(X) : return "+" or " " or "-" ; constant width 1 character
PrfxTo(S, L, C) : prefix copies of C to a copy of S while it is shorter than L
SpcsTo(S, L) : prefix spaces to a copy of S while it is shorter than L
ChrsTo(S, L, C) : prefix copies of character C to a copy of S while it is shorter than L
StrU(X, M, N) : convert non-negative number X to a string of M digits Point N digits
StrS(X, M, N) : prefix Sign(X) to StrU(Abs(X), M, N)
StrS(X, M, N) : as StrU, but signed, prefixing Sign(X)
StrT(X, M, N) : pad StrU(X, 1, N) on left with spaces to length M+N+1
StrW(X, M, N) : pad StrS(X, 1, N) on left with spaces to length M+N+2
* the results exceed M leading digits if necessary
* M, N must not be negative
* M, N should be positive
* M, N zero may/will give deprecated format
* the effect of omitting ,M,N is unspecified
* if the number X is too big for the method, e-format is returned
* preferences for function Sign() may vary

StrU and StrS were re-implemented here on 2009-01-12, and since adjusted, obtaining the core StrC by modifying StrU, in order to improve the behaviour of StrS with non-numeric inputs.

For StrS StrW, if X is slightly negative then the returned string woll be -0.00 or similar. To avoid that, if the value initially assigned to St is "0" then the sign appended should be that corresponding to true zero. One can use Sign(X*St) instead, or insert if (!+St) X = 0.

If the number of digits needed is so large that the initial St is in e-format, but X itself is not that large, the result will be a [signed] digit string with the right numerical value and no fractional part. One might replace ChrsTo(X, with ChrsTo(String(X).replace(/^[ +-](\d+)$/, "$1.00"),; but that would rarely be worthwhile.

Note that the final paragraph tests StrU with the first argument missing, or a simple Object, or an Array, or a Date Object, or a Function.

There are more rounding functions, STRU STRS STRT STRW, with test harness, in Rounding 3. They use a more flexible method.

Converting Ab Initio to String

For these, the intended range of M & N is from 0 upwards, though actual use of 0 for either is generally deprecated (M=N=0 gives a signed decimal point). Both M & N are otherwise unlimited, but M+N>16 is usually silly, as numbers are at best good to 15-16 significant figures.

To sign, integer part, point, N decimal places, where Math.floor(y) does not give e-format (|y|<1021) :-

N.B. with N=2, "1.5555" gives "+1.56", "0.5555" gives "+0.56"; "0.0555" gives "+0.06", "0.0055" gives "+0.01", "0.0033" gives "+0.00", "0" gives " 0.00". These are correct.


To sign, M digits, or more if the value requires it (with leading zeroes; if unwanted, put M=1; if always unwanted, remove " M," and "j<M||"), decimal point, N decimal places :-

N.B. with M=N=2, "1.5555" gives "+01.56", "0.5555" gives "+00.56"; "0.0555" gives "+00.06", "0.0055" gives "+00.01", "0.0033" gives "+00.00", "0" gives " 00.00". These are correct.

Rounding to N Significant Figures

See also toExponential above.

I would like to add a function that returns a string of chosen size.

New code is in Rounding 3, and this section may eventually be removed.

These are the functions now used across this site.

To a Number

Round to N significant figures (returns a number) :-

To a String

For N significant figures, exponential format (returns a string) :-

Extending Right to N Decimals

Extend a number or a string to >= N decimals (cannot test a string on this page) :-


JavaScript Rounding   0, 2, 3.
Home Page
Mail: no HTML
© Dr J R Stockton, near London, UK.
All Rights Reserved.
These pages are tested mainly with Firefox and W3's Tidy.
This site, http://www.merlyn.demon.co.uk/, is maintained by me.
Head.