3

I know that for getting a 10 based logarithm I have to use Math.log() divided by the constant of the natural logarithm of 10.

var e1000 = Math.log(1000) / Math.LN10;

// Result: 2.9999999999999996 instead of 
//   expected 3.
console.log(e1000); 

// Result:  999.999999999999 instead of
//   expected 1000.
console.log(Math.pow(10, e1000));

BUT: The result is just an approximation. If I use the calculated value in further calculation the inaccuracy becomes worse.

Am I doing something wrong? Is there are more elegant way around it then just using Math.ceil()?

cluster1
  • 4,968
  • 6
  • 32
  • 49
  • http://stackoverflow.com/a/3439981/251311 – zerkms Jul 11 '15 at 08:19
  • In general, you can't expect floating point numbers to be exact. If your program relies on that, you'll need to rethink your approach. – Teepeemm Jul 11 '15 at 19:45
  • 1
    I don't think this question is duplicate with current questions mentioned, first I think the main theme of is question is about log,but not floating point issue. Also, even solving floating point is a solution, it may be one of solutions only , there may be some solutions specific to log (e.g.: division until 0) other than solving float point issue. – ggrr Jul 13 '15 at 01:29
  • @amuse, I agree with you, this question is about solving the specific effect the floating point issue has on log10 and finding a workable solution/alternative for log10, not about the occurrence of floating calculation differences in general. Voted to reopen. – Me.Name Jul 14 '15 at 07:24

1 Answers1

1

The floating point rounding difference is known and coincidentally the 2.9999 is the exact example used in the MDN Math.Log page. As you mentioned Math.ceiling can be used to alther the result. Likewise you could increase the base number and use a smaller divider to decrease the change of floating errors. e.g.

function log10(value){
  return -3 * (Math.log(value * 100)  / Math.log(0.001))  - 2;
}

Example: fiddle

As a sidenote, some browsers already support the Math.log10 functionality, you could extend Math to use the function above if it is not implemented with:

if (!Math.log10) Math.log10 = function(value){
  return -3 * (Math.log(value * 100)  / Math.log(0.001))  - 2;
};

After running that initializer, you can simply use Math.log10() and your code will automatically use the browser functionality where it is (or when it becomes) available. (fiddle)

Me.Name
  • 12,259
  • 3
  • 31
  • 48
  • "e1000 = (Math.log(1000 * 100000) / Math.LN10) - 5;" works perfectly fine. :-) Thanks a lot. You're awesome. – cluster1 Jul 11 '15 at 08:57
  • :) Thanks, glad you could use it. Was curious to see if it behaved well with log10s of fractions too and was happy to see it did. Although log10(0.01) still gave a rounding difference which was solved with a slightly larger base: `(Math.log(value * 1000000) / Math.LN10) - 6;` – Me.Name Jul 11 '15 at 09:10
  • hmm, with 6, 1000 gives rounding errors again, perhaps it's not as generic as I hoped it would be – Me.Name Jul 11 '15 at 09:16
  • Mmhh ... I'm afraid you're right. "2.9999999999999982" in Firebug / Firefox. – cluster1 Jul 11 '15 at 11:01
  • Did some fiddling around, by also decreasing the divider it seems to work `-3 * (Math.log(value * 100) / Math.log(0.001)) - 2;` – Me.Name Jul 11 '15 at 11:16
  • allrighty, that was a fun excercise, tested the function on firefox, chrome and ie, where it produced the expected results for all numbers in the test code `for(var v = 0.001; v <= 10000000; v*=10) console.log( log10(v));` – Me.Name Jul 11 '15 at 11:39
  • Yep. Works and produces an interesting output on the console if you write "console.log( v + ': ' + Math.log10(v));" ;-) Thx! – cluster1 Jul 11 '15 at 12:56
  • Have put this Q&A on Twitter It provoked a lot of favs & retweets. Thank you a lot for you're endeavour. – cluster1 Jul 11 '15 at 15:18
  • @Me.Name the `*=` operator in your program already introduces rounding errors. Unless you write the fractions as float literals or a expressions of the form `1.0 / powerOfTen`, the result of your code doesn't prove anything at all. – Roland Illig Apr 22 '19 at 06:43