Skip to content

Commit 14f9be7

Browse files
committed
Merge branch 'develop' of https://github.com/stdlib-js/stdlib into feature/random
2 parents 8363a06 + 2849710 commit 14f9be7

137 files changed

Lines changed: 2771 additions & 106 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

FAQ.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* [Why numeric computing in JavaScript?](#numeric-computing-in-javascript)
77
* [What about WebAssembly?](#web-assembly)
88
* [Why reimplement and provide custom Math implementations?](#custom-math-implementations)
9+
* [Why not change the official ECMAScript specification to use better Math algorithms?](#ecmascript-math-specification)
910
* [Why reimplement module functionality already available on npm?](#reimplementing-existing-packages)
1011
* [Backward compatibility?](#backward-compatibility)
1112
* [Promise support?](#promise-support)
@@ -71,6 +72,51 @@
7172
<!-- </faq-question> -->
7273

7374

75+
<!-- <faq-question> -->
76+
77+
---
78+
79+
<a name="ecmascript-math-specification"></a>
80+
81+
### Why not change the official ECMAScript specification to use better Math algorithms?
82+
83+
Common arguments in support of changing the official ECMAScript specification:
84+
85+
* __standards__: everyone benefits from using common implementations.
86+
* __network__: more and better built-ins translates to smaller bundles and thus decreased network costs.
87+
* __evergreen__: improving built-ins means existing codebases using built-ins get "upgraded" (and patched) for free.
88+
89+
On the surface, the above arguments seem compelling. They fail, however, to recognize the rather messy reality of JavaScript applications and originate from a misunderstanding as to how JavaScript is implemented and practiced today.
90+
91+
A central thesis of this project is as follows:
92+
93+
> The standard Math library in JavaScript is fundamentally broken and cannot, and should not, be fixed through the official ECMAScript standard.
94+
95+
The reasons are as follows:
96+
97+
1. __underspecified standard__: the ECMAScript specification for the standard Math library is underspecified, but not without merit. Namely, underspecification allows those implementing the specification to make trade-offs between speed and precision. Were the specification to mandate a particular algorithm, e.g., for `Math.sin`, implementers would be locked into __always__ using a particular implementation. Especially for special functions, different algorithms will yield different results under varying conditions. Thus, to change an underlying algorithm would mean to break backward compatibility. By not committing themselves to any hard backward compatibility constraints, implementors maintain a degree of flexibility, including the ability to use algorithms which cater to a particular user base (gaming versus numeric computing). In which case, underspecification has advantages.
98+
99+
1. __cross-browser variability__: an underspecified standard, however, has disadvantages. Because implementors are free to choose underlying algorithms, relying exclusively on built-in Math functionality renders portability across more than one environment impossible. Even if all implementors happened to use the same underlying algorithm, a developer cannot, *a priori*, __guarantee__ or assume that only one algorithm is implemented. The default assumption must be: *if more than one algorithm can exist, more than one algorithm will exist*.
100+
101+
1. __no single codebase__: unlike other standard libraries (e.g., Golang, Python, Julia, etc), JavaScript does not have a single shared codebase. Each browser manufacturer has their own implementation and independent codebase with varying architecture and organization. More fundamentally, a common *implementation* does __not__ exist; only common *interfaces* exist. Thus, a developer wanting to write a numerical application must navigate and understand multiple sources of truth. Such expenditures incur significant overhead, especially when wanting to file issues, submit patches, or standardize a particular algorithm. For example, a patch in Chrome does not translate to a patch in Safari. Because each implementor is free to erect a protected castle, those writing numerical algorithms are resigned to treating the standard Math library as a black box and must always cater to the lowest common denominator (which is often the empirically determined slowest and/or least precise algorithm).
102+
103+
1. __versioning__: a developer does not have the freedom to choose which version of a particular algorithm she is given. In an "evergreen" environment, her application is only guaranteed a consistent interface, not an underlying implementation. Each background update may influence results in subtle ways and introduce bugs and unforeseen variability. A developer relying exclusively on standard library built-ins cannot assume reproducibility upon relaunching a browser. Thus, not only is cross-browser portability problematic, but same-browser-different-version portability is problematic.
104+
105+
1. __required shims__: because no common codebase exists and implementors make mistakes, application developers are dependent on shims (i.e., libraries which ensure consistent implementations across browsers, provide missing built-in functionality, and patch bugs). The issue here, of course, is that, if an application developer must supply a shim, reduced network cost due to the presence of built-ins is non-existent: an implementation is sent over the network regardless in order to patch a possibly buggy environment. While a developer could use browser sniffing and HTTP2 to lazily load patches, such practices incur a performance cost. Accordingly, if an implementation is sent irrespective of whether an environment provides an implementation natively, why does an environment need to guarantee the existence of an implementation in the first place?
106+
107+
1. __globals__: standard library functions are unprotected globals (they need to be, or else how would shims work?). This means, however, that, not only must a numerical application developer worry about cross-browser and same-browser portability, but she must also worry about third party libraries overriding built-ins. Hence, a numerical application developer must always consider a JavaScript environment a hostile environment, leaving her no choice but to provide her own guarded implementations.
108+
109+
1. __testing__: while implementors can be reasonably trusted to implement a specification, implementors vary in their knowledge and ability to rigorously test numerical algorithms. Too often numerical tests fail to adequately cover input argument regimes and edge cases, and rarely do tests cross-compare against implementations in other platforms and environments. While outside developers are free to contribute tests to implementation codebases, the lack of a single codebase means that work must be duplicated across many other codebases.
110+
111+
1. __no golden algorithm__: those who advocate for standard algorithms assume that __a__ standard algorithm is all that is needed. The reality, however, is that different applications require different algorithms. For example, many developers believe (incorrectly) that an environment only needs one pseudorandom number generator (PRNG). And if we only implemented the very best possible PRNG, our problems would be solved. Such a belief, however, is mistaken. Numerical applications, particularly simulations, often require more than one different type of PRNG (e.g., LCG versus Xorshift) in order to ensure that the results of a simulation are not an artifact of the PRNG itself. Furthermore, having a standardized, e.g., `Math.sin`, algorithm does __not__ eliminate the need for other algorithms which compute sine. The "optimal" implementation depends on a variety of factors, including speed, precision, value range, and more. Ultimately, the individual best equipped to determine which algorithm is most appropriate for an application is the developer herself.
112+
113+
1. __timescale__: specifications and bug fixes are implemented over extended timescales. Historically, improving the standard Math library has been low priority (e.g., Mozilla first identified the need to improve `Math.random()` in 2006 and did not do so until 2015). Even if advocating for official inclusion in ECMAScript was believed desirable, the time involved to enact such implementation is not worth the effort: community solutions can simply move much faster in terms of development, testing, patching, and maintenance.
114+
115+
1. __trust__: at a very fundamental level, trust is broken. This reason underscores all the others. A continued history of bugs, poor algorithms, insufficient testing, lack of IEEE 754 compliance, favoring speed at the cost of precision, insufficient domain knowledge, and carelessness with backward compatibility present an overwhelming case that JavaScript environments cannot, on their own, be relied upon to provide a single consistent solution to the Math problem.
116+
117+
Based on the reasons above, Math is fundamentally broken at the standards and native implementation levels. Nevertheless, based on the existence of solid low-level primitives, speed, and ecosystem, this project maintains that JavaScript __is__ a viable platform for numeric and mathematical computing. The solution, however, does not entail standardization, but rather the development of independent community-driven solutions which can provide the kind of rigorous, robust, and performant numerical algorithms applications need.
118+
119+
74120
<!-- <faq-question> -->
75121

76122
---

TODO.md

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
TODO
2-
====
1+
# TODO
32

43
0. once `stdlib` is live (merged to `master` and published), make the default branch be `develop`
54

@@ -391,6 +390,8 @@ TODO
391390
- [ansi-escapes](https://github.com/sindresorhus/ansi-escapes)
392391
- [node-charm](https://github.com/substack/node-charm)
393392
- [gvz](https://github.com/chrisdickinson/gvz)
393+
- [UnicodePlots.jl](https://github.com/Evizero/UnicodePlots.jl)
394+
- [TextPlots.jl](https://github.com/sunetos/TextPlots.jl)
394395

395396
* ASCII [tables](https://github.com/sorensen/ascii-table)
396397

@@ -666,9 +667,7 @@ TODO
666667
667668
- could use `@browseronly` and `@nodejsonly` special annotations, akin to `@private` and `@public`
668669
669-
76. `@stdlib/regexp/extname`, `*/dirname` export circular references; prob best to clone the regexp and bind to exported object
670-
671-
* requires porting `utils-copy`
670+
76. electron ui for creating a `stdlib` bundle (could support rollup, webpack, browserify)
672671
673672
77. for browser REPL, use a virtual filesystem
674673
@@ -806,7 +805,7 @@ TODO
806805
* [x] fs
807806
* [x] math/base/blas
808807
* [ ] math/base/dist
809-
* [ ] math/base/random
808+
* [-] math/base/random
810809
* [ ] math/base/special
811810
* [ ] math/base/tools
812811
* [ ] math/base/utils
@@ -1098,6 +1097,8 @@ TODO
10981097
10991098
193. timed [tape](https://github.com/diasdavid/timed-tape) tests...useful?
11001099
1100+
- once `tape` is brought in-house, could make part of the lib
1101+
11011102
194. [match-case](https://github.com/wooorm/match-casing)
11021103
11031104
195. Consider setting up [jenkins](https://jenkins.io/) for CI (notably Windows)
@@ -1187,13 +1188,9 @@ TODO
11871188
11881189
236. [travis-deploy-example](https://github.com/bcoe/travis-deploy-example)
11891190
1190-
237. test-tools, test-tools-cov mk recipe
1191-
1192-
238. static stats mk recipe
1191+
237. [reserved words](http://www.javascripter.net/faq/reserved.htm) and [reserved words](https://mathiasbynens.be/notes/reserved-keywords) and [keywords](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar)
11931192
1194-
- num files (w/ breakdown by extension num/%)
1195-
- size
1196-
- num lines
1193+
238. a branch (based on `master`) which every month is run against every single Node version since `0.10.0` (may want a separate Jenkins server for this)
11971194
11981195
239. Given an import-require tree, should be able to statically detect cyclic deps and flag
11991196
@@ -1230,6 +1227,7 @@ TODO
12301227
- [churn](https://gist.github.com/coreyhaines/829932)
12311228
- [churn](https://github.com/danmayer/churn)
12321229
- [code-maat](https://github.com/adamtornhill/code-maat)
1230+
- [GitHub analysis](https://github.com/StephenOTT/GitHub-Analytics)
12331231
12341232
255. link [checking](https://github.com/golang/go/blob/master/misc/linkcheck/linkcheck.go)
12351233
@@ -1330,7 +1328,6 @@ TODO
13301328
- [duplexer2](https://github.com/deoxxa/duplexer2)
13311329
- [mississippi](https://github.com/maxogden/mississippi)
13321330
- `to-console` or maybe `to-log` (provide own logger, with default being console using util-inspect) => write stream which writes each chunk to console (either normal or object mode); if object mode, use util-inspect and allow setting of depth
1333-
- `debug` as a transform stream => could provide name and then toggle debugging based on name!
13341331
- [tap-stream](https://github.com/thlorenz/tap-stream) and [inspect-stream](https://github.com/thlorenz/inspect-stream/blob/master/inspect-stream.js); see also [sculpt#tap](https://github.com/Medium/sculpt#tap)
13351332
- [guide](https://gist.github.com/joyrexus/10026630) to node streams
13361333
- [vstream](https://github.com/joyent/node-vstream) => instrumented streams

docs/native_math_bugs.md

Lines changed: 48 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,30 @@
22

33
> Bugs in the native (built-in) `Math` namespace.
44
5-
* [Sine and cosine in V8][1]
6-
* [Trigonometric functions in V8][2]
7-
* [V8 not IEEE 754-2008 compliant][3]
8-
* [Mozilla discussion on sine and cosine in V8][4]
9-
* [V8 replaced a lookup table by computing `Math.tan` as `Math.sin/Math.cos`][5]
10-
* [Browser math accuracy issues][6]
11-
* [ES6 accuracy of special functions][7]
12-
* [Accuracy of `Math.exp` in V8][8]
13-
* [Spreadsheet showing trigonometric results across browsers][9]
14-
* [Accuracy of `Math.pow` in V8][10]
15-
* [Accumulation of errors in Mozilla `Math.pow`][11]
16-
* [Accuracy of hyperbolic trigonometric functions in V8][12]
17-
* [TC39 testing of Math built-ins][13]
18-
* [ES6 shim accuracy issues][14]
5+
* [Sine and cosine in V8][@bug:v8:3006]
6+
* [Trigonometric functions in V8][@bug:chromium:320097]
7+
* [V8 not IEEE 754-2008 compliant][@bug:v8:3089]
8+
* [Mozilla discussion on sine and cosine in V8][@bug:mozilla:967709]
9+
* [V8 replaced a lookup table by computing `Math.tan` as `Math.sin/Math.cos`][@bug:chromium:78263005]
10+
* [Browser math accuracy issues][@bug:kangax:compat-table:392]
11+
* [Mozilla attempt to address precision in new Math functions][@bug:mozilla:933257]
12+
* [Mozilla's previous lack of tolerance tests for Math functions][@bug:mozilla:892671]
13+
* [Mozilla `Math.expm1` accuracy][@bug:mozilla:897634]
14+
* [Mozilla thread on implementing ES6 math functions][@bug:mozilla:717379]
15+
* [V8 `Math.atanh` issues][@bug:v8:3511]
16+
* [V8 `Math.acosh` issues][@bug:v8:3509]
17+
* [V8 `Math.asinh` issues][@bug:v8:3496]
18+
* [V8 numeric issues in hyperbolic functions][@bug:v8:3266]
19+
* [ES6 accuracy of special functions][@bug:esdiscuss:038525]
20+
* [Accuracy of `Math.exp` in V8][@bug:v8:3468]
21+
* [TC39 meeting discussing Math accuracy issues][@bug:esdiscuss:2014-07-31]
22+
* [Spreadsheet showing trigonometric results across browsers][@bug:esdiscuss:038525:spreadsheet]
23+
* [Accuracy of `Math.pow` in V8][@bug:v8:3599]
24+
* [Accumulation of errors in Mozilla `Math.pow`][@bug:mozilla:618251]
25+
* [Accuracy of hyperbolic trigonometric functions in V8][@bug:paulmiller:es6-shim:334]
26+
* [ES6 shim accuracy issues][@bug:paulmillr:es6-shim:314]
27+
* [TC39 testing of Math built-ins][@bug:tc39:test262:269]
28+
1929
* [Non-randomness of `Math.random` in V8][15]
2030
* [V8 fixes `Math.random`][16]
2131
* [V8 patches `Math.random` to return pseudorandom numbers][17]
@@ -37,20 +47,30 @@
3747

3848
<!-- <links> -->
3949

40-
[1]: https://bugs.chromium.org/p/v8/issues/detail?id=3006
41-
[2]: https://bugs.chromium.org/p/chromium/issues/detail?id=320097
42-
[3]: https://bugs.chromium.org/p/v8/issues/detail?id=3089
43-
[4]: https://bugzilla.mozilla.org/show_bug.cgi?id=967709#c33
44-
[5]: https://github.com/v8/v8/commit/33b5db090258c2a2dc825659c3ad109bd02110c1
45-
[6]: https://github.com/kangax/compat-table/issues/392
46-
[7]: https://esdiscuss.org/topic/es6-accuracy-of-special-functions
47-
[8]: https://bugs.chromium.org/p/v8/issues/detail?id=3468
48-
[9]: https://docs.google.com/spreadsheets/d/1t2jrptAvaQetDIYPD8GKc90Dni2dT3FuHgKKFF-eJHw/edit#gid=0
49-
[10]: https://bugs.chromium.org/p/v8/issues/detail?id=3599
50-
[11]: https://bugzilla.mozilla.org/show_bug.cgi?id=618251
51-
[12]: https://github.com/paulmillr/es6-shim/issues/334
52-
[13]: https://github.com/tc39/test262/pull/269
53-
[14]: https://github.com/paulmillr/es6-shim/issues/314
50+
[@bug:v8:3006]: https://bugs.chromium.org/p/v8/issues/detail?id=3006
51+
[@bug:chromium:320097]: https://bugs.chromium.org/p/chromium/issues/detail?id=320097
52+
[@bug:v8:3089]: https://bugs.chromium.org/p/v8/issues/detail?id=3089
53+
[@bug:mozilla:967709]: https://bugzilla.mozilla.org/show_bug.cgi?id=967709
54+
[@bug:chromium:78263005]: https://github.com/v8/v8/commit/33b5db090258c2a2dc825659c3ad109bd02110c1
55+
[@bug:kangax:compat-table:392]: https://github.com/kangax/compat-table/issues/392
56+
[@bug:mozilla:933257]: https://bugzilla.mozilla.org/show_bug.cgi?id=933257
57+
[@bug:mozilla:892671]: https://bugzilla.mozilla.org/show_bug.cgi?id=892671
58+
[@bug:mozilla:897634]: https://bugzilla.mozilla.org/show_bug.cgi?id=897634
59+
[@bug:mozilla:717379]: https://bugzilla.mozilla.org/show_bug.cgi?id=717379#c5
60+
[@bug:v8:3511]: https://bugs.chromium.org/p/v8/issues/detail?id=3511
61+
[@bug:v8:3509]: https://bugs.chromium.org/p/v8/issues/detail?id=3509
62+
[@bug:v8:3496]: https://bugs.chromium.org/p/v8/issues/detail?id=3496
63+
[@bug:v8:3266]: https://bugs.chromium.org/p/v8/issues/detail?id=3266
64+
[@bug:esdiscuss:038525]: https://esdiscuss.org/topic/es6-accuracy-of-special-functions
65+
[@bug:v8:3468]: https://bugs.chromium.org/p/v8/issues/detail?id=3468
66+
[@bug:esdiscuss:2014-07-31]: https://esdiscuss.org/notes/2014-07-31
67+
[@bug:esdiscuss:038525:spreadsheet]: https://docs.google.com/spreadsheets/d/1t2jrptAvaQetDIYPD8GKc90Dni2dT3FuHgKKFF-eJHw/edit#gid=0
68+
[@bug:v8:3599]: https://bugs.chromium.org/p/v8/issues/detail?id=3599
69+
[@bug:mozilla:618251]: https://bugzilla.mozilla.org/show_bug.cgi?id=618251
70+
[@bug:paulmiller:es6-shim:334]: https://github.com/paulmillr/es6-shim/issues/334
71+
[@bug:paulmillr:es6-shim:314]: https://github.com/paulmillr/es6-shim/issues/314
72+
[@bug:tc39:test262:269]: https://github.com/tc39/test262/pull/269
73+
5474
[15]: https://medium.com/@betable/tifu-by-using-math-random-f1c308c4fd9d#.pxwdcvikc
5575
[16]: http://hackaday.com/2015/12/28/v8-javascript-fixes-horrible-random-number-generator/
5676
[17]: http://thenextweb.com/google/2015/12/17/google-chromes-javascript-engine-finally-returns-actual-random-numbers/#gref

0 commit comments

Comments
 (0)