Closed Thread Icon

Topic awaiting preservation: Math.random truncation (Page 1 of 1) Pages that link to <a href="https://ozoneasylum.com/backlink?for=27003" title="Pages that link to Topic awaiting preservation: Math.random truncation (Page 1 of 1)" rel="nofollow" >Topic awaiting preservation: Math.random truncation <span class="small">(Page 1 of 1)</span>\

 
Sevenspade
Obsessive-Compulsive (I) Inmate

From:
Insane since: Oct 2005

posted posted 11-12-2005 16:54

I came across this while writing a script for the SpiderMonkey shell, but I've adapted it into a small hypertext example. I've tested this on Gecko/SpiderMonkey, and the KHTML and Presto javascript engines.

code:
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML Strict 1.0//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">

<head>
<title>testing randomness</title>

<script type="text/javascript">
//<![CDATA[
function print(x) {
  document.getElementById('output').appendChild(document.createTextNode(x));
  document.getElementById('output').appendChild(document.createElement('br'));
}

/************************************************/
function makewhole(x) {
  return x * Math.pow(10,(x.toString().length - 2));
}

var rand = Math.random();

for (i=1; makewhole(rand) == Math.floor(makewhole(rand)); i++) {
  rand = Math.random();
}
/************************************************/
//]]>
</script>
</head>

<body>
<div id="output"></div>

<script type="text/javascript">
//<![CDATA[
print('Test ' + i + ':');
print(rand);
print(makewhole(rand));
//]]>
</script>

</body>
</html>



Notice how directly outputting Math.random() occasionally results in a decimal number a few digits shorter than the one used to feed makewhole(). Why causes this and what is the proper way to fix this rather than using case-specific workarounds (such as Math.floor() to get a random whole number)?

(Edited by Sevenspade on 11-12-2005 16:56)

(Edited by Sevenspade on 11-12-2005 16:58)

(Edited by Sevenspade on 11-12-2005 17:06)

liorean
Bipolar (III) Inmate

From: Umeå, Sweden
Insane since: Sep 2004

posted posted 11-12-2005 21:47

The problem is inherent to floating numbers and the limited precision of fixed size numbers.

I would try to explain this to you, but I happen to know there are already plenty of good descriptions of the problem. I'll just link a series of entries on Eric Lippert's blog Fabulous Adventures In Coding:
- Why does JScript have rounding errors?

- Floating Point Arithmetic, Part One
- Benford's Law
- Floating Point And Benford's Law, Part Two
- Fun With Floating Point Arithmetic, Part Three
- Fun With Floating Point Arithmetic, Part Four
- Fun With Floating Point Arithmetic, Part Five
- Fun With Floating Point Arithmetic, Part Six

--
var Liorean = {
abode: "http://web-graphics.com/",
profile: "http://codingforums.com/member.php?u=5798"};

(Edited by liorean on 11-12-2005 21:47)

Sevenspade
Obsessive-Compulsive (I) Inmate

From:
Insane since: Oct 2005

posted posted 11-13-2005 02:04

Thanks.

quote:
The ECMAScript specification mandates that JScript display as much precision as possible when displaying floating point numbers as strings.


I find this odd, considering the relatively high level language that JavaScript is. Though I guess this is flawed reasoning, as an ECMAScript variant could certainly be created in assembly.

liorean
Bipolar (III) Inmate

From: Umeå, Sweden
Insane since: Sep 2004

posted posted 11-13-2005 06:51

Gah, had a long reply written on this, but dosbox caused a kernel panic on my mac...

So I'll give you a shorty instead: JavaScript has correctness as paramount, while VBScript has convenience. VBScript does what you want in most cases, but is unable to at all handle the odd cases. JavaScript on the other hand go for being correct in all cases, at the cost of that you need to code the cleaner display of numbers yourself.



As to the real problem here, it lies in the difference between binary and decimal. Binary is base 2, decimal base 10. For doing math on computers, we really didn't chose a good base for out numbers, all those centuries ago...

Anyway. Think about if you wrote fractional numbers in binary:

code:
2^-n:   0   1       2       3       4       5           1,3,5
        1   1/2     1/4     1/8     1/16    1/32        21/32
bin:    1   .1      .01     .001    .0001   .00001      .10101
dec:    1   .5      .25     .125    .0625   .03125      .65625
hex:    1   .8      .4      .2      .1      .08         .a8

Back to the bases, decimal radix is 10, binary is 2. 10 is factorisable into 2 and 5. Now what does this have to do with things? Well, it means the following:

code:
n/10:   10  9   8   7   6   5   4   3   2   1
dec:    1   .9  .8  .7  .6  .5  .4  .3  .2  .1
bin:    1   -   -   -   -   .1  -   -   -   -
hex:    1   -   -   -   -   .8  -   -   -   -

All numbers represented with a dash cannot be precisely represented in binary because they aren't evenly divisible with 5. 5 being a prime, fractions of it can't be precisely represented in base 2.


Look at the first table I listed here. Note that what need a single "decimal" in binary may need several "decimals" in decimal? The floating point number has a definite maximum number of binary "decimals", but thos can't be translated straight to decimal. Depending on what exact number we're representing, we we may have a different precision than the next larger/smaller number. If we had used hexadecimal instead of the decimal system, this same property would exist, but since hexadecimal numbers are factorisable to 2, we would have eliminated part of what makes this so evident when using floating point numbers.

--
var Liorean = {
abode: "http://web-graphics.com/",
profile: "http://codingforums.com/member.php?u=5798"};

Sevenspade
Obsessive-Compulsive (I) Inmate

From:
Insane since: Oct 2005

posted posted 11-13-2005 23:13

I understood. The part I quoted above was the answer I was looking for. I'm sorry you thought differently, but I'm grateful that you would take the time to explain bases and the limits of floating point numbers.

BillyRayPreachersSon
Bipolar (III) Inmate

From: London
Insane since: Jul 2004

posted posted 11-15-2005 13:18

You can also use "toFixed" to display a fixed number of DP:

code:
alert(123.45678.toFixed(2));



Dan

liorean
Bipolar (III) Inmate

From: Umeå, Sweden
Insane since: Sep 2004

posted posted 11-15-2005 23:00

Ie5 (mac and win) as well as saf doesn't *correctly* support toFixed. (The version I checked this in, at least. They might have added it now, I looked at this before saf 1.3/2.0.)
Also, toFixed is subject to this same problem in ie5.5w and ie6w - if the least significant digit is rounded unfortunately it will still display too many decimals.

--
var Liorean = {
abode: "http://web-graphics.com/",
profile: "http://codingforums.com/member.php?u=5798"};

(Edited by liorean on 11-15-2005 23:03)

« BackwardsOnwards »

Show Forum Drop Down Menu