© J R Stockton, ≥ 2012-07-01

Links within this site :-

**Merlyn Home Page**- Site Index, E-Mail, Copying**JavaScript**:-- Index and Introduction - with About This Site, Code Re-use, Links
**This page**:-- Rounding 1 :-
- Rounding 2 :-
- Rounding 3 :-
- Include Files
- Maths
- Date and Time
- Tests
- General
- Alarm

- Pascal/Delphi Rounding and Truncation
- Pascal Maths
- VBScript General and Maths

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

See also page Pascal/Delphi Rounding and Truncation, for further general discussion of rounding; also Wikipedia and Rounding Algorithms 101 - Maxfield and Brown.

Generally,
`Round(X)` rounds to the nearest integer,
`Floor(X) / Trunc(X)` rounds down, and
`Ceil(X)` rounds up.
The cases of `X` being negative, half-way between integers, or
both, always need careful consideration; different languages, and maybe
different implementations of languages, can do it differently.

To round a Number to a Fraction, commonly to a power of 0.1, multiply by the inverse of the power, round to integer, and divide by the power. It is better to use factors which are represented exactly : integers, rather than their reciprocals.

To get a given number of decimal places, the result must be a String, so that trailing zeroes can be indicated.

Rounding a Number to a String with a given number of decimal places, or in other formats, is often required. Many languages provide appropriate routines; JavaScript default is more limited, but code can be provided.

Bankers' Rounding requires that the exact half-way case be rounded to an even least digit.

In statistical rounding, a fractional part of value X is rounded up a fraction X of the time, and otherwise down.

JavaScript stores the value of a Number as an IEEE Double, in binary floating-point. Currently it has no other formats. There are two zero values, +0 and -0; the sign usually has no effect, but it is detectable.

Integers smaller than about ±9E15 are held exactly. So are positive/negative-power-of-two multiples of such integers, within range limit about ±1.7E308. So are sums of such multiples, provided that the span of powers-of-two does not exceed about 53. See in JavaScript Maths.

Most values, including most of those with one, two, or three decimal places, are not stored exactly.

Bit Representations of Number shows conversion to/from binary and the exact values of Numbers.

It is essential that the intrinsic properties of the Number type be understood.

JavaScript storage of and arithmetic on non-integers is necessarily inexact (almost always); see in JavaScript Maths and Pascal Floating-Point. For example, displaying 0.05+0.01 gives 0.060000000000000005 and 0.06+0.01 gives 0.06999999999999999. Such numbers should be rounded to a suitable format for presentation.

Most real numbers, in particular those with finite base-10
representations, cannot be held exactly in a Double. This is why, for
instance,
`Math.round(1.035*100)` gives `103`, but
`Math.round(2.035*100)` gives `204` and
`Math.round(1.045*100)` gives `105`; moreover,
`RoundToNdp(1.0035, 3)` gives `1.004`, but
`RoundToNdp(1.035, 2)` gives `1.03`.

One can write 1.3550, or "1.3550", in code, or read the string "1.3550" from a control, and then store it in a variable V as type Number, and then convert it to a String "1.355"; but that does not mean that V actually has a value exactly equal to 1.355 (which cannot be represented exactly). Rounding to two decimal places by arithmetic will, quite correctly, be controlled by the sign of the difference from 1.355. Alternatively, one might convert the value of V to a String, which act itself includes some rounding; and then round that to two places by operations on the individual characters.

If doing arithmetic other than addition, subtraction, and multiplication by an integer, one should consider what sort of intermediate rounding is indeed proper for the field; rounding to pence internally is not necessarily legitimate.

When a calculated number is to be converted to a string with, say,
two decimal places, it *must* be rounded arithmetically; it cannot
just be extended or truncated if nominally a multiple of 0.1 or 1.0;
this is because of imperfect accuracy in calculation.

The JavaScript primitives taking a general Number
`X` and returning an adjacent integer value are :-

`Math.ceil(X)`- rounds towards plus infinity`Math.floor(X)`- rounds towards minus infinity`Math.round(X)`- rounds towards nearest, with halfway being rounded towards plus infinity

All can give `+0 -0`.

`Math.ceil(-X) = -Math.floor(X)`

All systems have a method returning String :-

`Number.toString(R)`- Radix 2 to 36, default 10

Later systems have more methods returning String, for which see in Rounding 1 :-

`Number.toFixed(N)``Number.toExponential(N)``Number.toPrecision(N)`

Bankers' Rounding, for half-way going to the nearest even number, is not provided.

ISO/IEC 16262 15.8.2.15 specifies that `Math.round` of a
half-integer must choose the value closer to plus infinity (a dubious
expression, since all finite values are infinitely far from plus
infinity; it should be "rounds towards ...").

A Number that displays like `234.5p` is held exactly. It is
half-way between two integers and will `Math.round` towards plus
infinity (or away from zero in a routine that separates the sign).
Bankers' Rounding is meaningful, but requires additional code.

A Number that displays like `£2.345` is only held
approximately. It is therefore not half-way between pence and should
`Math.round` to the nearest penny. Bankers' Rounding to pence is only
meaningful for the odd eighths of a pound - an odd number of
half-crowns, in fact. Therefore, Bankers' Rounding of a pounds Number
to the nearest penny is not meaningful, except in 4% of cases. See also
#.##5 to #.## - up or down?.

To get exact results, make the smaller unit an integer - use pence rather than pounds. Half-pence are held exactly.

Rounding a Number to a Number
which is a multiple of 10^{-N}, and
Formatting a Number to a Decimal String
with exactly N decimal places (implying possible trailing
zeroes), are two rather different things. In the latter case, there may
also be a need for Extending to
(at least) a fixed number of digits/spaces before the decimal point,
for visual alignment. In technical work, it may be better to use
Rounding to N Significant Figures
for output.

One should always consider when to round up and when to round down.
The default rounding in MSIE 4 JavaScript was different from that in
Delphi 3; therefore, if there is a relevant standard, *at least
one* of them did not comply with it.

In particular, when dividing odd numbers by two, or doing anything equivalent, one should determine what sort of rounding to integer is correct; see Bankers' Rounding.

Specific rounding was legally required in converting between the old Euro-land national currencies and the Euro.

Frequently, a currency calculation is thought of as in major units, but is expected to be accurate in minor units. In this case, it may well be better to perform the calculation in minor units, converting only when necessary. There's an output routine at Cent Number To Euro String.

JavaScript is exact for calculations using only integers not bigger than 9007199254740992.

Working with integers avoids many problems.

See also Currency Rounding below.

A truly general-purpose routine should be capable of handling all possible values of its main argument - including undefined, null, ±0, ±Infinity, NaN, and very large - and should give a reasonable result in every case. It must NEVER give a plausible but incorrect answer.

Code here has not considered `Number.MAX_VALUE
Number.MIN_VALUE`.

Because of floating-point rounding errors, any code used to round all non-negative numbers should allow for slightly negative numbers practically equivalent to zero.

For reliable results in the desired format, it is generally necessary
that the output, ignoring the decimal point and sign, should be an
integer no greater than 2^{53} = 9007199254740992.
Routines differ in their treatment of large numbers.

If it is actually necessary to get a moderately large number of
decimal places, add them in the manner of `ChrsTo`; for more, see
Making a Long String.

Note that a number of the format #.##5, except for #.125, #.375, #.625, #.875, cannot be represented exactly as an IEEE Double, which is what JavaScript uses for numbers. It is therefore often considered acceptable, when converting to two decimal places, for other numbers of the format #.##5 to be rounded either up or down; and similarly for any other "half-way" case of rounding to a decimal.

If this matters, for example when working with £.s.d. including
halfpence or farthings, then do the arithmetic with smaller units;
integer arithmetic is exact up to 2^{53}.

My function `StrS` rounds the "odd eighths" away from zero;
"Bankers' Rounding" would make the final digit even. In the tests,
the "Bankers'" line uses inputs represented exactly in an IEEE Double.
See also Bankers' Rounding.

When rounding (or truncating) a number which may be either positive or negative, it is sometimes necessary to round either towards plus infinity or towards minus infinity. But those are special cases.

Normally, however, rounding should be symmetrical about zero; rounding X should give the same digits as rounding -X, for all X.

Some of the routines quoted on these pages for signed numbers are unsymmetrical.

One may put `ceil / floor` instead of `round` in the
code of the following pages. But those can, in the presence of the
inevitable rounding errors of non-integer arithmetic, lead to results
other than those wanted. Some care is needed; see in Rounding 3.

Some algorithms for combining conversion to a formatted string with
choice of decimal separator seem error-prone. It may be better to
convert the separator afterwards, with for example `.replace(/\./,
',')`.

Input conversion may then also be needed :-
`parseFloat(Value.replace(/,/, '.')) &
+Value.replace(/,/, '.')` will read both '0.03' and '0,03'
as 3/100. But beware of incoming "thousands" separators.

For adding thousands separators, see in JavaScript Maths.

In my coding, I assume the UK decimal point and no thousands separators.

The testing code shown here, from an Include file, is used in other pages.

Rounding to a string must be carefully tested. In extreme cases, an undesired layout might be acceptable; but an numerically-incorrect value can never be.

Many routines fail to handle one or more of `0.007, 0.07, NaN,
+Infinity, -Infinity, null, undefined` well.

For general rounding to two decimal places, tests equivalent to *at
least* the following and their negatives are needed.

The cases 3.965, 3.995 may round differently when negative; #.995 specifically tests for one possible problem.

The test code preserves `null` and `undefined`.

Other test numbers are generated algorithmically
in `TryRnd`.

The "=" buttons test the current function, using the arguments to its left.

The "Cases" buttons pop-up the test case array,
`RndCases`.

The "cf.toF" buttons show, on a fresh page or tab, a full-range
comparison with `toFixed(2)`. Note that `toFixed`
gives errors in MS IE 8 and earlier.

The conversion functions on the following pages take input from their
arguments and use `return` for the result. Arguments are expected
to all be present, though in some cases they can be omitted (and are
likely to default to zero). "Size" arguments are expected to be
non-negative - after all, they are usually given directly as literals.
Those wanting different behaviour should add the requisite code.

The functions have not all been fully tested with illegal inputs; that will be reserved for those which seem among the best for legal ones. In actual use, it should be natural or easy to ensure that the arguments are numbers or strings representing numbers. Be careful with strings and String Objects; strings beginning with zero may be taken as representing octal numbers. If needful, write a wrapper to normalise input.

**N.B.** Generally useful functions are now
in inc-cmmn.js. There is, in code and test, by
intent, no additional protection against parameter error or absence
(absent parameters are converted to 0 by the test process). Background
colours are, more or less, significant.

Rounding functions here take one to three arguments, `X M N`.
The first, `X`, is the quantity to be rounded, `M` is the
number of characters before the decimal point, and `N` is the
number of digits after the decimal point. Sometimes the second
argument is different.

It has been reported that an error in the browser Konqueror causes incorrect results.

The following is imported (from `inc-cmmn.js`;
see Include Files)
and used in the following pages :-

There may be others not shown on these pages; RSVP.

Provide in the green TextArea a JavaScript function with up to three parameters; provide parameters in the small boxes; press "=" to get the result.

To enlarge the TextArea, press "=" after setting
its first line to

`function X() { return ++document.forms.FrmD.Text.rows }`

Provide in the green TextArea a body for the JavaScript function
`Thingy`; provide parameters in the small boxes; press "=" to get
the results, in the Form and in `DivE`.

PreE

To set the TextArea to ` N` rows,
set its first line to

and press "=".

For precise work, with simple arithmetic, the smallest applicable units should be used (Euros or Cents?) so that addition, subtraction, and multiplication within range are exact.

If the "ideal" value is, say, 1.03, but there may be accumulated
rounding errors smaller than 0.005, one can (as in
`StrU`)
multiply by 100, use `Math.round`, and insert a point to get
"1.03" rather than perhaps "1.02999999977".

But a Number of value nominally such as 1.035, which cannot be held exactly (see Precision), may need to be rounded to a String with two decimal places as if the Number had been held exactly.

One can multiply by 10^{N+K}, round to the nearest integer,
convert to string, and adjust the string. That involves reasonable
assumptions, controlled by K, about the maximum rounding error existing
in the input.

Rounding, Bankers' Rounding, and Truncation can all be handled by a single routine with the operation selected by an argument.

Function `ApRnd2(X, M, N)`
should match `StrU`, rounding the
intended value of `X` and giving `M` digits before the
decimal point and `N` digits after it. With it, routines
corresponding to `StrS StrT StrW` can be produced similarly.

One can use the default conversion of Number to String, and proceed by (tedious) string manipulation.

This may be right; needs checking & tidying; not recommended for use. Bankers' is probably exact, in terms of string S; X can be String.

Function `StRnd2(X, M, N)`
should match `StrU`, rounding
`String(X)` and giving `M` digits before the
decimal point and `N` digits after it. With it, routines
corresponding to `StrS StrT StrW` can be produced similarly.

Converts approximate pence to pounds and pence.

The following method, returning a Number, has been suggested by
Michael Adams of NZ as a simple way to strip the excess
from floating point numbers. Note however that, for most values,
`parseFloat()` does not give an exact representation (see Exact Arithmetic), but the result of this
function will generally be treated with `toString` for display.
The automated test below is not wholly suitable for this function.

The default string representations of its results are somewhat
similar to the results of my `[Str]SigFigFxd`, but the
fractional parts have no trailing zeroes.