svaarala / duktape

Duktape - embeddable Javascript engine with a focus on portability and compact footprint
MIT License
5.95k stars 514 forks source link

Add missing ES2015 Math built-ins #1070

Open fatcerberus opened 7 years ago

fatcerberus commented 7 years ago

Implement new Math built-in functions which were added in ES6.

fatcerberus commented 7 years ago

@svaarala I have a branch that adds support for Math.cbrt(), however no pull yet because cbrt() is C99-only and I haven't come up with an alternative. You can sort-of emulate cube root using pow(x, 1/3) but that apparently doesn't work for negative values.

svaarala commented 7 years ago

The pow() workaround should be possible as sign(x) * pow(fabs(x), 1.0/3.0), IOW:

> Math.cbrt(-6)
-1.8171205928321394
> -Math.pow(6, 1/3)
-1.8171205928321397

This is one case where it would be annoying if it was mandatory to provide a replacement for a missing cbrt() (wrapped as DUK_CBRT()) platform binding because there's an easy workaround. So maybe the code could be something like:

duk_double_t res;

[...]
#if defined(DUK_CBRT)
res = cbrt(x);
#else
if (DUK_SIGNBIT(x)) {
res = -DUK_POW(-x, 1.0/3.0);
} else {
res = DUK_POW(x, 1.0/3.0);
}
#endif
[...]

This would allow a replacement to be provided; if not, there would be a useful fallback without porting hassle.

fatcerberus commented 7 years ago

I see the values don't match exactly (likely due to limited precision), however that should be okay since ES6 does say it returns a "platform-dependent approximation".

fatcerberus commented 7 years ago

log2() and log10() might be useful to add too, the rest have more limited uses and can wait for a future release.

svaarala commented 7 years ago

Remaining methods are mostly basic standard library mappings, with maybe some thought about providing fill-ins if not provided by platform headers. fround() is essentially (double) (float) x but I'll need to check if C cast guarantees fulfill the Ecmascript guarantees. If not, bit twiddling is needed to implement it correctly.

fatcerberus commented 7 years ago

My main concern with the double-float-double cast was that the compiler might misguidedly optimize the casts away.

svaarala commented 7 years ago

I don't think a compliant compiler is allowed to do that?

svaarala commented 7 years ago

Optimizing the cast away would be similar to skipping the cast in (uint32_t) (uint16_t) x (which should be equivalent to x & 0xffffUL) I think.

svaarala commented 7 years ago

Hmm, maybe I'll implement the bit twiddling version first - it's quite straightforward for normals at least.