| 2036 | } |
| 2037 | |
| 2038 | function logHypot(a, b) { |
| 2039 | a = new BigNumber(a).toNumber() |
| 2040 | b = new BigNumber(b).toNumber() |
| 2041 | |
| 2042 | const _a = Math.abs(a); |
| 2043 | const _b = Math.abs(b); |
| 2044 | |
| 2045 | if (a === 0) { |
| 2046 | return new BigNumber(Math.log(_b)); |
| 2047 | } |
| 2048 | |
| 2049 | if (b === 0) { |
| 2050 | return new BigNumber(Math.log(_a)); |
| 2051 | } |
| 2052 | |
| 2053 | if (_a < 3000 && _b < 3000) { |
| 2054 | return new BigNumber(Math.log(a * a + b * b) * 0.5); |
| 2055 | } |
| 2056 | |
| 2057 | /* I got 4 ideas to compute this property without overflow: |
| 2058 | * |
| 2059 | * Testing 1000000 times with random samples for a,b ∈ [1, 1000000000] against a big decimal library to get an error estimate |
| 2060 | * |
| 2061 | * 1. Only eliminate the square root: (OVERALL ERROR: 3.9122483030951116e-11) |
| 2062 | Math.log(a * a + b * b) / 2 |
| 2063 | * |
| 2064 | * |
| 2065 | * 2. Try to use the non-overflowing pythagoras: (OVERALL ERROR: 8.889760039210159e-10) |
| 2066 | var fn = function(a, b) { |
| 2067 | a = Math.abs(a); |
| 2068 | b = Math.abs(b); |
| 2069 | var t = Math.min(a, b); |
| 2070 | a = Math.max(a, b); |
| 2071 | t = t / a; |
| 2072 | return Math.log(a) + Math.log(1 + t * t) / 2; |
| 2073 | }; |
| 2074 | * 3. Abuse the identity cos(atan(y/x) = x / sqrt(x^2+y^2): (OVERALL ERROR: 3.4780178737037204e-10) |
| 2075 | Math.log(a / Math.cos(Math.atan2(b, a))) |
| 2076 | * 4. Use 3. and apply log rules: (OVERALL ERROR: 1.2014087502620896e-9) |
| 2077 | Math.log(a) - Math.log(Math.cos(Math.atan2(b, a))) |
| 2078 | */ |
| 2079 | |
| 2080 | return new BigNumber(Math.log(a / Math.cos(Math.atan2(b, a)))) |
| 2081 | } |
| 2082 | |
| 2083 | |
| 2084 | let a = this.a; |