Re: Decimall Float Question



JRS: In article <44366c02$0$20594$5a62ac22@per-qv1-newsreader-
01.iinet.net.au>, dated Fri, 7 Apr 2006 23:41:13 remote, seen in
news:comp.lang.javascript, RobG <rgqld@xxxxxxxxxxxx> posted :

The rounding function itself should not modify
the number other than to round the decimal part. For example, the typical
round to money function of:

var x = Math.round(x*100)/100;

if given 1.025 returns 1.02, not 1.03 which is typically required (assuming
'bankers rounding' to the nearest even number is not required). That's
what I mean by the rounding function introducing errors.

But you don't give it 1.025. You give it a variable of type Number
which has been loaded by something equivalent to +"1.025" ; and, since
that three-digit decimal part is not a multiple of an eighth, the value
cannot be stored exactly. The rounding is correct.

While the user of a Web page cannot be expected to understand binary
float capabilities in detail, and the FAQ reader ought to but probably
does not (yet?), the providers of such code do need to know exactly what
is happening arithmetically.


Where the input Number is obtained by a physical calculation, general
convention is that an exact half rounds away from zero and that anything
not exactly a half rounds to nearest. Uncertainties mean that for
numbers near a half, rounding either way gives an almost equally good
result.

But when the input Number is obtained by an administrative calculation,
an exact half should round as required by the application and a very-
close-to-half should round as if it were exactly half.

In a sufficiently large administrative calculation, accumulated rounding
error may mean that num+"" does not have the right digit to the right
of the chopping-point. It might help to round to more digits, then
round to fewer.


<FAQENTRY>
On the other hand, if one wants exact results one should be doing an
integer calculation anyway; cents, not dollars - or, as in the Delphi
(IEEE?) Currency type, centicents.
</FAQENTRY>


The function below doesn't, try it out and see. Let me know if it breaks.
I've fully commented it, remove all that and it's two lines longer than
the example in the FAQ.

However, the FAQ code includes having a variable number of digits after
the decimal point and a variable (but at least as many as are necessary)
number before it, and has code added to ensure a benign result for
numbers too large for the basic algorithm.


/* Round numbers to two decimal places
* Always rounds .xx5 upward.

Towards plus infinity or away from zero? They are not equivalent for
num<0. Comment needs to say whether num<0 is allowed; and it must be
said that a nominal 0.0 may actually be negative.

// Make a string 3 characters by adding zeros
// or truncating
function str3(x) {
while (x.length < 3) {x += '0';}
return x.substring(0,3);

or return (x+"000").substring(0, 3) ??


}
// Split number into integer and decimal bits

integer and fractional ?

var bits = (num+'').split('.');

Comment : // Convert number to string and split ...

// Get the decimal part

fractional ?

var frac = bits[1] || '';

// Make the number all digits with no decimal place
// as if had done num*1000 and truncated decimal places
// Split into an array of single digits
var digits = (bits[0] + str3(frac)).split('');

// Round the second last digit up if the last digit
// is 5 or greater
var i = digits.length;
if (digits[--i] > 4) { digits[--i] = +digits[i] + 1; }

// While the last number is 10, make it a zero and

// While the last digit ... ?

// carry 1 to left
while (i && digits[i] > 9){
digits[i] = 0;
digits[--i] = +digits[i] + 1;
}

// Make the digits a string again
digits = digits.join('');

// Put the decimal place back in and return a string
point

// Leave off the last digit
i = digits.length-3;
return digits.substring(0,i) + '.' + digits.substring(i, i+2);
}

</script>

However, roundTwo(+99.9999) gives 100.00 but roundTwo(-99.9999) gives me
NaN00.00 ; presumably because the first character is not a number.

IMHO, however, negative numbers should be done with Math.abs and finally
adding the sign information. That facilitates such results as (-3.33)
and -£3.33; and has the great benefit of reducing the amount of testing
needed.


Another approach, like that done for Bankers' Rounding in js-misc0.htm,
is to convert to String and look at the MSD of the part to be chopped.
If that's 0 to 4, chop. Otherwise, increment the original number by
what amounts to about 7 in that digit, and chop.

--
© John Stockton, Surrey, UK. ?@merlyn.demon.co.uk Turnpike v4.00 IE 4 ©
<URL:http://www.jibbering.com/faq/> JL/RC: FAQ of news:comp.lang.javascript
<URL:http://www.merlyn.demon.co.uk/js-index.htm> jscr maths, dates, sources.
<URL:http://www.merlyn.demon.co.uk/> TP/BP/Delphi/jscr/&c, FAQ items, links.
.



Relevant Pages

  • Re: XQ and ->Qpi bug on large X
    ... you shouldn't be rounding to only two digits ... I am trying to make a similar point here about rounding; ... and round it, ... prior to using the input values in calculations. ...
    (comp.sys.hp48)
  • RE: Rounding in VBA - Any ideas?
    ... MS chose not to display more than 15 digits because digits beyond the 15th ... Consider dblContainer*lngExpon which you round to produce ... VBA did what you told it to do, but that is different than what you wanted ... "banker's rounding" than the VBA Round function, ...
    (microsoft.public.excel.worksheet.functions)
  • Re: XQ and ->Qpi bug on large X
    ... did away with the IEEE directed rounding that the HP71 had ... What if the calculator were used for finance ... OTOH: VBScript's Round vs. FormatNumber and Format$: ... stored with 12 total digits is irrelevant. ...
    (comp.sys.hp48)
  • Re: Rounding errors
    ... digits then the average is _NOT_ 0.500. ... Rounding of the original set of long numbers, ... When you round the numbers to two digits what existed beyond the 3rd ... so the truncation doesn't matter. ...
    (comp.lang.cobol)
  • Re: Decimall Float Question
    ... The rounding function itself should not modify the number other than to round the decimal part. ... // Make a string 3 characters by adding zeros ... // Make the number all digits with no decimal place ...
    (comp.lang.javascript)