goscript 0.0.33 → 0.0.35
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/compiler/analysis.go +30 -22
- package/compiler/analysis_test.go +14 -0
- package/compiler/assignment.go +45 -7
- package/compiler/builtin_test.go +2 -0
- package/compiler/compiler.go +15 -89
- package/compiler/compiler_test.go +0 -53
- package/compiler/composite-lit.go +60 -17
- package/compiler/decl.go +1 -1
- package/compiler/expr-call.go +347 -30
- package/compiler/expr-selector.go +28 -2
- package/compiler/expr.go +79 -38
- package/compiler/lit.go +112 -3
- package/compiler/primitive.go +6 -6
- package/compiler/protobuf.go +0 -5
- package/compiler/sanitize.go +101 -0
- package/compiler/spec-value.go +25 -18
- package/compiler/stmt-assign.go +128 -91
- package/compiler/stmt-for.go +78 -1
- package/compiler/stmt-range.go +333 -461
- package/compiler/stmt.go +46 -9
- package/compiler/type.go +14 -11
- package/dist/gs/builtin/builtin.d.ts +8 -0
- package/dist/gs/builtin/builtin.js +31 -0
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/builtin/map.d.ts +4 -4
- package/dist/gs/builtin/map.js +12 -6
- package/dist/gs/builtin/map.js.map +1 -1
- package/dist/gs/builtin/slice.d.ts +14 -8
- package/dist/gs/builtin/slice.js +131 -31
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/github.com/pkg/errors/errors.d.ts +13 -0
- package/dist/gs/github.com/pkg/errors/errors.js +232 -0
- package/dist/gs/github.com/pkg/errors/errors.js.map +1 -0
- package/dist/gs/github.com/pkg/errors/go113.d.ts +4 -0
- package/dist/gs/github.com/pkg/errors/go113.js +34 -0
- package/dist/gs/github.com/pkg/errors/go113.js.map +1 -0
- package/dist/gs/github.com/pkg/errors/index.d.ts +3 -0
- package/dist/gs/github.com/pkg/errors/index.js +4 -0
- package/dist/gs/github.com/pkg/errors/index.js.map +1 -0
- package/dist/gs/github.com/pkg/errors/stack.d.ts +32 -0
- package/dist/gs/github.com/pkg/errors/stack.js +111 -0
- package/dist/gs/github.com/pkg/errors/stack.js.map +1 -0
- package/dist/gs/maps/index.d.ts +2 -0
- package/dist/gs/maps/index.js +3 -0
- package/dist/gs/maps/index.js.map +1 -0
- package/dist/gs/maps/iter.d.ts +7 -0
- package/dist/gs/maps/iter.gs.d.ts +7 -0
- package/dist/gs/maps/iter.gs.js +65 -0
- package/dist/gs/maps/iter.gs.js.map +1 -0
- package/dist/gs/maps/iter.js +57 -0
- package/dist/gs/maps/iter.js.map +1 -0
- package/dist/gs/maps/maps.d.ts +7 -0
- package/dist/gs/maps/maps.gs.d.ts +7 -0
- package/dist/gs/maps/maps.gs.js +79 -0
- package/dist/gs/maps/maps.gs.js.map +1 -0
- package/dist/gs/maps/maps.js +67 -0
- package/dist/gs/maps/maps.js.map +1 -0
- package/dist/gs/math/abs.gs.d.ts +1 -0
- package/dist/gs/math/abs.gs.js +10 -0
- package/dist/gs/math/abs.gs.js.map +1 -0
- package/dist/gs/math/acosh.gs.d.ts +2 -0
- package/dist/gs/math/acosh.gs.js +14 -0
- package/dist/gs/math/acosh.gs.js.map +1 -0
- package/dist/gs/math/asin.gs.d.ts +4 -0
- package/dist/gs/math/asin.gs.js +24 -0
- package/dist/gs/math/asin.gs.js.map +1 -0
- package/dist/gs/math/asinh.gs.d.ts +2 -0
- package/dist/gs/math/asinh.gs.js +14 -0
- package/dist/gs/math/asinh.gs.js.map +1 -0
- package/dist/gs/math/atan.gs.d.ts +4 -0
- package/dist/gs/math/atan.gs.js +22 -0
- package/dist/gs/math/atan.gs.js.map +1 -0
- package/dist/gs/math/atan2.gs.d.ts +2 -0
- package/dist/gs/math/atan2.gs.js +30 -0
- package/dist/gs/math/atan2.gs.js.map +1 -0
- package/dist/gs/math/atanh.gs.d.ts +2 -0
- package/dist/gs/math/atanh.gs.js +16 -0
- package/dist/gs/math/atanh.gs.js.map +1 -0
- package/dist/gs/math/bits.gs.d.ts +5 -0
- package/dist/gs/math/bits.gs.js +46 -0
- package/dist/gs/math/bits.gs.js.map +1 -0
- package/dist/gs/math/cbrt.gs.d.ts +2 -0
- package/dist/gs/math/cbrt.gs.js +14 -0
- package/dist/gs/math/cbrt.gs.js.map +1 -0
- package/dist/gs/math/const.gs.d.ts +30 -0
- package/dist/gs/math/const.gs.js +61 -0
- package/dist/gs/math/const.gs.js.map +1 -0
- package/dist/gs/math/copysign.gs.d.ts +1 -0
- package/dist/gs/math/copysign.gs.js +20 -0
- package/dist/gs/math/copysign.gs.js.map +1 -0
- package/dist/gs/math/dim.gs.d.ts +5 -0
- package/dist/gs/math/dim.gs.js +69 -0
- package/dist/gs/math/dim.gs.js.map +1 -0
- package/dist/gs/math/erf.gs.d.ts +4 -0
- package/dist/gs/math/erf.gs.js +336 -0
- package/dist/gs/math/erf.gs.js.map +1 -0
- package/dist/gs/math/erfinv.gs.d.ts +2 -0
- package/dist/gs/math/erfinv.gs.js +118 -0
- package/dist/gs/math/erfinv.gs.js.map +1 -0
- package/dist/gs/math/exp.gs.d.ts +5 -0
- package/dist/gs/math/exp.gs.js +30 -0
- package/dist/gs/math/exp.gs.js.map +1 -0
- package/dist/gs/math/expm1.gs.d.ts +2 -0
- package/dist/gs/math/expm1.gs.js +17 -0
- package/dist/gs/math/expm1.gs.js.map +1 -0
- package/dist/gs/math/floor.gs.d.ts +8 -0
- package/dist/gs/math/floor.gs.js +75 -0
- package/dist/gs/math/floor.gs.js.map +1 -0
- package/dist/gs/math/fma.gs.d.ts +1 -0
- package/dist/gs/math/fma.gs.js +8 -0
- package/dist/gs/math/fma.gs.js.map +1 -0
- package/dist/gs/math/frexp.gs.d.ts +2 -0
- package/dist/gs/math/frexp.gs.js +28 -0
- package/dist/gs/math/frexp.gs.js.map +1 -0
- package/dist/gs/math/gamma.gs.d.ts +3 -0
- package/dist/gs/math/gamma.gs.js +149 -0
- package/dist/gs/math/gamma.gs.js.map +1 -0
- package/dist/gs/math/hypot.gs.d.ts +2 -0
- package/dist/gs/math/hypot.gs.js +16 -0
- package/dist/gs/math/hypot.gs.js.map +1 -0
- package/dist/gs/math/index.d.ts +44 -0
- package/dist/gs/math/index.js +45 -0
- package/dist/gs/math/index.js.map +1 -0
- package/dist/gs/math/j0.gs.d.ts +4 -0
- package/dist/gs/math/j0.gs.js +228 -0
- package/dist/gs/math/j0.gs.js.map +1 -0
- package/dist/gs/math/j1.gs.d.ts +4 -0
- package/dist/gs/math/j1.gs.js +211 -0
- package/dist/gs/math/j1.gs.js.map +1 -0
- package/dist/gs/math/jn.gs.d.ts +2 -0
- package/dist/gs/math/jn.gs.js +412 -0
- package/dist/gs/math/jn.gs.js.map +1 -0
- package/dist/gs/math/ldexp.gs.d.ts +2 -0
- package/dist/gs/math/ldexp.gs.js +20 -0
- package/dist/gs/math/ldexp.gs.js.map +1 -0
- package/dist/gs/math/lgamma.gs.d.ts +2 -0
- package/dist/gs/math/lgamma.gs.js +243 -0
- package/dist/gs/math/lgamma.gs.js.map +1 -0
- package/dist/gs/math/log.gs.d.ts +2 -0
- package/dist/gs/math/log.gs.js +16 -0
- package/dist/gs/math/log.gs.js.map +1 -0
- package/dist/gs/math/log10.gs.d.ts +4 -0
- package/dist/gs/math/log10.gs.js +17 -0
- package/dist/gs/math/log10.gs.js.map +1 -0
- package/dist/gs/math/log1p.gs.d.ts +2 -0
- package/dist/gs/math/log1p.gs.js +17 -0
- package/dist/gs/math/log1p.gs.js.map +1 -0
- package/dist/gs/math/logb.gs.d.ts +3 -0
- package/dist/gs/math/logb.gs.js +43 -0
- package/dist/gs/math/logb.gs.js.map +1 -0
- package/dist/gs/math/mod.gs.d.ts +2 -0
- package/dist/gs/math/mod.gs.js +26 -0
- package/dist/gs/math/mod.gs.js.map +1 -0
- package/dist/gs/math/modf.gs.d.ts +2 -0
- package/dist/gs/math/modf.gs.js +24 -0
- package/dist/gs/math/modf.gs.js.map +1 -0
- package/dist/gs/math/nextafter.gs.d.ts +2 -0
- package/dist/gs/math/nextafter.gs.js +66 -0
- package/dist/gs/math/nextafter.gs.js.map +1 -0
- package/dist/gs/math/pow.gs.d.ts +3 -0
- package/dist/gs/math/pow.gs.js +40 -0
- package/dist/gs/math/pow.gs.js.map +1 -0
- package/dist/gs/math/pow10.gs.d.ts +1 -0
- package/dist/gs/math/pow10.gs.js +14 -0
- package/dist/gs/math/pow10.gs.js.map +1 -0
- package/dist/gs/math/remainder.gs.d.ts +2 -0
- package/dist/gs/math/remainder.gs.js +25 -0
- package/dist/gs/math/remainder.gs.js.map +1 -0
- package/dist/gs/math/signbit.gs.d.ts +1 -0
- package/dist/gs/math/signbit.gs.js +5 -0
- package/dist/gs/math/signbit.gs.js.map +1 -0
- package/dist/gs/math/sin.gs.d.ts +4 -0
- package/dist/gs/math/sin.gs.js +29 -0
- package/dist/gs/math/sin.gs.js.map +1 -0
- package/dist/gs/math/sincos.gs.d.ts +1 -0
- package/dist/gs/math/sincos.gs.js +11 -0
- package/dist/gs/math/sincos.gs.js.map +1 -0
- package/dist/gs/math/sinh.gs.d.ts +4 -0
- package/dist/gs/math/sinh.gs.js +27 -0
- package/dist/gs/math/sinh.gs.js.map +1 -0
- package/dist/gs/math/sqrt.gs.d.ts +2 -0
- package/dist/gs/math/sqrt.gs.js +15 -0
- package/dist/gs/math/sqrt.gs.js.map +1 -0
- package/dist/gs/math/tan.gs.d.ts +2 -0
- package/dist/gs/math/tan.gs.js +17 -0
- package/dist/gs/math/tan.gs.js.map +1 -0
- package/dist/gs/math/tanh.gs.d.ts +2 -0
- package/dist/gs/math/tanh.gs.js +17 -0
- package/dist/gs/math/tanh.gs.js.map +1 -0
- package/dist/gs/math/trig_reduce.gs.d.ts +1 -0
- package/dist/gs/math/trig_reduce.gs.js +62 -0
- package/dist/gs/math/trig_reduce.gs.js.map +1 -0
- package/dist/gs/math/unsafe.gs.d.ts +4 -0
- package/dist/gs/math/unsafe.gs.js +47 -0
- package/dist/gs/math/unsafe.gs.js.map +1 -0
- package/dist/gs/slices/slices.d.ts +6 -0
- package/dist/gs/slices/slices.js +8 -0
- package/dist/gs/slices/slices.js.map +1 -1
- package/dist/gs/strconv/atob.gs.d.ts +4 -0
- package/dist/gs/strconv/atob.gs.js +42 -0
- package/dist/gs/strconv/atob.gs.js.map +1 -0
- package/dist/gs/strconv/atof.gs.d.ts +2 -0
- package/dist/gs/strconv/atof.gs.js +51 -0
- package/dist/gs/strconv/atof.gs.js.map +1 -0
- package/dist/gs/strconv/atoi.gs.d.ts +33 -0
- package/dist/gs/strconv/atoi.gs.js +200 -0
- package/dist/gs/strconv/atoi.gs.js.map +1 -0
- package/dist/gs/strconv/doc.gs.d.ts +1 -0
- package/dist/gs/strconv/doc.gs.js +2 -0
- package/dist/gs/strconv/doc.gs.js.map +1 -0
- package/dist/gs/strconv/ftoa.gs.d.ts +3 -0
- package/dist/gs/strconv/ftoa.gs.js +58 -0
- package/dist/gs/strconv/ftoa.gs.js.map +1 -0
- package/dist/gs/strconv/index.d.ts +6 -0
- package/dist/gs/strconv/index.js +7 -0
- package/dist/gs/strconv/index.js.map +1 -0
- package/dist/gs/strconv/itoa.gs.d.ts +6 -0
- package/dist/gs/strconv/itoa.gs.js +37 -0
- package/dist/gs/strconv/itoa.gs.js.map +1 -0
- package/dist/gs/strconv/quote.gs.d.ts +19 -0
- package/dist/gs/strconv/quote.gs.js +217 -0
- package/dist/gs/strconv/quote.gs.js.map +1 -0
- package/dist/gs/strings/index.d.ts +3 -0
- package/dist/gs/strings/index.js +4 -0
- package/dist/gs/strings/index.js.map +1 -1
- package/dist/gs/strings/replace.d.ts +0 -74
- package/dist/gs/strings/replace.js +6 -204
- package/dist/gs/strings/replace.js.map +1 -1
- package/dist/gs/strings/search.d.ts +0 -1
- package/dist/gs/strings/search.js +0 -21
- package/dist/gs/strings/search.js.map +1 -1
- package/gs/builtin/builtin.ts +40 -0
- package/gs/builtin/map.ts +12 -7
- package/gs/builtin/slice.ts +174 -34
- package/gs/github.com/pkg/errors/errors.ts +307 -0
- package/gs/github.com/pkg/errors/go113.ts +39 -0
- package/gs/github.com/pkg/errors/index.ts +3 -0
- package/gs/github.com/pkg/errors/stack.ts +127 -0
- package/gs/maps/index.ts +2 -0
- package/gs/maps/iter.ts +67 -0
- package/gs/maps/maps.ts +89 -0
- package/gs/math/TODO.md +156 -0
- package/gs/math/abs.gs.test.ts +29 -0
- package/gs/math/abs.gs.ts +13 -0
- package/gs/math/acosh.gs.test.ts +39 -0
- package/gs/math/acosh.gs.ts +21 -0
- package/gs/math/asin.gs.test.ts +66 -0
- package/gs/math/asin.gs.ts +27 -0
- package/gs/math/asinh.gs.test.ts +37 -0
- package/gs/math/asinh.gs.ts +21 -0
- package/gs/math/atan.gs.test.ts +49 -0
- package/gs/math/atan.gs.ts +27 -0
- package/gs/math/atan2.gs.test.ts +55 -0
- package/gs/math/atan2.gs.ts +37 -0
- package/gs/math/atanh.gs.test.ts +47 -0
- package/gs/math/atanh.gs.ts +21 -0
- package/gs/math/bits.gs.test.ts +88 -0
- package/gs/math/bits.gs.ts +61 -0
- package/gs/math/cbrt.gs.test.ts +57 -0
- package/gs/math/cbrt.gs.ts +20 -0
- package/gs/math/const.gs.test.ts +54 -0
- package/gs/math/const.gs.ts +93 -0
- package/gs/math/copysign.gs.test.ts +44 -0
- package/gs/math/copysign.gs.ts +27 -0
- package/gs/math/dim.gs.test.ts +102 -0
- package/gs/math/dim.gs.ts +84 -0
- package/gs/math/erf.gs.test.ts +92 -0
- package/gs/math/erf.gs.ts +409 -0
- package/gs/math/erfinv.gs.test.ts +104 -0
- package/gs/math/erfinv.gs.ts +169 -0
- package/gs/math/exp.gs.test.ts +82 -0
- package/gs/math/exp.gs.ts +39 -0
- package/gs/math/expm1.gs.test.ts +48 -0
- package/gs/math/expm1.gs.ts +23 -0
- package/gs/math/floor.gs.test.ts +146 -0
- package/gs/math/floor.gs.ts +88 -0
- package/gs/math/fma.gs.test.ts +83 -0
- package/gs/math/fma.gs.ts +7 -0
- package/gs/math/frexp.gs.test.ts +146 -0
- package/gs/math/frexp.gs.ts +37 -0
- package/gs/math/gamma.gs.test.ts +66 -0
- package/gs/math/gamma.gs.ts +158 -0
- package/gs/math/hypot.gs.test.ts +73 -0
- package/gs/math/hypot.gs.ts +23 -0
- package/gs/math/index.ts +44 -0
- package/gs/math/j0.gs.test.ts +74 -0
- package/gs/math/j0.gs.ts +257 -0
- package/gs/math/j1.gs.test.ts +81 -0
- package/gs/math/j1.gs.ts +231 -0
- package/gs/math/jn.gs.test.ts +133 -0
- package/gs/math/jn.gs.ts +447 -0
- package/gs/math/ldexp.gs.test.ts +128 -0
- package/gs/math/ldexp.gs.ts +28 -0
- package/gs/math/lgamma.gs.test.ts +102 -0
- package/gs/math/lgamma.gs.ts +251 -0
- package/gs/math/log.gs.test.ts +40 -0
- package/gs/math/log.gs.ts +21 -0
- package/gs/math/log10.gs.test.ts +80 -0
- package/gs/math/log10.gs.ts +25 -0
- package/gs/math/log1p.gs.test.ts +55 -0
- package/gs/math/log1p.gs.ts +24 -0
- package/gs/math/logb.gs.test.ts +87 -0
- package/gs/math/logb.gs.ts +54 -0
- package/gs/math/mod.gs.test.ts +64 -0
- package/gs/math/mod.gs.ts +36 -0
- package/gs/math/modf.gs.test.ts +80 -0
- package/gs/math/modf.gs.ts +32 -0
- package/gs/math/nextafter.gs.test.ts +107 -0
- package/gs/math/nextafter.gs.ts +71 -0
- package/gs/math/pow.gs.test.ts +103 -0
- package/gs/math/pow.gs.ts +55 -0
- package/gs/math/pow10.gs.test.ts +58 -0
- package/gs/math/pow10.gs.ts +19 -0
- package/gs/math/remainder.gs.test.ts +70 -0
- package/gs/math/remainder.gs.ts +33 -0
- package/gs/math/signbit.gs.test.ts +33 -0
- package/gs/math/signbit.gs.ts +8 -0
- package/gs/math/sin.gs.test.ts +83 -0
- package/gs/math/sin.gs.ts +38 -0
- package/gs/math/sincos.gs.test.ts +91 -0
- package/gs/math/sincos.gs.ts +15 -0
- package/gs/math/sinh.gs.test.ts +66 -0
- package/gs/math/sinh.gs.ts +34 -0
- package/gs/math/sqrt.gs.test.ts +49 -0
- package/gs/math/sqrt.gs.ts +20 -0
- package/gs/math/tan.gs.test.ts +50 -0
- package/gs/math/tan.gs.ts +23 -0
- package/gs/math/tanh.gs.test.ts +52 -0
- package/gs/math/tanh.gs.ts +23 -0
- package/gs/math/trig_reduce.gs.ts +66 -0
- package/gs/math/unsafe.gs.ts +52 -0
- package/gs/slices/slices.ts +9 -0
- package/gs/strconv/atob.gs.ts +45 -0
- package/gs/strconv/atof.gs.ts +60 -0
- package/gs/strconv/atoi.gs.ts +243 -0
- package/gs/strconv/doc.gs.ts +2 -0
- package/gs/strconv/ftoa.gs.ts +66 -0
- package/gs/strconv/index.ts +6 -0
- package/gs/strconv/itoa.gs.ts +41 -0
- package/gs/strconv/quote.gs.ts +245 -0
- package/gs/strings/index.ts +4 -0
- package/gs/strings/replace.ts +9 -237
- package/gs/strings/search.ts +0 -28
- package/package.json +1 -1
- package/gs/stringslite/godoc.txt +0 -17
- package/gs/stringslite/index.ts +0 -1
- package/gs/stringslite/strings.ts +0 -82
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { FMA } from './fma.gs.js';
|
|
3
|
+
import { Inf, NaN, IsNaN, IsInf } from './bits.gs.js';
|
|
4
|
+
|
|
5
|
+
describe('FMA', () => {
|
|
6
|
+
it('should compute fused multiply-add correctly for basic cases', () => {
|
|
7
|
+
expect(FMA(2, 3, 4)).toBe(10); // 2*3 + 4 = 10
|
|
8
|
+
expect(FMA(1.5, 2, 0.5)).toBe(3.5); // 1.5*2 + 0.5 = 3.5
|
|
9
|
+
expect(FMA(0.1, 0.2, 0.3)).toBeCloseTo(0.32, 10); // 0.1*0.2 + 0.3 = 0.32
|
|
10
|
+
expect(FMA(-2, 3, 1)).toBe(-5); // -2*3 + 1 = -5
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('should handle zero values', () => {
|
|
14
|
+
expect(FMA(0, 5, 3)).toBe(3); // 0*5 + 3 = 3
|
|
15
|
+
expect(FMA(5, 0, 3)).toBe(3); // 5*0 + 3 = 3
|
|
16
|
+
expect(FMA(5, 3, 0)).toBe(15); // 5*3 + 0 = 15
|
|
17
|
+
expect(FMA(0, 0, 0)).toBe(0); // 0*0 + 0 = 0
|
|
18
|
+
expect(FMA(0, 0, 5)).toBe(5); // 0*0 + 5 = 5
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should handle negative values', () => {
|
|
22
|
+
expect(FMA(-2, -3, 4)).toBe(10); // -2*-3 + 4 = 10
|
|
23
|
+
expect(FMA(-2, 3, -4)).toBe(-10); // -2*3 + -4 = -10
|
|
24
|
+
expect(FMA(2, -3, -4)).toBe(-10); // 2*-3 + -4 = -10
|
|
25
|
+
expect(FMA(-2, -3, -4)).toBe(2); // -2*-3 + -4 = 2
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('should handle infinity cases', () => {
|
|
29
|
+
expect(FMA(Inf(1), 2, 3)).toBe(Inf(1)); // +Inf * 2 + 3 = +Inf
|
|
30
|
+
expect(FMA(2, Inf(1), 3)).toBe(Inf(1)); // 2 * +Inf + 3 = +Inf
|
|
31
|
+
expect(FMA(2, 3, Inf(1))).toBe(Inf(1)); // 2 * 3 + +Inf = +Inf
|
|
32
|
+
expect(FMA(Inf(-1), 2, 3)).toBe(Inf(-1)); // -Inf * 2 + 3 = -Inf
|
|
33
|
+
expect(FMA(Inf(1), Inf(1), 3)).toBe(Inf(1)); // +Inf * +Inf + 3 = +Inf
|
|
34
|
+
expect(FMA(Inf(-1), Inf(-1), 3)).toBe(Inf(1)); // -Inf * -Inf + 3 = +Inf
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should handle NaN cases', () => {
|
|
38
|
+
expect(IsNaN(FMA(NaN(), 2, 3))).toBe(true);
|
|
39
|
+
expect(IsNaN(FMA(2, NaN(), 3))).toBe(true);
|
|
40
|
+
expect(IsNaN(FMA(2, 3, NaN()))).toBe(true);
|
|
41
|
+
expect(IsNaN(FMA(NaN(), NaN(), NaN()))).toBe(true);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should handle special infinity and zero combinations', () => {
|
|
45
|
+
// Inf * 0 should produce NaN
|
|
46
|
+
expect(IsNaN(FMA(Inf(1), 0, 5))).toBe(true);
|
|
47
|
+
expect(IsNaN(FMA(0, Inf(1), 5))).toBe(true);
|
|
48
|
+
|
|
49
|
+
// But if the addition part is also infinity, behavior depends on implementation
|
|
50
|
+
expect(IsNaN(FMA(Inf(1), 0, Inf(1)))).toBe(true);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should handle cancellation cases', () => {
|
|
54
|
+
// Cases where x*y and z cancel out
|
|
55
|
+
expect(FMA(2, 3, -6)).toBe(0); // 2*3 + (-6) = 0
|
|
56
|
+
expect(FMA(-5, 4, 20)).toBe(0); // -5*4 + 20 = 0
|
|
57
|
+
expect(FMA(0.5, 0.2, -0.1)).toBeCloseTo(0, 10); // 0.5*0.2 + (-0.1) = 0
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should handle very large and small numbers', () => {
|
|
61
|
+
const large = 1e100;
|
|
62
|
+
const small = 1e-100;
|
|
63
|
+
|
|
64
|
+
// Relax tolerance for very large/small number calculations
|
|
65
|
+
const result1 = FMA(large, small, 1)
|
|
66
|
+
expect(result1).toBeCloseTo(2, 0); // large*small is approximately 1, so result is approximately 2
|
|
67
|
+
expect(FMA(small, small, large)).toBeCloseTo(large, 5); // small*small is negligible
|
|
68
|
+
expect(FMA(large, large, -large * large)).toBeCloseTo(0, 5); // cancellation
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('should be equivalent to x * y + z for simple cases', () => {
|
|
72
|
+
const testCases = [
|
|
73
|
+
[1, 2, 3],
|
|
74
|
+
[0.5, 0.25, 0.125],
|
|
75
|
+
[-1, 2, -3],
|
|
76
|
+
[10, 0.1, 5]
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
testCases.forEach(([x, y, z]) => {
|
|
80
|
+
expect(FMA(x, y, z)).toBeCloseTo(x * y + z, 10);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// FMA returns x * y + z, computed with only one rounding.
|
|
2
|
+
// (That is, FMA returns the fused multiply-add of x, y, and z.)
|
|
3
|
+
export function FMA(x: number, y: number, z: number): number {
|
|
4
|
+
// JavaScript doesn't have native FMA, so we use the simple implementation
|
|
5
|
+
// This may not be as precise as a true FMA but is much simpler
|
|
6
|
+
return x * y + z
|
|
7
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { Frexp, frexp } from './frexp.gs.js';
|
|
3
|
+
import { Inf, NaN as GoNaN, IsNaN } from './bits.gs.js';
|
|
4
|
+
|
|
5
|
+
describe('Frexp', () => {
|
|
6
|
+
it('should break numbers into normalized fraction and exponent', () => {
|
|
7
|
+
// Test basic cases where we can verify the math
|
|
8
|
+
let [frac, exp] = Frexp(8);
|
|
9
|
+
expect(frac).toBeCloseTo(0.5, 10);
|
|
10
|
+
expect(exp).toBe(4); // 8 = 0.5 * 2^4
|
|
11
|
+
|
|
12
|
+
[frac, exp] = Frexp(1);
|
|
13
|
+
expect(frac).toBeCloseTo(0.5, 10);
|
|
14
|
+
expect(exp).toBe(1); // 1 = 0.5 * 2^1
|
|
15
|
+
|
|
16
|
+
[frac, exp] = Frexp(2);
|
|
17
|
+
expect(frac).toBeCloseTo(0.5, 10);
|
|
18
|
+
expect(exp).toBe(2); // 2 = 0.5 * 2^2
|
|
19
|
+
|
|
20
|
+
[frac, exp] = Frexp(4);
|
|
21
|
+
expect(frac).toBeCloseTo(0.5, 10);
|
|
22
|
+
expect(exp).toBe(3); // 4 = 0.5 * 2^3
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should handle fractional numbers', () => {
|
|
26
|
+
let [frac, exp] = Frexp(0.5);
|
|
27
|
+
expect(frac).toBeCloseTo(0.5, 10);
|
|
28
|
+
expect(exp).toBe(0); // 0.5 = 0.5 * 2^0
|
|
29
|
+
|
|
30
|
+
[frac, exp] = Frexp(0.25);
|
|
31
|
+
expect(frac).toBeCloseTo(0.5, 10);
|
|
32
|
+
expect(exp).toBe(-1); // 0.25 = 0.5 * 2^-1
|
|
33
|
+
|
|
34
|
+
[frac, exp] = Frexp(0.125);
|
|
35
|
+
expect(frac).toBeCloseTo(0.5, 10);
|
|
36
|
+
expect(exp).toBe(-2); // 0.125 = 0.5 * 2^-2
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('should handle negative numbers', () => {
|
|
40
|
+
let [frac, exp] = Frexp(-8);
|
|
41
|
+
expect(frac).toBeCloseTo(-0.5, 10);
|
|
42
|
+
expect(exp).toBe(4); // -8 = -0.5 * 2^4
|
|
43
|
+
|
|
44
|
+
[frac, exp] = Frexp(-1);
|
|
45
|
+
expect(frac).toBeCloseTo(-0.5, 10);
|
|
46
|
+
expect(exp).toBe(1); // -1 = -0.5 * 2^1
|
|
47
|
+
|
|
48
|
+
[frac, exp] = Frexp(-0.5);
|
|
49
|
+
expect(frac).toBeCloseTo(-0.5, 10);
|
|
50
|
+
expect(exp).toBe(0); // -0.5 = -0.5 * 2^0
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should handle zero values', () => {
|
|
54
|
+
let [frac, exp] = Frexp(0);
|
|
55
|
+
expect(frac).toBe(0);
|
|
56
|
+
expect(exp).toBe(0);
|
|
57
|
+
|
|
58
|
+
[frac, exp] = Frexp(-0);
|
|
59
|
+
expect(frac).toBe(-0);
|
|
60
|
+
expect(exp).toBe(0);
|
|
61
|
+
expect(Object.is(frac, -0)).toBe(true); // Preserve sign of zero
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should handle infinity cases', () => {
|
|
65
|
+
let [frac, exp] = Frexp(Inf(1));
|
|
66
|
+
expect(frac).toBe(Inf(1));
|
|
67
|
+
expect(exp).toBe(0);
|
|
68
|
+
|
|
69
|
+
[frac, exp] = Frexp(Inf(-1));
|
|
70
|
+
expect(frac).toBe(Inf(-1));
|
|
71
|
+
expect(exp).toBe(0);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('should handle NaN cases', () => {
|
|
75
|
+
let [frac, _exp] = Frexp(GoNaN());
|
|
76
|
+
expect(IsNaN(frac)).toBe(true);
|
|
77
|
+
expect(_exp).toBe(0);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should satisfy the fundamental property f = frac * 2^exp', () => {
|
|
81
|
+
const testValues = [1, 2, 3, 4, 5, 8, 16, 0.5, 0.25, 0.125, 1.5, 3.14159, 100, 1000];
|
|
82
|
+
|
|
83
|
+
testValues.forEach(value => {
|
|
84
|
+
const [frac, exp] = Frexp(value);
|
|
85
|
+
const reconstructed = frac * Math.pow(2, exp);
|
|
86
|
+
expect(reconstructed).toBeCloseTo(value, 10);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// Test negative values
|
|
90
|
+
testValues.forEach(value => {
|
|
91
|
+
const [frac, exp] = Frexp(-value);
|
|
92
|
+
const reconstructed = frac * Math.pow(2, exp);
|
|
93
|
+
expect(reconstructed).toBeCloseTo(-value, 10);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('should ensure fraction is in range [0.5, 1) for positive numbers', () => {
|
|
98
|
+
const testValues = [1, 2, 3, 4, 5, 8, 16, 0.5, 0.25, 0.125, 1.5, 3.14159, 100, 1000];
|
|
99
|
+
|
|
100
|
+
testValues.forEach(value => {
|
|
101
|
+
const [frac, _exp] = Frexp(value);
|
|
102
|
+
if (value !== 0) {
|
|
103
|
+
expect(Math.abs(frac)).toBeGreaterThanOrEqual(0.5);
|
|
104
|
+
expect(Math.abs(frac)).toBeLessThan(1);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('should handle very large numbers', () => {
|
|
110
|
+
const large = 1e100;
|
|
111
|
+
const [frac, exp] = Frexp(large);
|
|
112
|
+
expect(Math.abs(frac)).toBeGreaterThanOrEqual(0.5);
|
|
113
|
+
expect(Math.abs(frac)).toBeLessThan(1);
|
|
114
|
+
expect(frac * Math.pow(2, exp)).toBeCloseTo(large, 5);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('should handle very small numbers', () => {
|
|
118
|
+
const small = 1e-100;
|
|
119
|
+
const [frac, exp] = Frexp(small);
|
|
120
|
+
expect(Math.abs(frac)).toBeGreaterThanOrEqual(0.5);
|
|
121
|
+
expect(Math.abs(frac)).toBeLessThan(1);
|
|
122
|
+
expect(frac * Math.pow(2, exp)).toBeCloseTo(small, 110);
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
describe('frexp (lowercase)', () => {
|
|
127
|
+
it('should work identically to Frexp', () => {
|
|
128
|
+
const testValues = [0, 1, 2, 4, 8, 0.5, 0.25, -1, -2, 3.14159];
|
|
129
|
+
|
|
130
|
+
testValues.forEach(value => {
|
|
131
|
+
const [frac1, exp1] = Frexp(value);
|
|
132
|
+
const [frac2, exp2] = frexp(value);
|
|
133
|
+
expect(frac1).toBe(frac2);
|
|
134
|
+
expect(exp1).toBe(exp2);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Test special cases
|
|
138
|
+
expect(frexp(Inf(1))).toEqual(Frexp(Inf(1)));
|
|
139
|
+
expect(frexp(Inf(-1))).toEqual(Frexp(Inf(-1)));
|
|
140
|
+
|
|
141
|
+
const [fracNaN1, expNaN1] = frexp(GoNaN());
|
|
142
|
+
const [fracNaN2, expNaN2] = Frexp(GoNaN());
|
|
143
|
+
expect(IsNaN(fracNaN1)).toBe(IsNaN(fracNaN2));
|
|
144
|
+
expect(expNaN1).toBe(expNaN2);
|
|
145
|
+
});
|
|
146
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as $ from "@goscript/builtin/builtin.js";
|
|
2
|
+
import { IsInf, IsNaN, normalize } from "./bits.gs.js";
|
|
3
|
+
|
|
4
|
+
import { Float64bits, Float64frombits } from "./unsafe.gs.js";
|
|
5
|
+
|
|
6
|
+
// Frexp breaks f into a normalized fraction
|
|
7
|
+
// and an integral power of two.
|
|
8
|
+
// It returns frac and exp satisfying f == frac × 2**exp,
|
|
9
|
+
// with the absolute value of frac in the interval [½, 1).
|
|
10
|
+
//
|
|
11
|
+
// Special cases are:
|
|
12
|
+
//
|
|
13
|
+
// Frexp(±0) = ±0, 0
|
|
14
|
+
// Frexp(±Inf) = ±Inf, 0
|
|
15
|
+
// Frexp(NaN) = NaN, 0
|
|
16
|
+
export function Frexp(f: number): [number, number] {
|
|
17
|
+
return frexp(f)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function frexp(f: number): [number, number] {
|
|
21
|
+
// Handle special cases
|
|
22
|
+
if (f === 0) {
|
|
23
|
+
return [f, 0] // Preserve sign of zero
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!Number.isFinite(f) || Number.isNaN(f)) {
|
|
27
|
+
return [f, 0]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// For normal numbers, extract exponent and mantissa
|
|
31
|
+
const absF = Math.abs(f)
|
|
32
|
+
const exp = Math.floor(Math.log2(absF)) + 1
|
|
33
|
+
const frac = f / Math.pow(2, exp)
|
|
34
|
+
|
|
35
|
+
return [frac, exp]
|
|
36
|
+
}
|
|
37
|
+
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { Gamma } from './gamma.gs.js'
|
|
3
|
+
|
|
4
|
+
describe('Gamma', () => {
|
|
5
|
+
it('should return correct values for positive integers', () => {
|
|
6
|
+
expect(Gamma(1)).toBe(1)
|
|
7
|
+
expect(Gamma(2)).toBe(1)
|
|
8
|
+
expect(Gamma(3)).toBe(2)
|
|
9
|
+
expect(Gamma(4)).toBe(6)
|
|
10
|
+
expect(Gamma(5)).toBe(24)
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
it('should return correct values for half-integers', () => {
|
|
14
|
+
expect(Gamma(0.5)).toBeCloseTo(1.7724538509055159, 14)
|
|
15
|
+
expect(Gamma(1.5)).toBeCloseTo(0.8862269254527579, 14)
|
|
16
|
+
expect(Gamma(2.5)).toBeCloseTo(1.329340388179137, 14)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('should handle negative non-integer values', () => {
|
|
20
|
+
expect(Gamma(-0.5)).toBeCloseTo(-3.5449077018110318, 14)
|
|
21
|
+
expect(Gamma(-1.5)).toBeCloseTo(2.363271801207355, 14)
|
|
22
|
+
expect(Gamma(-2.5)).toBeCloseTo(-0.9453087204829419, 14)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('should handle special values', () => {
|
|
26
|
+
expect(Gamma(0)).toBe(Number.POSITIVE_INFINITY)
|
|
27
|
+
expect(Gamma(Number.POSITIVE_INFINITY)).toBe(Number.POSITIVE_INFINITY)
|
|
28
|
+
expect(Number.isNaN(Gamma(Number.NEGATIVE_INFINITY))).toBe(true)
|
|
29
|
+
expect(Number.isNaN(Gamma(Number.NaN))).toBe(true)
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('should return NaN for negative integers', () => {
|
|
33
|
+
expect(Number.isNaN(Gamma(-1))).toBe(true)
|
|
34
|
+
expect(Number.isNaN(Gamma(-2))).toBe(true)
|
|
35
|
+
expect(Number.isNaN(Gamma(-3))).toBe(true)
|
|
36
|
+
expect(Number.isNaN(Gamma(-10))).toBe(true)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('should satisfy the recurrence relation Gamma(x+1) = x * Gamma(x)', () => {
|
|
40
|
+
const testValues = [0.5, 1.5, 2.5, 3.5]
|
|
41
|
+
for (const x of testValues) {
|
|
42
|
+
expect(Gamma(x + 1)).toBeCloseTo(x * Gamma(x), 12)
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('should handle very small positive values', () => {
|
|
47
|
+
// Relax tolerance for very small values due to JavaScript precision limits
|
|
48
|
+
expect(Gamma(1e-10)).toBeCloseTo(9999999999.422785, 1)
|
|
49
|
+
expect(Gamma(1e-5)).toBeCloseTo(99999.42279422554, 0)
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('should handle large positive values', () => {
|
|
53
|
+
expect(Gamma(10)).toBeCloseTo(362880, 8)
|
|
54
|
+
// Relax tolerance for very large values due to JavaScript precision limits
|
|
55
|
+
expect(Gamma(20)).toBeCloseTo(1.21645100408832e17, 10)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it('should satisfy reflection formula for negative values', () => {
|
|
59
|
+
// Gamma(x) * Gamma(1-x) = π / sin(πx) for non-integer x
|
|
60
|
+
const x = 0.3
|
|
61
|
+
const gamma_x = Gamma(x)
|
|
62
|
+
const gamma_1_minus_x = Gamma(1 - x)
|
|
63
|
+
const expected = Math.PI / Math.sin(Math.PI * x)
|
|
64
|
+
expect(gamma_x * gamma_1_minus_x).toBeCloseTo(expected, 10)
|
|
65
|
+
})
|
|
66
|
+
})
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import * as $ from "@goscript/builtin/builtin.js";
|
|
2
|
+
import { Abs } from "./abs.gs.js";
|
|
3
|
+
import { Inf, IsInf, IsNaN, NaN } from "./bits.gs.js";
|
|
4
|
+
import { Exp } from "./exp.gs.js";
|
|
5
|
+
import { Floor } from "./floor.gs.js";
|
|
6
|
+
import { Modf } from "./modf.gs.js";
|
|
7
|
+
import { Pow } from "./pow.gs.js";
|
|
8
|
+
import { Signbit } from "./signbit.gs.js";
|
|
9
|
+
import { Sin } from "./sin.gs.js";
|
|
10
|
+
|
|
11
|
+
let _gamP = $.arrayToSlice<number>([1.60119522476751861407e-04, 1.19135147006586384913e-03, 1.04213797561761569935e-02, 4.76367800457137231464e-02, 2.07448227648435975150e-01, 4.94214826801497100753e-01, 9.99999999999999996796e-01])
|
|
12
|
+
|
|
13
|
+
let _gamQ = $.arrayToSlice<number>([-2.31581873324120129819e-05, 5.39605580493303397842e-04, -4.45641913851797240494e-03, 1.18139785222060435552e-02, 3.58236398605498653373e-02, -2.34591795718243348568e-01, 7.14304917030273074085e-02, 1.00000000000000000320e+00])
|
|
14
|
+
|
|
15
|
+
let _gamS = $.arrayToSlice<number>([7.87311395793093628397e-04, -2.29549961613378126380e-04, -2.68132617805781232825e-03, 3.47222221605458667310e-03, 8.33333333333482257126e-02])
|
|
16
|
+
|
|
17
|
+
// Gamma function computed by Stirling's formula.
|
|
18
|
+
// The pair of results must be multiplied together to get the actual answer.
|
|
19
|
+
// The multiplication is left to the caller so that, if careful, the caller can avoid
|
|
20
|
+
// infinity for 172 <= x <= 180.
|
|
21
|
+
// The polynomial is valid for 33 <= x <= 172; larger values are only used
|
|
22
|
+
// in reciprocal and produce denormalized floats. The lower precision there
|
|
23
|
+
// masks any imprecision in the polynomial.
|
|
24
|
+
export function stirling(x: number): [number, number] {
|
|
25
|
+
if (x > 200) {
|
|
26
|
+
return [Inf(1), 1]
|
|
27
|
+
}
|
|
28
|
+
let SqrtTwoPi: number = 2.506628274631000502417
|
|
29
|
+
let MaxStirling: number = 143.01608
|
|
30
|
+
let w = 1 / x
|
|
31
|
+
w = 1 + w * ((((_gamS![0] * w + _gamS![1]) * w + _gamS![2]) * w + _gamS![3]) * w + _gamS![4])
|
|
32
|
+
let y1 = Exp(x)
|
|
33
|
+
let y2 = 1.0
|
|
34
|
+
// avoid Pow() overflow
|
|
35
|
+
if (x > 143.016) {
|
|
36
|
+
// avoid Pow() overflow
|
|
37
|
+
let v = Pow(x, 0.5 * x - 0.25)
|
|
38
|
+
y1 = v
|
|
39
|
+
y2 = v / y1
|
|
40
|
+
} else {
|
|
41
|
+
y1 = Pow(x, x - 0.5) / y1
|
|
42
|
+
}
|
|
43
|
+
return [y1, 2.50663 * w * y2]
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Gamma returns the Gamma function of x.
|
|
47
|
+
//
|
|
48
|
+
// Special cases are:
|
|
49
|
+
//
|
|
50
|
+
// Gamma(+Inf) = +Inf
|
|
51
|
+
// Gamma(+0) = +Inf
|
|
52
|
+
// Gamma(-0) = -Inf
|
|
53
|
+
// Gamma(x) = NaN for integer x < 0
|
|
54
|
+
// Gamma(-Inf) = NaN
|
|
55
|
+
// Gamma(NaN) = NaN
|
|
56
|
+
export function Gamma(x: number): number {
|
|
57
|
+
// A001620
|
|
58
|
+
let Euler: number = 0.57721566490153286060651209008240243104215933593992
|
|
59
|
+
// special cases
|
|
60
|
+
switch (true) {
|
|
61
|
+
case isNegInt(x) || IsInf(x, -1) || IsNaN(x):
|
|
62
|
+
return NaN()
|
|
63
|
+
break
|
|
64
|
+
case IsInf(x, 1):
|
|
65
|
+
return Inf(1)
|
|
66
|
+
break
|
|
67
|
+
case x == 0:
|
|
68
|
+
if (Signbit(x)) {
|
|
69
|
+
return Inf(-1)
|
|
70
|
+
}
|
|
71
|
+
return Inf(1)
|
|
72
|
+
break
|
|
73
|
+
}
|
|
74
|
+
let q = Abs(x)
|
|
75
|
+
let p = Floor(q)
|
|
76
|
+
|
|
77
|
+
// Note: x is negative but (checked above) not a negative integer,
|
|
78
|
+
// so x must be small enough to be in range for conversion to int64.
|
|
79
|
+
// If |x| were >= 2⁶³ it would have to be an integer.
|
|
80
|
+
if (q > 33) {
|
|
81
|
+
if (x >= 0) {
|
|
82
|
+
let [y1, y2] = stirling(x)
|
|
83
|
+
return y1 * y2
|
|
84
|
+
}
|
|
85
|
+
// Note: x is negative but (checked above) not a negative integer,
|
|
86
|
+
// so x must be small enough to be in range for conversion to int64.
|
|
87
|
+
// If |x| were >= 2⁶³ it would have to be an integer.
|
|
88
|
+
let signgam = 1
|
|
89
|
+
{
|
|
90
|
+
let ip = (p as number)
|
|
91
|
+
if ((ip & 1) == 0) {
|
|
92
|
+
signgam = -1
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
let z = q - p
|
|
96
|
+
if (z > 0.5) {
|
|
97
|
+
p = p + 1
|
|
98
|
+
z = q - p
|
|
99
|
+
}
|
|
100
|
+
z = q * Sin(3.14159 * z)
|
|
101
|
+
if (z == 0) {
|
|
102
|
+
return Inf(signgam)
|
|
103
|
+
}
|
|
104
|
+
let [sq1, sq2] = stirling(q)
|
|
105
|
+
let absz = Abs(z)
|
|
106
|
+
let d = absz * sq1 * sq2
|
|
107
|
+
if (IsInf(d, 0)) {
|
|
108
|
+
z = 3.14159 / absz / sq1 / sq2
|
|
109
|
+
} else {
|
|
110
|
+
z = 3.14159 / d
|
|
111
|
+
}
|
|
112
|
+
return (signgam as number) * z
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Reduce argument
|
|
116
|
+
let z = 1.0
|
|
117
|
+
for (; x >= 3; ) {
|
|
118
|
+
x = x - 1
|
|
119
|
+
z = z * x
|
|
120
|
+
}
|
|
121
|
+
for (; x < 0; ) {
|
|
122
|
+
if (x > -1e-09) {
|
|
123
|
+
// unhandled branch statement token: goto
|
|
124
|
+
}
|
|
125
|
+
z = z / x
|
|
126
|
+
x = x + 1
|
|
127
|
+
}
|
|
128
|
+
for (; x < 2; ) {
|
|
129
|
+
if (x < 1e-09) {
|
|
130
|
+
// unhandled branch statement token: goto
|
|
131
|
+
}
|
|
132
|
+
z = z / x
|
|
133
|
+
x = x + 1
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (x == 2) {
|
|
137
|
+
return z
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
x = x - 2
|
|
141
|
+
p = (((((x * _gamP![0] + _gamP![1]) * x + _gamP![2]) * x + _gamP![3]) * x + _gamP![4]) * x + _gamP![5]) * x + _gamP![6]
|
|
142
|
+
q = ((((((x * _gamQ![0] + _gamQ![1]) * x + _gamQ![2]) * x + _gamQ![3]) * x + _gamQ![4]) * x + _gamQ![5]) * x + _gamQ![6]) * x + _gamQ![7]
|
|
143
|
+
return z * p / q
|
|
144
|
+
|
|
145
|
+
small: if (x == 0) {
|
|
146
|
+
return Inf(1)
|
|
147
|
+
}
|
|
148
|
+
return z / ((1 + 0.577216 * x) * x)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function isNegInt(x: number): boolean {
|
|
152
|
+
if (x < 0) {
|
|
153
|
+
let [, xf] = Modf(x)
|
|
154
|
+
return xf == 0
|
|
155
|
+
}
|
|
156
|
+
return false
|
|
157
|
+
}
|
|
158
|
+
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { Hypot, hypot } from './hypot.gs.js';
|
|
3
|
+
import { Inf, NaN as GoNaN, IsNaN, IsInf } from './bits.gs.js';
|
|
4
|
+
|
|
5
|
+
describe('Hypot', () => {
|
|
6
|
+
it('should calculate hypotenuse correctly for basic cases', () => {
|
|
7
|
+
expect(Hypot(3, 4)).toBeCloseTo(5, 10);
|
|
8
|
+
expect(Hypot(5, 12)).toBeCloseTo(13, 10);
|
|
9
|
+
expect(Hypot(8, 15)).toBeCloseTo(17, 10);
|
|
10
|
+
expect(Hypot(1, 1)).toBeCloseTo(Math.sqrt(2), 10);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('should handle zero values', () => {
|
|
14
|
+
expect(Hypot(0, 0)).toBe(0);
|
|
15
|
+
expect(Hypot(0, 5)).toBe(5);
|
|
16
|
+
expect(Hypot(5, 0)).toBe(5);
|
|
17
|
+
expect(Hypot(0, -5)).toBe(5);
|
|
18
|
+
expect(Hypot(-5, 0)).toBe(5);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should handle negative values', () => {
|
|
22
|
+
expect(Hypot(-3, 4)).toBeCloseTo(5, 10);
|
|
23
|
+
expect(Hypot(3, -4)).toBeCloseTo(5, 10);
|
|
24
|
+
expect(Hypot(-3, -4)).toBeCloseTo(5, 10);
|
|
25
|
+
expect(Hypot(-5, -12)).toBeCloseTo(13, 10);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('should handle infinity cases', () => {
|
|
29
|
+
expect(Hypot(Inf(1), 5)).toBe(Inf(1));
|
|
30
|
+
expect(Hypot(5, Inf(1))).toBe(Inf(1));
|
|
31
|
+
expect(Hypot(Inf(-1), 5)).toBe(Inf(1));
|
|
32
|
+
expect(Hypot(5, Inf(-1))).toBe(Inf(1));
|
|
33
|
+
expect(Hypot(Inf(1), Inf(1))).toBe(Inf(1));
|
|
34
|
+
expect(Hypot(Inf(-1), Inf(-1))).toBe(Inf(1));
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should handle NaN cases', () => {
|
|
38
|
+
expect(IsNaN(Hypot(GoNaN(), 5))).toBe(true);
|
|
39
|
+
expect(IsNaN(Hypot(5, GoNaN()))).toBe(true);
|
|
40
|
+
expect(IsNaN(Hypot(GoNaN(), GoNaN()))).toBe(true);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should handle very large values without overflow', () => {
|
|
44
|
+
const large = 1e150;
|
|
45
|
+
const result = Hypot(large, large);
|
|
46
|
+
expect(result).toBeCloseTo(large * Math.sqrt(2), 5);
|
|
47
|
+
expect(IsInf(result, 0)).toBe(false);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should handle very small values without underflow', () => {
|
|
51
|
+
const small = 1e-150;
|
|
52
|
+
const result = Hypot(small, small);
|
|
53
|
+
expect(result).toBeCloseTo(small * Math.sqrt(2), 160);
|
|
54
|
+
expect(result).toBeGreaterThan(0);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('should be commutative', () => {
|
|
58
|
+
expect(Hypot(3, 4)).toBe(Hypot(4, 3));
|
|
59
|
+
expect(Hypot(-3, 4)).toBe(Hypot(4, -3));
|
|
60
|
+
expect(Hypot(1.5, 2.5)).toBe(Hypot(2.5, 1.5));
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe('hypot (lowercase)', () => {
|
|
65
|
+
it('should work identically to Hypot', () => {
|
|
66
|
+
expect(hypot(3, 4)).toBe(Hypot(3, 4));
|
|
67
|
+
expect(hypot(5, 12)).toBe(Hypot(5, 12));
|
|
68
|
+
expect(hypot(0, 0)).toBe(Hypot(0, 0));
|
|
69
|
+
expect(hypot(-3, 4)).toBe(Hypot(-3, 4));
|
|
70
|
+
expect(hypot(Inf(1), 5)).toBe(Hypot(Inf(1), 5));
|
|
71
|
+
expect(IsNaN(hypot(GoNaN(), 5))).toBe(IsNaN(Hypot(GoNaN(), 5)));
|
|
72
|
+
});
|
|
73
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as $ from "@goscript/builtin/builtin.js";
|
|
2
|
+
import { Abs } from "./abs.gs.js";
|
|
3
|
+
import { Inf, IsInf, IsNaN, NaN } from "./bits.gs.js";
|
|
4
|
+
// archHypot import removed - using optimized implementation
|
|
5
|
+
import { Sqrt } from "./sqrt.gs.js";
|
|
6
|
+
|
|
7
|
+
// Hypot returns [Sqrt](p*p + q*q), taking care to avoid
|
|
8
|
+
// unnecessary overflow and underflow.
|
|
9
|
+
//
|
|
10
|
+
// Special cases are:
|
|
11
|
+
//
|
|
12
|
+
// Hypot(±Inf, q) = +Inf
|
|
13
|
+
// Hypot(p, ±Inf) = +Inf
|
|
14
|
+
// Hypot(NaN, q) = NaN
|
|
15
|
+
// Hypot(p, NaN) = NaN
|
|
16
|
+
export function Hypot(p: number, q: number): number {
|
|
17
|
+
return Math.hypot(p, q)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function hypot(p: number, q: number): number {
|
|
21
|
+
return Math.hypot(p, q)
|
|
22
|
+
}
|
|
23
|
+
|
package/gs/math/index.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export { Abs } from "./abs.gs.js"
|
|
2
|
+
export { Acosh } from "./acosh.gs.js"
|
|
3
|
+
export { Acos, Asin } from "./asin.gs.js"
|
|
4
|
+
export { Asinh } from "./asinh.gs.js"
|
|
5
|
+
export { Atan } from "./atan.gs.js"
|
|
6
|
+
export { Atan2 } from "./atan2.gs.js"
|
|
7
|
+
export { Atanh } from "./atanh.gs.js"
|
|
8
|
+
export { Inf, IsInf, IsNaN, NaN } from "./bits.gs.js"
|
|
9
|
+
export { Cbrt } from "./cbrt.gs.js"
|
|
10
|
+
export { E, Ln10, Ln2, Log10E, Log2E, MaxFloat32, MaxFloat64, MaxInt, MaxInt16, MaxInt32, MaxInt64, MaxInt8, MaxUint, MaxUint16, MaxUint32, MaxUint64, MaxUint8, MinInt, MinInt16, MinInt32, MinInt64, MinInt8, Phi, Pi, SmallestNonzeroFloat32, SmallestNonzeroFloat64, Sqrt2, SqrtE, SqrtPhi, SqrtPi } from "./const.gs.js"
|
|
11
|
+
export { Copysign } from "./copysign.gs.js"
|
|
12
|
+
export { Dim, Max, Min } from "./dim.gs.js"
|
|
13
|
+
export { Erf, Erfc } from "./erf.gs.js"
|
|
14
|
+
export { Erfcinv, Erfinv } from "./erfinv.gs.js"
|
|
15
|
+
export { Exp, Exp2 } from "./exp.gs.js"
|
|
16
|
+
export { Expm1 } from "./expm1.gs.js"
|
|
17
|
+
export { Ceil, Floor, Round, RoundToEven, Trunc } from "./floor.gs.js"
|
|
18
|
+
export { FMA } from "./fma.gs.js"
|
|
19
|
+
export { Frexp } from "./frexp.gs.js"
|
|
20
|
+
export { Gamma } from "./gamma.gs.js"
|
|
21
|
+
export { Hypot } from "./hypot.gs.js"
|
|
22
|
+
export { J0, Y0 } from "./j0.gs.js"
|
|
23
|
+
export { J1, Y1 } from "./j1.gs.js"
|
|
24
|
+
export { Jn, Yn } from "./jn.gs.js"
|
|
25
|
+
export { Ldexp } from "./ldexp.gs.js"
|
|
26
|
+
export { Lgamma } from "./lgamma.gs.js"
|
|
27
|
+
export { Log } from "./log.gs.js"
|
|
28
|
+
export { Log10, Log2 } from "./log10.gs.js"
|
|
29
|
+
export { Log1p } from "./log1p.gs.js"
|
|
30
|
+
export { Ilogb, Logb } from "./logb.gs.js"
|
|
31
|
+
export { Mod } from "./mod.gs.js"
|
|
32
|
+
export { Modf } from "./modf.gs.js"
|
|
33
|
+
export { Nextafter, Nextafter32 } from "./nextafter.gs.js"
|
|
34
|
+
export { Pow } from "./pow.gs.js"
|
|
35
|
+
export { Pow10 } from "./pow10.gs.js"
|
|
36
|
+
export { Remainder } from "./remainder.gs.js"
|
|
37
|
+
export { Signbit } from "./signbit.gs.js"
|
|
38
|
+
export { Cos, Sin } from "./sin.gs.js"
|
|
39
|
+
export { Sincos } from "./sincos.gs.js"
|
|
40
|
+
export { Cosh, Sinh } from "./sinh.gs.js"
|
|
41
|
+
export { Sqrt } from "./sqrt.gs.js"
|
|
42
|
+
export { Tan } from "./tan.gs.js"
|
|
43
|
+
export { Tanh } from "./tanh.gs.js"
|
|
44
|
+
export { Float32bits, Float32frombits, Float64bits, Float64frombits } from "./unsafe.gs.js"
|