0

I need to find the average of a set of values and after doing some reading am not sure if JavaScript is able to produce an accurate result or not.

Each value has a precision of 2 d.p. and there could be up to 10000 of them between -100000.00 and 100000.00. The result also needs to be to 2 d.p.

From what I can see it is usually the figures around the 16th decimal place that are inaccurate which means that I would have to average an extremely large set before affecting my result. Is the best way of doing it to simply sum all of the values, divide by the total number and then use a toFixed(2)?

Jim
  • 1,333
  • 1
  • 11
  • 15
  • Neither JS nor PHP is known to have high precision. You should do this with a programming language like C that is closer to the hardware and can use 64bit for numbers. – Powerriegel Mar 18 '15 at 17:16

1 Answers1

0

You could take advantage of your 2dp prevision, and multiply all your numbers by 100 first, then do the mathematics using integers. EG, a float error occurs in this simple average (I am just using 1dp for this example):

(0.1 + 0.2) / 2
0.15000000000000002

But this works:

(0.1*10 + 0.2*10) / (2*10)
0.15

Some good reading here:

http://floating-point-gui.de/basic/

and here:

How to deal with floating point number precision in JavaScript?

and a really precise fix to do it using decimals is to use this:

https://github.com/dtrebbien/BigDecimal.js

Example for 2 dp:

var numbers = [0.10, 0.20, 0.30]

var simple_average = numbers.reduce(function(a, b) {
    return a + b
}) / numbers.length
console.log(simple_average)

var smart_average = numbers.map(function(a) {
    return a * 100
}).reduce(function(a, b) {
    return a + b
}) / (numbers.length * 100) 
console.log(smart_average)

This demo can be run here -- http://repl.it/e1B/1

Community
  • 1
  • 1
sifriday
  • 4,342
  • 1
  • 13
  • 24
  • I'm not sure multiplying by 10 first is always accurate. E.g. 0.34 * 10 gives 3.4000000000000004. – Jim Mar 18 '15 at 17:25
  • Yep, I multiply by 10 because I am giving you the example with 1dp. For 2dp, multiply everything by 100. 0.34 * 100 is 34, just as you need it :-) – sifriday Mar 18 '15 at 17:28
  • I just added an example for 2dp, which relies on Array.reduce so modern JS only! https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce – sifriday Mar 18 '15 at 17:30
  • I tried your example but when you use 3 or more numbers it seems to go wrong. – Jim Mar 18 '15 at 17:43
  • 1
    Oh it's because you need to add a divide by 100 in the reduce otherwise it keeps mulitplying by 100 and adding it on to the next number. Should be `reduce(function(a,b) {return (a*100 + b*100)/100}) / numbers.length` – Jim Mar 18 '15 at 17:52
  • sorry yes you're right! will correct the above. I did it a bit differently to yourself; I think your suggestion risks returning a value with 2dp for the reduction, whereas I have gone with *100 first, then reducing to a sum to stay entirely in ints. – sifriday Mar 18 '15 at 17:55