paulmillr / es6-shim

ECMAScript 6 compatibility shims for legacy JS engines
http://paulmillr.com
MIT License
3.11k stars 389 forks source link

relative error is too big for Math.expm1 and Math.log1p #314

Closed Yaffle closed 9 years ago

Yaffle commented 9 years ago

Math.expm1(-2e-17)

Math.log1p(-2e-17)

ljharb commented 9 years ago

The spec doesn't tend to define precision very well for its Math operations. Can you link to something in the spec that's incorrect here? What values do you expect? In what browser(s) are you getting which values that you don't expect?

Yaffle commented 9 years ago

@ljharb , so why not to use Math.exp(x) - 1 or Math.log(1 + x) ? You can define Math.expm1 = function (){} according to the spec, but does it make your shim good?

https://github.com/kangax/compat-table/issues/392

ljharb commented 9 years ago

I'm still not understanding what this issue is about. All three of the variables referenced in the compat-table issue return true for me in Chrome with or without the es6-shim (since they're native). In which browsers are you seeing any of these return false?

Also, if the spec does not explicitly say that your error criteria must be applied, then they need not be applied by this shim or by any browsers. I'm definitely open to making them more precise, but the shims are "good" so long as they provide any guarantees the spec requires of them, nothing more.

ljharb commented 9 years ago

Thanks for your examples - I'm sorry we continue to have misunderstandings in these issues, I hope we can chalk it up to language barriers.

I've added failing tests for log1p, and corrected them, in the es6-shim. While our number 1 priority is to comply with the spec, number 2 is, when it doesn't conflict with the spec, to comply with the majority of implementations - in this case, both of these math functions aren't returning the same values as their native counterparts.

I can't locate a polyfill for expm1 that's not exp(1) - 1, and that polyfill has the error you described. Do you have a suggested implementation?

Yaffle commented 9 years ago

I have only this(using Taylor series expansion):

Math.expm1 = function (x) {
  if (x !== x || x === 0) {
    return x;
  }
  if (Math.abs(x) > 1 / 2) {
    return Math.exp(x) - 1;
  }
  var t = x;
  var s = 0;
  var n = 1;
  while (s + t !== s) {
    s += t;
    n += 1;
    t *= x;
    t /= n;
  }
  return s;
};
ljharb commented 9 years ago

@Yaffle Thanks, that seems to do it! Can you suggest more meaningful variable names than "t", "s", and "n"?