forked from numberscope/frontscope
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmath.ts
145 lines (116 loc) · 4.05 KB
/
math.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/** md
## Math utilities for numberscope
The primary resource for doing math inside the frontscope code is the
[mathjs](http://mathjs.org) package, which this repository depends on.
The `shared/math` module of Numberscope provides some additional utilities
aimed at making common mathematical operations more convenient, especially
when working with bigints.
Note that currently every one of these functions accepts either
`number` or `bigint` inputs for all arguments and simply converts them
to bigints.
### Example usage
```ts
import {
safeNumber,
floorSqrt,
modulo,
powmod,
natlog
} from '../shared/math'
try {
const myNumber = safeNumber(9007199254740992n)
} catch (err: unknown) {
console.log('This will always be logged')
}
try {
const myNumber = safeNumber(9007n)
} catch (err: unknown) {
console.log('This will never be logged and myNumber will be 9007')
}
const five: bigint = floorSqrt(30n)
const negativeTwo: bigint = floorSqrt(-2n)
const three: bigint = modulo(-7n, 5)
const two: bigint = modulo(7, 5n)
const six: bigint = powmod(6, 2401n, 7n)
// n to the p is congruent to n mod a prime p,
// so a to any power of p is as well.
const fortysixish: number = natlog(100000000000000000000n)
const seven: bigint = bigabs(-7n)
```
### Detailed function reference
**/
import isqrt from 'bigint-isqrt'
import {modPow} from 'bigint-mod-arith'
const maxSafeNumber = BigInt(Number.MAX_SAFE_INTEGER)
const minSafeNumber = BigInt(Number.MIN_SAFE_INTEGER)
/** md
#### safeNumber(n: number | bigint): number
Returns the `number` mathematically equal to _n_ if there is one, or
throws an error otherwise.
**/
export function safeNumber(n: number | bigint): number {
const bn = BigInt(n)
if (bn < minSafeNumber || bn > maxSafeNumber) {
throw new RangeError(`Attempt to use ${bn} as a number`)
}
return Number(bn)
}
/** md
#### floorSqrt(n: number | bigint): bigint
Returns the largest bigint _r_ such that the square of _r_ is less than or
equal to _n_, if there is one; otherwise returns the bigint mathematically
equal to _n_. (Thus, it leaves negative bigints unchanged.)
**/
export function floorSqrt(n: number | bigint): bigint {
const bn = BigInt(n)
return isqrt(bn)
}
/** md
#### modulo(n: number | bigint, modulus: number | bigint): bigint
Returns the smallest nonnegative bigint congruent to _n_ modulo
_modulus_; this is also the remainder upon dividing _n_ by _modulus_. Note
that this is the "mathematician's modulus" that never returns a negative
value, unlike the built-in JavaScript `%` operator.
Throws a RangeError if _modulus_ is nonpositive.
**/
export function modulo(n: number | bigint, modulus: number | bigint): bigint {
const bn = BigInt(n)
const bmodulus = BigInt(modulus)
if (bmodulus <= 0n) {
throw new RangeError(`Attempt to use nonpositive modulus ${bmodulus}`)
}
const result = bn % bmodulus
return result < 0n ? result + bmodulus : result
}
/** md
#### powmod(n, exponent, modulus): bigint
All parameters have type `number | bigint`. If _modulus_ is nonpositive,
throws a RangeError.
Otherwise, if _exponent_ is positive, returns the smallest nonnegative bigint
congruent to _n_ raised to the _exponent_ power modulo _modulus_ (but far more
efficiently than computing `modulo(n**exponent, modulus)`).
If _exponent_ is negative, first computes `i = powmod(n, -exponent, modulus)`.
If _i_ has a multiplicative inverse modulo _modulus_, returns that inverse,
otherwise throws a RangeError.
**/
export const powmod = modPow // just need to fix the name
const nlg16 = Math.log(16)
/** md
#### natlog(n: number | bigint): number
Returns the natural log of the input.
**/
export function natlog(n: number | bigint): number {
if (typeof n === 'number') return Math.log(n)
if (n < 0) return NaN
const s = n.toString(16)
const s15 = s.substring(0, 15)
return nlg16 * (s.length - s15.length) + Math.log(Number('0x' + s15))
}
/** md
#### bigabs(n: bigint): bigint
returns the absolute value of a bigint
**/
export function bigabs(n: bigint): bigint {
if (n < 0n) return -n
return n
}