@driftengine/core 4.8.2 → 4.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.json +127 -0
- package/README.md +1 -1
- package/dist/geometry/meshConcat.js +2 -0
- package/dist/index.d.ts +11 -4
- package/dist/index.js +22 -1
- package/dist/math/scalar.js +1 -1
- package/dist/render/anisotropicLobe.d.ts +7 -0
- package/dist/render/anisotropicLobe.js +33 -0
- package/dist/render/backend/api.d.ts +41 -4
- package/dist/render/backend/materialChanges.d.ts +7 -2
- package/dist/render/backend/materialChanges.js +8 -3
- package/dist/render/backend/select.js +8 -0
- package/dist/render/backend/webgl2/clothTextures.d.ts +27 -0
- package/dist/render/backend/webgl2/clothTextures.js +93 -0
- package/dist/render/backend/webgl2/renderer.d.ts +159 -3
- package/dist/render/backend/webgl2/renderer.js +662 -80
- package/dist/render/backend/webgl2/skinScatter.d.ts +50 -0
- package/dist/render/backend/webgl2/skinScatter.js +256 -0
- package/dist/render/backend/webgpu/buffers.d.ts +25 -11
- package/dist/render/backend/webgpu/buffers.js +98 -49
- package/dist/render/backend/webgpu/causticsPass.js +2 -1
- package/dist/render/backend/webgpu/clothSolvePack.d.ts +27 -0
- package/dist/render/backend/webgpu/clothSolvePack.js +129 -0
- package/dist/render/backend/webgpu/clothTextures.d.ts +68 -0
- package/dist/render/backend/webgpu/clothTextures.js +145 -0
- package/dist/render/backend/webgpu/compressedUpload.d.ts +18 -0
- package/dist/render/backend/webgpu/compressedUpload.js +38 -0
- package/dist/render/backend/webgpu/computeHost.d.ts +21 -0
- package/dist/render/backend/webgpu/computeHost.js +5 -0
- package/dist/render/backend/webgpu/depthPass.d.ts +29 -9
- package/dist/render/backend/webgpu/depthPass.js +43 -12
- package/dist/render/backend/webgpu/drawCommand.js +6 -2
- package/dist/render/backend/webgpu/filmPass.js +2 -1
- package/dist/render/backend/webgpu/flatPass.d.ts +43 -4
- package/dist/render/backend/webgpu/flatPass.js +111 -13
- package/dist/render/backend/webgpu/gpuSkinnedCloth.d.ts +74 -0
- package/dist/render/backend/webgpu/gpuSkinnedCloth.js +452 -0
- package/dist/render/backend/webgpu/linePass.js +2 -1
- package/dist/render/backend/webgpu/motionPass.d.ts +20 -0
- package/dist/render/backend/webgpu/motionPass.js +106 -9
- package/dist/render/backend/webgpu/panelPass.js +2 -1
- package/dist/render/backend/webgpu/particlePass.js +2 -1
- package/dist/render/backend/webgpu/plumePass.js +2 -1
- package/dist/render/backend/webgpu/postPass.d.ts +15 -3
- package/dist/render/backend/webgpu/postPass.js +25 -8
- package/dist/render/backend/webgpu/renderer.d.ts +123 -6
- package/dist/render/backend/webgpu/renderer.js +534 -58
- package/dist/render/backend/webgpu/sdfTextPass.js +2 -1
- package/dist/render/backend/webgpu/shaders/clothSolve.wgsl.d.ts +33 -0
- package/dist/render/backend/webgpu/shaders/clothSolve.wgsl.js +469 -0
- package/dist/render/backend/webgpu/skinScatterPass.d.ts +51 -0
- package/dist/render/backend/webgpu/skinScatterPass.js +253 -0
- package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +4 -1
- package/dist/render/backend/webgpu/surfaceTexturePass.js +37 -12
- package/dist/render/backend/webgpu/textPass.js +2 -1
- package/dist/render/backend/webgpu/waterPass.js +2 -1
- package/dist/render/backend/webgpu/windStreakPass.js +2 -1
- package/dist/render/boltBatch.js +2 -1
- package/dist/render/causticsRenderer.js +2 -1
- package/dist/render/clothBindingData.d.ts +41 -0
- package/dist/render/clothBindingData.js +72 -0
- package/dist/render/clothPlacement.d.ts +25 -0
- package/dist/render/clothPlacement.js +85 -0
- package/dist/render/compressedSource.d.ts +66 -0
- package/dist/render/compressedSource.js +138 -0
- package/dist/render/cutoutCaster.d.ts +5 -1
- package/dist/render/cutoutCaster.js +6 -0
- package/dist/render/cutoutDither.d.ts +51 -0
- package/dist/render/cutoutDither.js +90 -0
- package/dist/render/decalPass.js +2 -1
- package/dist/render/eyeRefraction.d.ts +35 -0
- package/dist/render/eyeRefraction.js +40 -0
- package/dist/render/glCompressed.d.ts +27 -0
- package/dist/render/glCompressed.js +53 -0
- package/dist/render/globalMediumPass.js +3 -2
- package/dist/render/hairLobes.d.ts +70 -0
- package/dist/render/hairLobes.js +120 -0
- package/dist/render/lightBudget.d.ts +22 -0
- package/dist/render/lightBudget.js +22 -0
- package/dist/render/lineBatch.js +5 -1
- package/dist/render/mesh.d.ts +7 -0
- package/dist/render/mesh.js +24 -0
- package/dist/render/oitPass.js +2 -1
- package/dist/render/particleBatch.js +3 -2
- package/dist/render/particlePool.d.ts +6 -2
- package/dist/render/plumeRenderer.js +3 -2
- package/dist/render/recon/motionVectors.d.ts +4 -2
- package/dist/render/recon/motionVectors.js +6 -3
- package/dist/render/renderQuality.d.ts +29 -2
- package/dist/render/renderQuality.js +5 -0
- package/dist/render/rendererHarness.js +4 -0
- package/dist/render/sceneCoverage.d.ts +54 -0
- package/dist/render/sceneCoverage.js +72 -0
- package/dist/render/sceneTarget.d.ts +12 -0
- package/dist/render/sceneTarget.js +14 -0
- package/dist/render/sdfTextRenderer.js +2 -1
- package/dist/render/shaders/clothBinding.d.ts +22 -0
- package/dist/render/shaders/clothBinding.js +80 -0
- package/dist/render/shaders/depth.js +45 -8
- package/dist/render/shaders/flat/anisotropic.d.ts +15 -0
- package/dist/render/shaders/flat/anisotropic.js +68 -0
- package/dist/render/shaders/flat/eye.d.ts +1 -0
- package/dist/render/shaders/flat/eye.js +81 -0
- package/dist/render/shaders/flat/hair.d.ts +1 -0
- package/dist/render/shaders/flat/hair.js +101 -0
- package/dist/render/shaders/flat/index.js +42 -3
- package/dist/render/shaders/flat/main.d.ts +1 -1
- package/dist/render/shaders/flat/main.js +113 -17
- package/dist/render/shaders/flat/models.d.ts +14 -0
- package/dist/render/shaders/flat/models.js +273 -0
- package/dist/render/shaders/flat/preamble.js +26 -24
- package/dist/render/shaders/flat/skin.d.ts +1 -0
- package/dist/render/shaders/flat/skin.js +114 -0
- package/dist/render/shaders/generated/depth.wgsl.d.ts +66 -24
- package/dist/render/shaders/generated/depth.wgsl.js +66 -24
- package/dist/render/shaders/generated/flat.wgsl.d.ts +1815 -1704
- package/dist/render/shaders/generated/flat.wgsl.js +1853 -1742
- package/dist/render/shaders/generated/line.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/line.wgsl.js +1 -1
- package/dist/render/shaders/generated/particle.wgsl.d.ts +3 -3
- package/dist/render/shaders/generated/particle.wgsl.js +3 -3
- package/dist/render/shaders/generated/rush.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/rush.wgsl.js +1 -1
- package/dist/render/shaders/generated/sdfText.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/sdfText.wgsl.js +1 -1
- package/dist/render/shaders/generated/skinBlur.wgsl.d.ts +48 -0
- package/dist/render/shaders/generated/skinBlur.wgsl.js +54 -0
- package/dist/render/shaders/generated/temporalResolve.wgsl.d.ts +1 -1
- package/dist/render/shaders/generated/temporalResolve.wgsl.js +1 -1
- package/dist/render/shaders/line.d.ts +1 -1
- package/dist/render/shaders/outputTransform.d.ts +14 -1
- package/dist/render/shaders/outputTransform.js +23 -1
- package/dist/render/shaders/particle.d.ts +3 -3
- package/dist/render/shaders/recon/motion.wgsl.d.ts +1 -1
- package/dist/render/shaders/recon/motion.wgsl.js +102 -0
- package/dist/render/shaders/recon/resolve.wgsl.js +15 -1
- package/dist/render/shaders/rush.js +13 -2
- package/dist/render/shaders/sdfText.d.ts +1 -1
- package/dist/render/shaders/skinBlur.d.ts +1 -0
- package/dist/render/shaders/skinBlur.js +103 -0
- package/dist/render/shaders/skinning.d.ts +3 -1
- package/dist/render/shaders/skinning.js +31 -4
- package/dist/render/shaders/temporalResolve.js +12 -5
- package/dist/render/shadowCasters.d.ts +13 -1
- package/dist/render/skinBlur.d.ts +41 -0
- package/dist/render/skinBlur.js +49 -0
- package/dist/render/skinScatter.d.ts +67 -0
- package/dist/render/skinScatter.js +80 -0
- package/dist/render/skinnedClothRun.d.ts +26 -0
- package/dist/render/skinnedClothRun.js +84 -0
- package/dist/render/ssrPass.js +2 -1
- package/dist/render/surfaceModel.d.ts +129 -0
- package/dist/render/surfaceModel.js +152 -0
- package/dist/render/surfaceTexture.d.ts +55 -4
- package/dist/render/surfaceTexture.js +60 -46
- package/dist/render/textRenderer.js +2 -1
- package/dist/render/vertexDefaults.js +8 -0
- package/dist/render/waterRenderer.js +2 -1
- package/dist/render/windStreakRenderer.js +2 -1
- package/package.json +6 -6
- package/src/geometry/meshConcat.ts +2 -0
- package/src/index.ts +53 -1
- package/src/math/scalar.ts +1 -1
- package/src/render/anisotropicLobe.ts +41 -0
- package/src/render/backend/api.ts +52 -3
- package/src/render/backend/materialChanges.ts +8 -3
- package/src/render/backend/select.ts +8 -0
- package/src/render/backend/webgl2/clothTextures.ts +120 -0
- package/src/render/backend/webgl2/renderer.ts +750 -80
- package/src/render/backend/webgl2/skinScatter.ts +309 -0
- package/src/render/backend/webgpu/buffers.ts +137 -63
- package/src/render/backend/webgpu/causticsPass.ts +2 -1
- package/src/render/backend/webgpu/clothSolvePack.ts +161 -0
- package/src/render/backend/webgpu/clothTextures.ts +194 -0
- package/src/render/backend/webgpu/compressedUpload.ts +65 -0
- package/src/render/backend/webgpu/computeHost.ts +25 -0
- package/src/render/backend/webgpu/depthPass.ts +43 -10
- package/src/render/backend/webgpu/drawCommand.ts +6 -2
- package/src/render/backend/webgpu/filmPass.ts +2 -1
- package/src/render/backend/webgpu/flatPass.ts +147 -8
- package/src/render/backend/webgpu/gpuSkinnedCloth.ts +502 -0
- package/src/render/backend/webgpu/linePass.ts +2 -1
- package/src/render/backend/webgpu/motionPass.ts +128 -9
- package/src/render/backend/webgpu/panelPass.ts +2 -1
- package/src/render/backend/webgpu/particlePass.ts +2 -1
- package/src/render/backend/webgpu/plumePass.ts +2 -1
- package/src/render/backend/webgpu/postPass.ts +25 -6
- package/src/render/backend/webgpu/renderer.ts +701 -52
- package/src/render/backend/webgpu/sdfTextPass.ts +2 -1
- package/src/render/backend/webgpu/shaders/clothSolve.wgsl.ts +470 -0
- package/src/render/backend/webgpu/skinScatterPass.ts +309 -0
- package/src/render/backend/webgpu/surfaceTexturePass.ts +42 -12
- package/src/render/backend/webgpu/textPass.ts +2 -1
- package/src/render/backend/webgpu/waterPass.ts +2 -1
- package/src/render/backend/webgpu/windStreakPass.ts +2 -1
- package/src/render/boltBatch.ts +2 -1
- package/src/render/causticsRenderer.ts +2 -1
- package/src/render/clothBindingData.ts +89 -0
- package/src/render/clothPlacement.ts +114 -0
- package/src/render/compressedSource.ts +198 -0
- package/src/render/cutoutCaster.ts +20 -2
- package/src/render/cutoutDither.ts +99 -0
- package/src/render/decalPass.ts +2 -1
- package/src/render/eyeRefraction.ts +72 -0
- package/src/render/glCompressed.ts +86 -0
- package/src/render/globalMediumPass.ts +3 -2
- package/src/render/hairLobes.ts +188 -0
- package/src/render/lightBudget.ts +25 -0
- package/src/render/lineBatch.ts +3 -1
- package/src/render/mesh.ts +23 -0
- package/src/render/oitPass.ts +2 -1
- package/src/render/particleBatch.ts +3 -2
- package/src/render/particlePool.ts +6 -2
- package/src/render/plumeRenderer.ts +3 -2
- package/src/render/recon/motionVectors.ts +6 -3
- package/src/render/renderQuality.ts +37 -2
- package/src/render/rendererHarness.ts +4 -0
- package/src/render/sceneCoverage.ts +78 -0
- package/src/render/sceneTarget.ts +21 -0
- package/src/render/sdfTextRenderer.ts +2 -1
- package/src/render/shaders/clothBinding.ts +81 -0
- package/src/render/shaders/depth.ts +45 -8
- package/src/render/shaders/flat/anisotropic.ts +68 -0
- package/src/render/shaders/flat/eye.ts +82 -0
- package/src/render/shaders/flat/hair.ts +102 -0
- package/src/render/shaders/flat/index.ts +42 -3
- package/src/render/shaders/flat/main.ts +113 -17
- package/src/render/shaders/flat/models.ts +286 -0
- package/src/render/shaders/flat/preamble.ts +26 -24
- package/src/render/shaders/flat/skin.ts +116 -0
- package/src/render/shaders/generated/depth.wgsl.ts +66 -24
- package/src/render/shaders/generated/flat.wgsl.ts +1853 -1742
- package/src/render/shaders/generated/line.wgsl.ts +1 -1
- package/src/render/shaders/generated/particle.wgsl.ts +3 -3
- package/src/render/shaders/generated/rush.wgsl.ts +1 -1
- package/src/render/shaders/generated/sdfText.wgsl.ts +1 -1
- package/src/render/shaders/generated/skinBlur.wgsl.ts +56 -0
- package/src/render/shaders/generated/temporalResolve.wgsl.ts +1 -1
- package/src/render/shaders/outputTransform.ts +24 -1
- package/src/render/shaders/recon/motion.wgsl.ts +102 -0
- package/src/render/shaders/recon/resolve.wgsl.ts +15 -1
- package/src/render/shaders/rush.ts +13 -2
- package/src/render/shaders/skinBlur.ts +105 -0
- package/src/render/shaders/skinning.ts +31 -4
- package/src/render/shaders/temporalResolve.ts +12 -5
- package/src/render/shadowCasters.ts +13 -0
- package/src/render/skinBlur.ts +53 -0
- package/src/render/skinScatter.ts +92 -0
- package/src/render/skinnedClothRun.ts +128 -0
- package/src/render/ssrPass.ts +2 -1
- package/src/render/surfaceModel.ts +274 -0
- package/src/render/surfaceTexture.ts +134 -63
- package/src/render/textRenderer.ts +2 -1
- package/src/render/vertexDefaults.ts +8 -0
- package/src/render/waterRenderer.ts +2 -1
- package/src/render/windStreakRenderer.ts +2 -1
- package/dist/math/exact.d.ts +0 -76
- package/dist/math/exact.js +0 -327
- package/src/math/exact.ts +0 -340
package/src/math/exact.ts
DELETED
|
@@ -1,340 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Transcendentals that give the same bits on every JavaScript engine.
|
|
3
|
-
*
|
|
4
|
-
* **Not more accurate than `Math`, and that is not what they are for.** These are within a couple
|
|
5
|
-
* of units in the last place of correctly rounded, which is about what a platform `sin` gives you.
|
|
6
|
-
* What they are is *reproducible*: ECMAScript declines to specify `sin`, `cos`, `exp`, `acos` and
|
|
7
|
-
* eighteen more, so two engines may differ by an ulp, and an ulp is enough to make two peers running
|
|
8
|
-
* the same simulation disagree — first invisibly, then completely.
|
|
9
|
-
*
|
|
10
|
-
* `scripts/determinism.mjs` is the gate that refuses the unspecified ones inside the simulation set
|
|
11
|
-
* and names the twenty-two. Its header carries the other half of the argument: `+ - * /` are IEEE
|
|
12
|
-
* 754 operations by specification, JavaScript permits no fused-multiply-add contraction, and
|
|
13
|
-
* `Math.sqrt` is required correctly rounded and is *not* on that list. **So everything below uses
|
|
14
|
-
* only those five operations**, which is the whole design: reproducibility by construction rather
|
|
15
|
-
* than by hoping two engines chose the same algorithm.
|
|
16
|
-
*
|
|
17
|
-
* ---
|
|
18
|
-
*
|
|
19
|
-
* ## What is here, and what is deliberately not
|
|
20
|
-
*
|
|
21
|
-
* `exactSin`, `exactCos`, `exactExp`, `exactAcos` and `exactLog`. Five, because five is what the
|
|
22
|
-
* engine and its first consumer actually reach for: the terrain binding's slope angle needs `acos`,
|
|
23
|
-
* a lockstep fixture rotating anything needs `sin` and `cos`, exponential decay needs `exp`, and a
|
|
24
|
-
* detector's box prior is a logit of the patch grid, which needs `log`.
|
|
25
|
-
*
|
|
26
|
-
* **`atan2` is absent.** It is the obvious fifth and nothing here needs one: `shape.ts` sorts by a
|
|
27
|
-
* comparison key computed from two in-plane axes rather than by an angle, and `joints.ts` compares
|
|
28
|
-
* a quaternion component against a half-angle's sine. *Reversed by* a site that genuinely needs a
|
|
29
|
-
* signed angle from two components, at which point it arrives with its own golden vectors.
|
|
30
|
-
*
|
|
31
|
-
* ## Nothing in core imports these
|
|
32
|
-
*
|
|
33
|
-
* Deliberately. `core-only` is the one size figure in this repository that every consumer pays, and
|
|
34
|
-
* a module reachable from `createRenderer` is in it whether anybody calls it or not. These are
|
|
35
|
-
* reached by the script bindings and by consumers who ask for them, so tree-shaking keeps them out
|
|
36
|
-
* of a bundle that does not, which is measured rather than assumed.
|
|
37
|
-
*
|
|
38
|
-
* ## The coefficients
|
|
39
|
-
*
|
|
40
|
-
* The polynomial and rational coefficients are fdlibm's, which is the ancestor of most platform
|
|
41
|
-
* libms and is public domain. They are written as literals: **a literal is the same number on
|
|
42
|
-
* every engine, which is the only property being bought.** Their provenance matters less than their
|
|
43
|
-
* fixity — a coefficient somebody re-derived to one more digit is a different function, and
|
|
44
|
-
* `exact.test.ts`'s golden bit patterns are what would catch that.
|
|
45
|
-
*/
|
|
46
|
-
|
|
47
|
-
/*
|
|
48
|
-
* π/2 in four pieces, most significant first, so a large multiple of it can be removed without
|
|
49
|
-
* losing the small remainder in the subtraction.
|
|
50
|
-
*
|
|
51
|
-
* **Two pieces are not enough and the measurement says so**: at an angle of 740 radians a two-part
|
|
52
|
-
* reduction leaves `sin` and `cos` 18.5 ulps out, because `k * PIO2_1` needs more than 53 bits once
|
|
53
|
-
* `k` grows. Three brings it under two ulps for the cost of two multiplies.
|
|
54
|
-
*
|
|
55
|
-
* **`PIO2_TAIL` and `PIO2_TAIL_LO` are one number in two halves, not two successive corrections.**
|
|
56
|
-
* fdlibm carries a fourth constant, `pio2_1t`, which is the tail for its *single*-iteration path;
|
|
57
|
-
* `pio2_2` is the same tail rounded differently, with `pio2_2t` as its own tail, and the two paths
|
|
58
|
-
* are alternatives. Refining the first with the second is not more accurate, it is wrong: it
|
|
59
|
-
* subtracts the tail twice and took `sin` to 2.2e11 ulps out, which is how this comment came to be
|
|
60
|
-
* here.
|
|
61
|
-
*/
|
|
62
|
-
const PIO2_1 = 1.5707963267341256;
|
|
63
|
-
const PIO2_TAIL = 6.077100506303966e-11;
|
|
64
|
-
const PIO2_TAIL_LO = 2.0222662487959506e-21;
|
|
65
|
-
const TWO_OVER_PI = 0.6366197723675814;
|
|
66
|
-
|
|
67
|
-
const HALF_PI = 1.5707963267948966;
|
|
68
|
-
const PI = 3.141592653589793;
|
|
69
|
-
|
|
70
|
-
/* fdlibm's `__kernel_sin` coefficients. */
|
|
71
|
-
const S1 = -1.6666666666666632e-1;
|
|
72
|
-
const S2 = 8.33333333332249e-3;
|
|
73
|
-
const S3 = -1.984126982985795e-4;
|
|
74
|
-
const S4 = 2.7557313707070068e-6;
|
|
75
|
-
const S5 = -2.5050760253406863e-8;
|
|
76
|
-
const S6 = 1.5896909952115501e-10;
|
|
77
|
-
|
|
78
|
-
/* fdlibm's `__kernel_cos` coefficients. */
|
|
79
|
-
const C1 = 4.1666666666666602e-2;
|
|
80
|
-
const C2 = -1.388888888887411e-3;
|
|
81
|
-
const C3 = 2.480158728947673e-5;
|
|
82
|
-
const C4 = -2.7557314351390663e-7;
|
|
83
|
-
const C5 = 2.0875723212981748e-9;
|
|
84
|
-
const C6 = -1.1359647557788195e-11;
|
|
85
|
-
|
|
86
|
-
/* fdlibm's `asin` rational, numerator then denominator. */
|
|
87
|
-
const P0 = 1.6666666666666666e-1;
|
|
88
|
-
const P1 = -3.2556581862240092e-1;
|
|
89
|
-
const P2 = 2.0121253213486293e-1;
|
|
90
|
-
const P3 = -4.0055534500679411e-2;
|
|
91
|
-
const P4 = 7.9153499428981453e-4;
|
|
92
|
-
const P5 = 3.4793310759602117e-5;
|
|
93
|
-
const Q1 = -2.4033949117344142;
|
|
94
|
-
const Q2 = 2.0209457602335057;
|
|
95
|
-
const Q3 = -6.8828397160545329e-1;
|
|
96
|
-
const Q4 = 7.7038150555901935e-2;
|
|
97
|
-
|
|
98
|
-
/** ln 2, split for the same reason π/2 is. */
|
|
99
|
-
const LN2_HI = 0.6931471803691238;
|
|
100
|
-
const LN2_LO = 1.9082149292705877e-10;
|
|
101
|
-
const ONE_OVER_LN2 = 1.4426950408889634;
|
|
102
|
-
|
|
103
|
-
/** 2^(2^i), for i = 0 to 9. Every one is exact, so a product of them is exact. */
|
|
104
|
-
const POW2 = [
|
|
105
|
-
2, 4, 16, 256, 65536, 4294967296, 1.8446744073709552e19, 3.402823669209385e38,
|
|
106
|
-
1.157920892373162e77, 1.3407807929942597e154,
|
|
107
|
-
];
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Two to an integer power, by binary decomposition of the exponent.
|
|
111
|
-
*
|
|
112
|
-
* Multiplication by a power of two is exact in IEEE 754, so this is exact wherever it does not
|
|
113
|
-
* overflow — which is what makes it a legitimate substitute for the `Math.pow` a range reduction
|
|
114
|
-
* would otherwise reach for.
|
|
115
|
-
*
|
|
116
|
-
* A large negative exponent lands on zero instead of a subnormal, because the reciprocal is taken
|
|
117
|
-
* after the product overflows. That is `exp` underflowing to zero, which is where it was going.
|
|
118
|
-
*/
|
|
119
|
-
function pow2(exponent: number): number {
|
|
120
|
-
let remaining = exponent < 0 ? -exponent : exponent;
|
|
121
|
-
let result = 1;
|
|
122
|
-
let index = 0;
|
|
123
|
-
while (remaining > 0 && index < POW2.length) {
|
|
124
|
-
if ((remaining & 1) === 1) result *= POW2[index] as number;
|
|
125
|
-
remaining >>= 1;
|
|
126
|
-
index += 1;
|
|
127
|
-
}
|
|
128
|
-
return exponent < 0 ? 1 / result : result;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/** sin on [-π/4, π/4]. */
|
|
132
|
-
function sinKernel(x: number): number {
|
|
133
|
-
const z = x * x;
|
|
134
|
-
const poly = S1 + z * (S2 + z * (S3 + z * (S4 + z * (S5 + z * S6))));
|
|
135
|
-
return x + x * z * poly;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/** cos on [-π/4, π/4]. */
|
|
139
|
-
function cosKernel(x: number): number {
|
|
140
|
-
const z = x * x;
|
|
141
|
-
const poly = C1 + z * (C2 + z * (C3 + z * (C4 + z * (C5 + z * C6))));
|
|
142
|
-
return 1 - 0.5 * z + z * z * poly;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Fold an angle into [-π/4, π/4] and say which quadrant it came from.
|
|
147
|
-
*
|
|
148
|
-
* Cody-Waite: the multiple of π/2 is removed in pieces, so the subtraction that produces a small
|
|
149
|
-
* remainder from two large numbers does not lose the bits it is supposed to keep. One-piece
|
|
150
|
-
* reduction is accurate to about 1e-8 at an angle of a thousand radians, which for a simulation
|
|
151
|
-
* that accumulates rotation is the difference between an object facing forward and facing sideways
|
|
152
|
-
* after a few minutes.
|
|
153
|
-
*/
|
|
154
|
-
function reduce(x: number): { r: number; quadrant: number } {
|
|
155
|
-
const k = Math.round(x * TWO_OVER_PI);
|
|
156
|
-
|
|
157
|
-
/* The leading piece, whose product with `k` is exact for every `k` a simulation reaches. */
|
|
158
|
-
const head = x - k * PIO2_1;
|
|
159
|
-
|
|
160
|
-
/*
|
|
161
|
-
* The tail, in two halves. `head - tail` loses the bits below its own last place, and
|
|
162
|
-
* `PIO2_TAIL_LO - (head - r - tail)` is exactly those bits recovered — the same
|
|
163
|
-
* subtract-and-recover fdlibm uses on its two-iteration path.
|
|
164
|
-
*/
|
|
165
|
-
const tail = k * PIO2_TAIL;
|
|
166
|
-
let r = head - tail;
|
|
167
|
-
const lost = k * PIO2_TAIL_LO - (head - r - tail);
|
|
168
|
-
r = r - lost;
|
|
169
|
-
|
|
170
|
-
return { r, quadrant: ((k % 4) + 4) % 4 };
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/** `Math.sin`, reproducibly. NaN in, NaN out; an infinity answers NaN, as `Math.sin` does. */
|
|
174
|
-
export function exactSin(x: number): number {
|
|
175
|
-
if (!Number.isFinite(x)) return Number.NaN;
|
|
176
|
-
const { r, quadrant } = reduce(x);
|
|
177
|
-
switch (quadrant) {
|
|
178
|
-
case 0:
|
|
179
|
-
return sinKernel(r);
|
|
180
|
-
case 1:
|
|
181
|
-
return cosKernel(r);
|
|
182
|
-
case 2:
|
|
183
|
-
return -sinKernel(r);
|
|
184
|
-
default:
|
|
185
|
-
return -cosKernel(r);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/** `Math.cos`, reproducibly. */
|
|
190
|
-
export function exactCos(x: number): number {
|
|
191
|
-
if (!Number.isFinite(x)) return Number.NaN;
|
|
192
|
-
const { r, quadrant } = reduce(x);
|
|
193
|
-
switch (quadrant) {
|
|
194
|
-
case 0:
|
|
195
|
-
return cosKernel(r);
|
|
196
|
-
case 1:
|
|
197
|
-
return -sinKernel(r);
|
|
198
|
-
case 2:
|
|
199
|
-
return -cosKernel(r);
|
|
200
|
-
default:
|
|
201
|
-
return sinKernel(r);
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* `Math.exp`, reproducibly.
|
|
207
|
-
*
|
|
208
|
-
* Reduce by a multiple of ln 2 into [-ln2/2, ln2/2], sum the Taylor series there, and scale by a
|
|
209
|
-
* power of two. **A degree-14 series and not a shorter minimax**, because on that interval the
|
|
210
|
-
* fifteenth term is about 4e-20 — below the precision of a double — so the series is exact to the
|
|
211
|
-
* representation and there is nothing a fitted polynomial would buy.
|
|
212
|
-
*/
|
|
213
|
-
export function exactExp(x: number): number {
|
|
214
|
-
if (Number.isNaN(x)) return Number.NaN;
|
|
215
|
-
if (x === Number.POSITIVE_INFINITY) return Number.POSITIVE_INFINITY;
|
|
216
|
-
if (x === Number.NEGATIVE_INFINITY) return 0;
|
|
217
|
-
if (x > 709.782712893384) return Number.POSITIVE_INFINITY;
|
|
218
|
-
if (x < -745.1332191019411) return 0;
|
|
219
|
-
|
|
220
|
-
const k = Math.round(x * ONE_OVER_LN2);
|
|
221
|
-
const r = x - k * LN2_HI - k * LN2_LO;
|
|
222
|
-
|
|
223
|
-
/* Horner over 1/n!, highest term first. */
|
|
224
|
-
let sum = 1 / 87178291200; // 1/14!
|
|
225
|
-
sum = 1 / 6227020800 + r * sum; // 1/13!
|
|
226
|
-
sum = 1 / 479001600 + r * sum; // 1/12!
|
|
227
|
-
sum = 1 / 39916800 + r * sum; // 1/11!
|
|
228
|
-
sum = 1 / 3628800 + r * sum; // 1/10!
|
|
229
|
-
sum = 1 / 362880 + r * sum; // 1/9!
|
|
230
|
-
sum = 1 / 40320 + r * sum; // 1/8!
|
|
231
|
-
sum = 1 / 5040 + r * sum; // 1/7!
|
|
232
|
-
sum = 1 / 720 + r * sum; // 1/6!
|
|
233
|
-
sum = 1 / 120 + r * sum; // 1/5!
|
|
234
|
-
sum = 1 / 24 + r * sum; // 1/4!
|
|
235
|
-
sum = 1 / 6 + r * sum; // 1/3!
|
|
236
|
-
sum = 0.5 + r * sum;
|
|
237
|
-
sum = 1 + r * sum;
|
|
238
|
-
sum = 1 + r * sum;
|
|
239
|
-
|
|
240
|
-
return sum * pow2(k);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/* fdlibm's `log` polynomial in s², for log(1 + f) around f = 0 by way of s = f / (2 + f). */
|
|
244
|
-
const LG1 = 6.66666666666673513e-1;
|
|
245
|
-
const LG2 = 3.999999999940941908e-1;
|
|
246
|
-
const LG3 = 2.857142874366239149e-1;
|
|
247
|
-
const LG4 = 2.222219843214978396e-1;
|
|
248
|
-
const LG5 = 1.818357216161805012e-1;
|
|
249
|
-
const LG6 = 1.531383769920937332e-1;
|
|
250
|
-
const LG7 = 1.479819860511658591e-1;
|
|
251
|
-
const TWO54 = 1.8014398509481984e16;
|
|
252
|
-
const SMALLEST_NORMAL = 2.2250738585072014e-308;
|
|
253
|
-
|
|
254
|
-
/* A double's two words, for reading and setting an exponent; one view, reused. */
|
|
255
|
-
const words = new DataView(new ArrayBuffer(8));
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* `Math.log`, reproducibly: fdlibm's algorithm, which is also V8's.
|
|
259
|
-
*
|
|
260
|
-
* Take the power of two out as `k` and leave a significand in [√2/2, √2), so that `f = m - 1` is
|
|
261
|
-
* small either side of zero; then log(1 + f) = f - f²/2 + s·(f²/2 + R(s²)) with s = f/(2 + f), and
|
|
262
|
-
* `k·ln 2` added back in two parts so the large part loses nothing. The exponent is read and the
|
|
263
|
-
* significand rescaled through the double's own words — integer operations, not transcendentals.
|
|
264
|
-
*/
|
|
265
|
-
export function exactLog(x: number): number {
|
|
266
|
-
if (Number.isNaN(x) || x < 0) return Number.NaN;
|
|
267
|
-
if (x === 0) return Number.NEGATIVE_INFINITY;
|
|
268
|
-
if (x === Number.POSITIVE_INFINITY) return x;
|
|
269
|
-
|
|
270
|
-
let k = 0;
|
|
271
|
-
let value = x;
|
|
272
|
-
if (value < SMALLEST_NORMAL) {
|
|
273
|
-
k = -54;
|
|
274
|
-
value *= TWO54;
|
|
275
|
-
}
|
|
276
|
-
words.setFloat64(0, value);
|
|
277
|
-
let hx = words.getUint32(0);
|
|
278
|
-
k += (hx >>> 20) - 1023;
|
|
279
|
-
hx &= 0x000fffff;
|
|
280
|
-
/* Keep the significand at or above √2/2: past √2, halve it and count one more power of two. */
|
|
281
|
-
const i = (hx + 0x95f64) & 0x100000;
|
|
282
|
-
words.setUint32(0, hx | (i ^ 0x3ff00000));
|
|
283
|
-
k += i >>> 20;
|
|
284
|
-
const f = words.getFloat64(0) - 1;
|
|
285
|
-
|
|
286
|
-
if ((0x000fffff & (2 + hx)) < 3) {
|
|
287
|
-
/* |f| < 2^-20: two terms of the series are the whole answer. */
|
|
288
|
-
if (f === 0) return k === 0 ? 0 : k * LN2_HI + k * LN2_LO;
|
|
289
|
-
const r = f * f * (0.5 - 0.3333333333333333 * f);
|
|
290
|
-
return k === 0 ? f - r : k * LN2_HI - (r - k * LN2_LO - f);
|
|
291
|
-
}
|
|
292
|
-
const s = f / (2 + f);
|
|
293
|
-
const z = s * s;
|
|
294
|
-
const w = z * z;
|
|
295
|
-
const t1 = w * (LG2 + w * (LG4 + w * LG6));
|
|
296
|
-
const t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7)));
|
|
297
|
-
const r = t2 + t1;
|
|
298
|
-
/* Far enough from one that f²/2 is worth carrying apart from f. */
|
|
299
|
-
if (((hx - 0x6147a) | (0x6b851 - hx)) > 0) {
|
|
300
|
-
const half = 0.5 * f * f;
|
|
301
|
-
return k === 0
|
|
302
|
-
? f - (half - s * (half + r))
|
|
303
|
-
: k * LN2_HI - (half - (s * (half + r) + k * LN2_LO) - f);
|
|
304
|
-
}
|
|
305
|
-
return k === 0 ? f - s * (f - r) : k * LN2_HI - (s * (f - r) - k * LN2_LO - f);
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
/** fdlibm's `asin` rational on `z = x²`, valid where `z` is small. */
|
|
309
|
-
function asinRational(z: number): number {
|
|
310
|
-
const numerator = z * (P0 + z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * P5)))));
|
|
311
|
-
const denominator = 1 + z * (Q1 + z * (Q2 + z * (Q3 + z * Q4)));
|
|
312
|
-
return numerator / denominator;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* `Math.acos`, reproducibly. Outside [-1, 1] this answers NaN, as `Math.acos` does.
|
|
317
|
-
*
|
|
318
|
-
* Three branches rather than one, and the split at ±0.5 is the reason it is accurate near the ends:
|
|
319
|
-
* `acos` has infinite derivative at ±1, so a polynomial in `x` loses its footing there. Substituting
|
|
320
|
-
* `s = sqrt((1 ∓ x)/2)` moves the awkward point to zero, where a polynomial is comfortable — which
|
|
321
|
-
* is also why `sqrt` being exactly rounded matters here rather than being a convenience.
|
|
322
|
-
*/
|
|
323
|
-
export function exactAcos(x: number): number {
|
|
324
|
-
if (Number.isNaN(x) || x > 1 || x < -1) return Number.NaN;
|
|
325
|
-
if (x === 1) return 0;
|
|
326
|
-
if (x === -1) return PI;
|
|
327
|
-
|
|
328
|
-
if (x >= 0.5) {
|
|
329
|
-
const z = (1 - x) / 2;
|
|
330
|
-
const s = Math.sqrt(z);
|
|
331
|
-
return 2 * (s + s * asinRational(z));
|
|
332
|
-
}
|
|
333
|
-
if (x <= -0.5) {
|
|
334
|
-
const z = (1 + x) / 2;
|
|
335
|
-
const s = Math.sqrt(z);
|
|
336
|
-
return PI - 2 * (s + s * asinRational(z));
|
|
337
|
-
}
|
|
338
|
-
const z = x * x;
|
|
339
|
-
return HALF_PI - (x + x * asinRational(z));
|
|
340
|
-
}
|