ES6 accuracy of special functions

# Carl Shapiro (11 years ago)

In ECMA-262, section 15.8.2, the note allows implementations to choose appropriate algorithms for the evaluation of the special functions and it is recommended but not required to use the algorithms from fdlibm netlib.org/fdlibm.

Since this is a recommendation and not a requirement implementations compute incorrect results for some values. This produces things where Math.cos(Math.pow(2,120)) doesn’t even have the correct sign or basic identities like sin(-x) = -sin(x) don’t hold for all finite values of x. This spreadsheet gives some results from various browsers on some selected functions.

This lack of precision makes it very difficult to port numerical applications from C or Java to Javascript. It also forces every serious numerical Javascript application to test against every browser and platform for correct behaviour. This seems a major disservice to the web platform and Javascript in particular.

Since the specification recommends using the algorithms from fdlibm, which, I believe produces results that are accurate to < 1 ulp, why not make this a requirement? As the spreadsheet shows, many browsers already achieve correct results. Porting fdlibm to Javascript is not particularly difficult provided a couple of key routines are available. (My colleague has done this for the trig functions, except for the hairy case of the Payne-Hanek pi reduction routine.)

Note also that Java requires that many special function be accurate to < 1 ulp.

Specifying a similar requirement for Javascript should not be too onerous on existing implementations. Java is an existence proof that these requirements can work.

While having an accuracy requirement is good in itself, it’s also important that the functions are semi-monotonic to match the mathematical functions. This is also a requirement in Java. It is known that applications using divided differences behave incorrectly when functions are not monotonic when they should be.

# alawatthe (11 years ago)

Clear rules would also help in discussions like this one: code.google.com/p/v8/issues/detail?id=3006

Background: V8 implemented a new version of sin and cos, which is faster, but does not have the precision many user want. One of the comments (#8) said about precision:

The ECMA script specification clearly states that Math.sin/cos are implementation-dependent approximations. There is no guarantees required regarding precision.

I think, this feels a little bit odd, because where do we draw the line between performance and precision? So, again clear rules (even if they are not as strict as in Java), would help a lot.

# Carl Shapiro (11 years ago)

The exp function in V8 has a similar issue

code.google.com/p/v8/issues/detail?id=3468

as do the recently added hyperbolics

code.google.com/p/v8/issues/detail?id=3266

These issues are not limited to the V8 environment. As noted in the spreadsheet, other browsers exhibit similar behaviour.

Having relaxed constraints on the trigonometric functions can put a substantial burden on the user. Writing and testing an application becomes more time consuming and error prone. Using JS as a portable assembler for numeric applications requires additional care because the special functions deviate in their behaviour from the C library. Authoring an efficient and accurate implementation of the special functions generally requires access to low-level primitives not available in JS making it impossible to code around accuracy limitations portability and efficiently.

# Raymond Toy (11 years ago)

Yes. There are no requirements, but the spirit of the spec is clearly to be accurate or at least no worse than fdlibm.

Carried to the extreme, this lack of requirements allows implementations to be conforming even if all functions returned 0 everywhere. Fortunately, no one does that.

# Katelyn Gadd (11 years ago)

History has shown that native code developers concerned with performance (game devs, graphics devs, etc) will happily use approximations of these special functions when performance is important, and will pick approximations with suitable accuracy.

The inverse we have here, where the builtins have unpredictable precision, requires developers to test on various os/browser combinations to figure out whether they have precision issues, and if they do, try to find an accurate high-precision sw implementation of these builtins and use that. I think this will lead to a lot of unreliable software out there on the web, and worse, lead to existing apps breaking when new browser releases reduce precision/accuracy.

If there's a strong desire for high-performance builtin sin, cos, etc it could be reasonable to add Math.fastCos etc but I feel like most developers would feel safer with approximations that have known characteristics, so you should encourage that instead.

# Raymond Toy (11 years ago)

​I think Math.fastCos would be difficult to specify. Only the developer really knows what the appropriate tradeoff between accuracy and speed should be. Math.fastCos probably won't satisfy that.