pimath 0.1.39 → 0.2.0
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/dist/pimath.js +3127 -2865
- package/dist/pimath.js.map +1 -1
- package/package.json +16 -12
- package/src/algebra/equation.ts +558 -0
- package/src/algebra/equationSolver.ts +488 -0
- package/src/algebra/factor.ts +338 -0
- package/src/algebra/index.ts +11 -0
- package/src/algebra/linearSystem.ts +439 -0
- package/src/algebra/logicalset.ts +255 -0
- package/src/algebra/matrix.ts +474 -0
- package/src/algebra/monom.ts +977 -0
- package/src/algebra/operations.ts +23 -0
- package/src/algebra/polyFactor.ts +668 -0
- package/src/algebra/polynom.ts +1247 -0
- package/src/analyze/index.ts +4 -0
- package/src/analyze/solution.ts +178 -0
- package/src/analyze/tableOfSigns.ts +30 -0
- package/src/coefficients/fraction.ts +718 -0
- package/src/coefficients/index.ts +4 -0
- package/src/coefficients/root.ts +346 -0
- package/src/geometry/TupleN.ts +128 -0
- package/src/geometry/circle.ts +456 -0
- package/src/geometry/geomMath.ts +71 -0
- package/src/geometry/index.ts +11 -0
- package/src/geometry/line.ts +653 -0
- package/src/geometry/line3.ts +211 -0
- package/src/geometry/plane3.ts +179 -0
- package/src/geometry/point.ts +104 -0
- package/src/geometry/sphere3.ts +214 -0
- package/src/geometry/triangle.ts +482 -0
- package/src/geometry/vector.ts +225 -0
- package/src/helpers.ts +35 -0
- package/src/index.ts +61 -0
- package/src/numeric.ts +196 -0
- package/src/pimath.interface.ts +162 -0
- package/src/randomization/algebra/rndEquation.ts +41 -0
- package/src/randomization/algebra/rndMonom.ts +39 -0
- package/src/randomization/algebra/rndPolynom.ts +100 -0
- package/src/randomization/coefficient/rndFraction.ts +38 -0
- package/src/randomization/geometry/rndCircle.ts +27 -0
- package/src/randomization/geometry/rndLine.ts +35 -0
- package/src/randomization/geometry/rndLine3.ts +27 -0
- package/src/randomization/geometry/rndVector.ts +63 -0
- package/src/randomization/random.ts +89 -0
- package/src/randomization/rndHelpers.ts +102 -0
- package/src/randomization/rndTypes.ts +67 -0
- package/types/algebra/equation.d.ts +18 -17
- package/types/algebra/equation.d.ts.map +1 -1
- package/types/algebra/equationSolver.d.ts +7 -3
- package/types/algebra/equationSolver.d.ts.map +1 -1
- package/types/algebra/factor.d.ts +1 -1
- package/types/algebra/factor.d.ts.map +1 -1
- package/types/algebra/linearSystem.d.ts +23 -6
- package/types/algebra/linearSystem.d.ts.map +1 -1
- package/types/algebra/logicalset.d.ts +1 -1
- package/types/algebra/logicalset.d.ts.map +1 -1
- package/types/algebra/monom.d.ts +1 -6
- package/types/algebra/monom.d.ts.map +1 -1
- package/types/algebra/operations.d.ts.map +1 -1
- package/types/algebra/polyFactor.d.ts +9 -4
- package/types/algebra/polyFactor.d.ts.map +1 -1
- package/types/algebra/polynom.d.ts +10 -7
- package/types/algebra/polynom.d.ts.map +1 -1
- package/types/analyze/index.d.ts +2 -0
- package/types/analyze/index.d.ts.map +1 -0
- package/types/analyze/solution.d.ts +27 -0
- package/types/analyze/solution.d.ts.map +1 -0
- package/types/analyze/tableOfSigns.d.ts +9 -0
- package/types/analyze/tableOfSigns.d.ts.map +1 -0
- package/types/coefficients/fraction.d.ts +14 -12
- package/types/coefficients/fraction.d.ts.map +1 -1
- package/types/coefficients/index.d.ts +1 -1
- package/types/coefficients/index.d.ts.map +1 -1
- package/types/coefficients/root.d.ts +41 -0
- package/types/coefficients/root.d.ts.map +1 -0
- package/types/geometry/TupleAbstract.d.ts +22 -0
- package/types/geometry/TupleAbstract.d.ts.map +1 -0
- package/types/geometry/TupleN.d.ts +24 -0
- package/types/geometry/TupleN.d.ts.map +1 -0
- package/types/geometry/circle.d.ts +26 -17
- package/types/geometry/circle.d.ts.map +1 -1
- package/types/geometry/geomMath.d.ts +2 -1
- package/types/geometry/geomMath.d.ts.map +1 -1
- package/types/geometry/index.d.ts.map +1 -1
- package/types/geometry/line.d.ts +21 -30
- package/types/geometry/line.d.ts.map +1 -1
- package/types/geometry/line3.d.ts +19 -19
- package/types/geometry/line3.d.ts.map +1 -1
- package/types/geometry/matrix.d.ts +11 -11
- package/types/geometry/plane3.d.ts +9 -9
- package/types/geometry/plane3.d.ts.map +1 -1
- package/types/geometry/point.d.ts +12 -7
- package/types/geometry/point.d.ts.map +1 -1
- package/types/geometry/triangle.d.ts +68 -23
- package/types/geometry/triangle.d.ts.map +1 -1
- package/types/geometry/vector.d.ts +24 -44
- package/types/geometry/vector.d.ts.map +1 -1
- package/types/helpers.d.ts +1 -0
- package/types/helpers.d.ts.map +1 -1
- package/types/index.d.ts +6 -4
- package/types/index.d.ts.map +1 -1
- package/types/numeric.d.ts +2 -0
- package/types/numeric.d.ts.map +1 -1
- package/types/pimath.interface.d.ts +38 -44
- package/types/pimath.interface.d.ts.map +1 -1
- package/types/randomization/algebra/rndPolynom.d.ts.map +1 -1
- package/types/randomization/coefficient/rndFraction.d.ts +1 -1
- package/types/randomization/coefficient/rndFraction.d.ts.map +1 -1
- package/types/randomization/geometry/rndLine.d.ts.map +1 -1
- package/types/randomization/random.d.ts +3 -2
- package/types/randomization/random.d.ts.map +1 -1
- package/types/randomization/rndTypes.d.ts +15 -10
- package/types/randomization/rndTypes.d.ts.map +1 -1
|
@@ -0,0 +1,718 @@
|
|
|
1
|
+
import type {compareSign, IExpression, InputValue, IPiMathObject} from "../pimath.interface"
|
|
2
|
+
import {Numeric} from "../numeric"
|
|
3
|
+
|
|
4
|
+
export enum FRAC_TYPE {
|
|
5
|
+
frac = 'frac',
|
|
6
|
+
dfrac = 'dfrac',
|
|
7
|
+
tfrac = 'tfrac'
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The fraction class make possible to handle
|
|
12
|
+
* \\(\frac{a}{b}\\) or \\[\frac{a}{b}\\] values.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export class Fraction implements IPiMathObject<Fraction>, IExpression<Fraction> {
|
|
16
|
+
#denominator = 1
|
|
17
|
+
#digits = 3
|
|
18
|
+
#exact = true
|
|
19
|
+
#numerator = 1
|
|
20
|
+
#type: FRAC_TYPE = FRAC_TYPE.frac
|
|
21
|
+
#withSign = false
|
|
22
|
+
|
|
23
|
+
constructor()
|
|
24
|
+
constructor(value: InputValue<Fraction>)
|
|
25
|
+
constructor(numerator: number, denominator: number)
|
|
26
|
+
constructor(value?: InputValue<Fraction>, denominator?: number) {
|
|
27
|
+
|
|
28
|
+
if (value !== undefined) {
|
|
29
|
+
this.parse(value, denominator)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return this
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ------------------------------------------
|
|
36
|
+
/**
|
|
37
|
+
* Parse the value to get the numerator and denominator
|
|
38
|
+
* @param value : number or string to parse to get the fraction
|
|
39
|
+
*/
|
|
40
|
+
public parse = (value: InputValue<Fraction>, denominator?: number): this => {
|
|
41
|
+
|
|
42
|
+
// A null value means a zero fraction.
|
|
43
|
+
if (value === "") {
|
|
44
|
+
this.#numerator = 0
|
|
45
|
+
this.#denominator = 1
|
|
46
|
+
return this
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (typeof value === "string") {
|
|
50
|
+
return this.fromString(value)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (typeof value === "number" && denominator===undefined) {
|
|
54
|
+
return this.fromNumber(value)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (typeof value === "number" && typeof denominator==="number") {
|
|
58
|
+
return this.fromNumbers(value, denominator)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (value instanceof Fraction) {
|
|
62
|
+
return this.copy(value)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return this
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public clone = (): Fraction => {
|
|
69
|
+
const F = new Fraction()
|
|
70
|
+
F.numerator = this.#numerator
|
|
71
|
+
F.denominator = this.#denominator
|
|
72
|
+
F.exact = this.exact
|
|
73
|
+
return F
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
public copy(value: Fraction): this {
|
|
77
|
+
this.#numerator = value.numerator
|
|
78
|
+
this.#denominator = value.denominator
|
|
79
|
+
this.#exact = value.exact
|
|
80
|
+
|
|
81
|
+
return this
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public get tex(): string {
|
|
85
|
+
if (this.isInfinity()) {
|
|
86
|
+
return `${this.sign() === 1 ? '+' : '-'}\\infty`
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const plus = this.#withSign && this.isPositive() ? '+' : ''
|
|
90
|
+
|
|
91
|
+
if (this.exact) {
|
|
92
|
+
if (this.#denominator === 1) {
|
|
93
|
+
return `${plus}${this.#numerator}`
|
|
94
|
+
} else if (this.#numerator < 0) {
|
|
95
|
+
return `-\\${this.#type}{ ${-this.#numerator} }{ ${this.#denominator} }`
|
|
96
|
+
} else {
|
|
97
|
+
return `${plus}\\${this.#type}{ ${this.#numerator} }{ ${this.#denominator} }`
|
|
98
|
+
}
|
|
99
|
+
} else {
|
|
100
|
+
return plus + this.value.toFixed(this.#digits)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
public get display(): string {
|
|
105
|
+
if (this.isInfinity()) {
|
|
106
|
+
return `${this.sign() === 1 ? '+' : '-'}oo`
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const plus = this.#withSign && this.isPositive() ? '+' : ''
|
|
110
|
+
|
|
111
|
+
if (this.exact) {
|
|
112
|
+
if (this.#denominator === 1) {
|
|
113
|
+
return `${plus}${this.#numerator}`
|
|
114
|
+
} else {
|
|
115
|
+
return `${plus}${this.#numerator}/${this.#denominator}`
|
|
116
|
+
}
|
|
117
|
+
} else {
|
|
118
|
+
return plus + this.value.toFixed(this.#digits)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
public static average = (...fractions: (InputValue<Fraction>)[]): Fraction => {
|
|
123
|
+
const M = new Fraction().zero()
|
|
124
|
+
|
|
125
|
+
for (const f of fractions) {
|
|
126
|
+
M.add(f)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
M.divide(fractions.length)
|
|
130
|
+
|
|
131
|
+
return M
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
public static isFraction(value: InputValue<Fraction>) {
|
|
135
|
+
if (value instanceof Fraction ||
|
|
136
|
+
(typeof value === "number" && !isNaN(value))
|
|
137
|
+
) {
|
|
138
|
+
return true
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (typeof value === "string") {
|
|
142
|
+
const [num, den] = value.split('/')
|
|
143
|
+
|
|
144
|
+
return !isNaN(+num) && !isNaN(+den)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return false
|
|
148
|
+
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
public static max = (...fractions: InputValue<Fraction>[]): Fraction => {
|
|
152
|
+
let M = new Fraction(fractions[0])
|
|
153
|
+
|
|
154
|
+
for (const m of fractions) {
|
|
155
|
+
const compare = new Fraction(m)
|
|
156
|
+
if (compare.isGreater(M)) {
|
|
157
|
+
M = compare.clone()
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return M
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
public static min = (...fractions: (InputValue<Fraction>)[]): Fraction => {
|
|
165
|
+
let M = new Fraction(fractions[0])
|
|
166
|
+
|
|
167
|
+
for (const m of fractions) {
|
|
168
|
+
const compare = new Fraction(m)
|
|
169
|
+
if (compare.isLesser(M)) {
|
|
170
|
+
M = compare.clone()
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return M
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
public static sort = (fractions: (InputValue<Fraction>)[], reverse?: boolean): Fraction[] => {
|
|
178
|
+
const fractionsObject: Fraction[] = fractions.map(f => f instanceof Fraction ? f : new Fraction(f))
|
|
179
|
+
|
|
180
|
+
const sorted = fractionsObject.sort((a, b) => a.value - b.value)
|
|
181
|
+
|
|
182
|
+
if (reverse) {
|
|
183
|
+
sorted.reverse()
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return sorted
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
public static toSameDenominateur(...fractions: InputValue<Fraction>[]): Fraction[] {
|
|
190
|
+
const F = fractions.map(x => new Fraction(x))
|
|
191
|
+
const lcm = Numeric.lcm(...F.map(x => x.denominator))
|
|
192
|
+
|
|
193
|
+
F.forEach(x => x.amplify(lcm / x.denominator))
|
|
194
|
+
|
|
195
|
+
return F
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
public static unique = (fractions: (InputValue<Fraction>)[]): Fraction[] => {
|
|
199
|
+
const unique: Record<string, boolean> = {},
|
|
200
|
+
distinct: Fraction[] = []
|
|
201
|
+
|
|
202
|
+
fractions.forEach(x => {
|
|
203
|
+
if (!(x instanceof Fraction)) {
|
|
204
|
+
x = new Fraction(x)
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (!unique[x.clone().reduce().tex]) {
|
|
208
|
+
distinct.push(x.clone())
|
|
209
|
+
unique[x.tex] = true
|
|
210
|
+
}
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
return distinct
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
public static xMultiply = (...values: (InputValue<Fraction>)[]): Fraction => {
|
|
217
|
+
const R = new Fraction()
|
|
218
|
+
|
|
219
|
+
values.forEach(f=> R.multiply(f, false))
|
|
220
|
+
|
|
221
|
+
return R
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
public abs = (): this => {
|
|
225
|
+
this.#numerator = Math.abs(this.#numerator)
|
|
226
|
+
this.#denominator = Math.abs(this.#denominator)
|
|
227
|
+
return this
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
public add = (F: InputValue<Fraction>): Fraction => {
|
|
231
|
+
if (F instanceof Fraction) {
|
|
232
|
+
const N: number = this.#numerator,
|
|
233
|
+
D: number = this.#denominator
|
|
234
|
+
|
|
235
|
+
this.#numerator = N * F.denominator + F.numerator * D
|
|
236
|
+
this.#denominator = D * F.denominator
|
|
237
|
+
this.exact = this.exact && F.exact
|
|
238
|
+
} else {
|
|
239
|
+
return this.add(new Fraction(F))
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return this.reduce()
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
public amplify = (k: number): this => {
|
|
246
|
+
if (Number.isSafeInteger(k)) {
|
|
247
|
+
this.#numerator *= k
|
|
248
|
+
this.#denominator *= k
|
|
249
|
+
}
|
|
250
|
+
return this
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
public areEquals = (...F: Fraction[]): boolean => {
|
|
254
|
+
return F.every(f => f.isEqual(F[0]))
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Compare the current coefficient with another coefficient
|
|
259
|
+
* @param F (Coefficient) The coefficient to _compare
|
|
260
|
+
* @param sign (string| default is =): authorized values: =, <, <=, >, >= with some variations.
|
|
261
|
+
*/
|
|
262
|
+
public compare = (F: InputValue<Fraction>, sign?: compareSign): boolean => {
|
|
263
|
+
sign ??= '='
|
|
264
|
+
|
|
265
|
+
let compareFraction: Fraction
|
|
266
|
+
if (F instanceof Fraction) {
|
|
267
|
+
compareFraction = F.clone()
|
|
268
|
+
} else {
|
|
269
|
+
compareFraction = new Fraction(F)
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
switch (sign) {
|
|
273
|
+
case '>':
|
|
274
|
+
return this.value > compareFraction.value
|
|
275
|
+
case ">=":
|
|
276
|
+
case "=>":
|
|
277
|
+
case "geq":
|
|
278
|
+
return this.value >= compareFraction.value
|
|
279
|
+
case "<":
|
|
280
|
+
return this.value < compareFraction.value
|
|
281
|
+
case "<=":
|
|
282
|
+
case "=<":
|
|
283
|
+
case "leq":
|
|
284
|
+
return this.value <= compareFraction.value
|
|
285
|
+
case "=":
|
|
286
|
+
return this.value === compareFraction.value
|
|
287
|
+
case "<>":
|
|
288
|
+
return this.value !== compareFraction.value
|
|
289
|
+
default:
|
|
290
|
+
return false
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
public get denominator(): number {
|
|
295
|
+
return this.#denominator
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
public set denominator(value: number) {
|
|
299
|
+
this.#denominator = value
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
public get dfrac(): this {
|
|
303
|
+
this.#type = FRAC_TYPE.dfrac
|
|
304
|
+
return this
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
digits(value: number): this {
|
|
308
|
+
this.#digits = value
|
|
309
|
+
return this
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
public divide = (F: Fraction | number): Fraction => {
|
|
313
|
+
const Q = new Fraction(F)
|
|
314
|
+
|
|
315
|
+
if (Q.numerator === 0) {
|
|
316
|
+
return new Fraction().infinite()
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const N: number = this.#numerator,
|
|
320
|
+
D: number = this.#denominator
|
|
321
|
+
|
|
322
|
+
this.#numerator = N * Q.denominator
|
|
323
|
+
this.#denominator = D * Q.numerator
|
|
324
|
+
|
|
325
|
+
this.exact = this.exact && Q.exact
|
|
326
|
+
return this.reduce()
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
get exact(): boolean {
|
|
330
|
+
return this.#exact
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
set exact(value: boolean) {
|
|
334
|
+
this.#exact = value
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
public get frac(): this {
|
|
338
|
+
this.#type = FRAC_TYPE.frac
|
|
339
|
+
return this
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
public fromNumber(value: number): this {
|
|
343
|
+
if (Number.isSafeInteger(value)) {
|
|
344
|
+
// The given value is an integer
|
|
345
|
+
this.#numerator = value
|
|
346
|
+
this.#denominator = 1
|
|
347
|
+
this.#exact = true
|
|
348
|
+
return this
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// The given value is a float number
|
|
352
|
+
// Get the number of decimals after the float sign
|
|
353
|
+
const [, decimal] = (value.toString()).split('.')
|
|
354
|
+
const p: number = decimal ? decimal.length : 0
|
|
355
|
+
const power = Math.pow(10, p)
|
|
356
|
+
|
|
357
|
+
this.#numerator = value * power
|
|
358
|
+
this.#denominator = power
|
|
359
|
+
|
|
360
|
+
this.#numerator = Numeric.numberCorrection(this.#numerator)
|
|
361
|
+
this.#denominator = Numeric.numberCorrection(this.#denominator)
|
|
362
|
+
|
|
363
|
+
this.reduce()
|
|
364
|
+
|
|
365
|
+
// assume it's not exact if the decimal part is more than 10 decimals
|
|
366
|
+
this.#exact = p < 10
|
|
367
|
+
|
|
368
|
+
return this
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
public fromNumbers(numerator: number, denominator: number): this {
|
|
372
|
+
if (Number.isSafeInteger(numerator) && Number.isSafeInteger(denominator)) {
|
|
373
|
+
// The given value is an integer
|
|
374
|
+
this.#numerator = numerator
|
|
375
|
+
this.#denominator = denominator
|
|
376
|
+
this.#exact = true
|
|
377
|
+
return this
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
return this.fromNumber(numerator / denominator)
|
|
381
|
+
}
|
|
382
|
+
public fromPeriodic(value: string | number, length: number): this {
|
|
383
|
+
const [, decimal] = (value.toString()).split(/[.,]/)
|
|
384
|
+
const p: number = decimal ? decimal.length : 0
|
|
385
|
+
const power = Math.pow(10, p)
|
|
386
|
+
|
|
387
|
+
this.#numerator = (+value) * power - Math.floor((+value) * Math.pow(10, p - length))
|
|
388
|
+
this.#denominator = power - Math.pow(10, p - length)
|
|
389
|
+
this.#exact = true
|
|
390
|
+
|
|
391
|
+
return this
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
public fromString(value: string): this {
|
|
395
|
+
// Split the string value in two parts: Numerator/Denominator
|
|
396
|
+
const S = value.split('/').map(Number)
|
|
397
|
+
|
|
398
|
+
this.#exact = true
|
|
399
|
+
|
|
400
|
+
// Only one divide sign allowed
|
|
401
|
+
if (S.length > 2) {
|
|
402
|
+
this.#numerator = NaN
|
|
403
|
+
return this
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// Each parts must be a number
|
|
407
|
+
if (S.some(x => isNaN(x))) {
|
|
408
|
+
this.#numerator = NaN
|
|
409
|
+
return this
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
if (S.length === 1) {
|
|
413
|
+
// No divide sign - it's a number
|
|
414
|
+
return this.fromNumber(+value)
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// One divide signe
|
|
418
|
+
// We check if the denominator is zero
|
|
419
|
+
if (S[1] === 0) {
|
|
420
|
+
this.#numerator = NaN
|
|
421
|
+
this.#denominator = 1
|
|
422
|
+
return this
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
this.#numerator = S[0]
|
|
426
|
+
this.#denominator = S[1]
|
|
427
|
+
|
|
428
|
+
return this
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
public infinite = (): this => {
|
|
432
|
+
this.#numerator = Infinity
|
|
433
|
+
this.#denominator = 1
|
|
434
|
+
this.exact = true
|
|
435
|
+
return this
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
public invalid = (): this => {
|
|
439
|
+
this.#numerator = NaN
|
|
440
|
+
this.#denominator = 1
|
|
441
|
+
this.exact = true
|
|
442
|
+
return this
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
public inverse = (): this => {
|
|
446
|
+
const sign = this.sign()
|
|
447
|
+
const n = Math.abs(this.#numerator)
|
|
448
|
+
this.#numerator = Math.abs(this.#denominator) * sign
|
|
449
|
+
this.#denominator = n
|
|
450
|
+
|
|
451
|
+
return this
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
public isEqual = (than: Fraction | number): boolean => {
|
|
455
|
+
return this.compare(than, '=')
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
public isEven = (): boolean => {
|
|
459
|
+
return this.isRelative() && this.value % 2 === 0
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
public isFinite = (): boolean => {
|
|
463
|
+
return !this.isInfinity() && !this.isNaN()
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
public isGeq = (than: Fraction | number): boolean => {
|
|
467
|
+
return this.compare(than, '>=')
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
public isGreater = (than: Fraction | number): boolean => {
|
|
471
|
+
return this.compare(than, '>')
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
public isInfinity = (): boolean => {
|
|
475
|
+
return Math.abs(this.#numerator) === Infinity
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
public isLeq = (than: Fraction | number): boolean => {
|
|
479
|
+
return this.compare(than, '<=')
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
public isLesser = (than: Fraction | number): boolean => {
|
|
483
|
+
return this.compare(than, '<')
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
public isNaN = (): boolean => {
|
|
487
|
+
return isNaN(this.#numerator)
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
public isNatural = (): boolean => {
|
|
491
|
+
return this.isRelative() && this.isPositive()
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
public isNegative = (): boolean => {
|
|
495
|
+
return this.sign() === -1
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
public isNotEqual = (than: Fraction | number): boolean => {
|
|
499
|
+
return this.compare(than, '<>')
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
public isNotZero = (): boolean => {
|
|
503
|
+
return this.#numerator !== 0
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
public isOdd = (): boolean => {
|
|
507
|
+
return this.isRelative() && this.value % 2 === 1
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
public isOne = (): boolean => {
|
|
511
|
+
return this.#numerator === 1 && this.#denominator === 1
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
public isPositive = (): boolean => {
|
|
515
|
+
return this.sign() === 1
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
public isRational = (): boolean => {
|
|
519
|
+
return this.exact && !this.isRelative()
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
public isReduced = (): boolean => {
|
|
523
|
+
return Math.abs(Numeric.gcd(this.#numerator, this.#denominator)) === 1
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
public isRelative = (): boolean => {
|
|
527
|
+
return this.exact && this.clone().reduce().denominator === 1
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
public isSquare = (): boolean => {
|
|
531
|
+
return Math.sqrt(this.#numerator) % 1 === 0 && Math.sqrt(this.#denominator) % 1 === 0
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
public isStrictlyNegative = (): boolean => {
|
|
535
|
+
return this.value < 0
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
public isStrictlyPositive = (): boolean => {
|
|
539
|
+
return this.value > 0
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
public isUnit(): boolean {
|
|
543
|
+
return Math.abs(this.#numerator) === 1 && this.#denominator === 1
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// Mathematical operations specific to fractions
|
|
547
|
+
public isZero = (): boolean => {
|
|
548
|
+
return this.#numerator === 0
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
public multiply = (F: InputValue<Fraction>, reduce = true): this => {
|
|
552
|
+
// Parse the value.
|
|
553
|
+
// If it's a fraction, return a clone of it
|
|
554
|
+
// If it's an integer, return the fraction F/1
|
|
555
|
+
const Q = new Fraction(F)
|
|
556
|
+
|
|
557
|
+
this.#numerator = this.#numerator * Q.numerator
|
|
558
|
+
this.#denominator = this.#denominator * Q.denominator
|
|
559
|
+
|
|
560
|
+
this.exact = this.exact && Q.exact
|
|
561
|
+
|
|
562
|
+
return reduce ? this.reduce() : this
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// ------------------------------------------
|
|
566
|
+
public get numerator(): number {
|
|
567
|
+
return this.#numerator
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
public set numerator(value: number) {
|
|
571
|
+
this.#numerator = value
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
public one = (): this => {
|
|
575
|
+
return this.fromNumber(1)
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
public opposite = (): this => {
|
|
579
|
+
this.#numerator = -this.#numerator
|
|
580
|
+
return this
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
public pow = (p: number | Fraction): Fraction => {
|
|
584
|
+
if (p instanceof Fraction) {
|
|
585
|
+
return this.pow(p.value)
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
this.reduce()
|
|
589
|
+
if (p < 0) {
|
|
590
|
+
this.inverse()
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
// Check if numerator and denominator are roots of...
|
|
594
|
+
// otherwise, convert to numeric.
|
|
595
|
+
const controlNumerator = Math.floor(Math.pow(this.#numerator, Math.abs(p))),
|
|
596
|
+
controlDenominator = Math.floor(Math.pow(this.#denominator, Math.abs(p)))
|
|
597
|
+
|
|
598
|
+
if (controlNumerator ** Math.abs(p) === this.#numerator
|
|
599
|
+
&&
|
|
600
|
+
controlDenominator ** Math.abs(p) === this.#denominator) {
|
|
601
|
+
this.#numerator = this.#numerator ** Math.abs(p)
|
|
602
|
+
this.#denominator = this.#denominator ** Math.abs(p)
|
|
603
|
+
} else {
|
|
604
|
+
this.#numerator = this.#numerator ** Math.abs(p)
|
|
605
|
+
this.#denominator = this.#denominator ** Math.abs(p)
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
return this
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
public reduce = (): this => {
|
|
612
|
+
const g = Numeric.gcd(this.#numerator, this.#denominator)
|
|
613
|
+
this.#numerator = this.#numerator / g
|
|
614
|
+
this.#denominator = this.#denominator / g
|
|
615
|
+
|
|
616
|
+
if (this.#denominator < 0) {
|
|
617
|
+
this.#denominator = -this.#denominator
|
|
618
|
+
this.#numerator = -this.#numerator
|
|
619
|
+
}
|
|
620
|
+
return this
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
public root = (p: number): this => {
|
|
624
|
+
|
|
625
|
+
// Check if they are perfect roots..
|
|
626
|
+
if (p === 0) {
|
|
627
|
+
return this
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// If negative, inverse the fraction
|
|
631
|
+
if (p < 0) {
|
|
632
|
+
this.inverse()
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// if p is not a safe integer, throw error
|
|
636
|
+
if (!Number.isSafeInteger(p)) {
|
|
637
|
+
throw new Error("The root must be an integer.")
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// if the fraction is negative and the root is even, throw error
|
|
641
|
+
if (this.isNegative() && p % 2 === 0) {
|
|
642
|
+
throw new Error("The root of a negative number must be odd.")
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
// get the sign of the fraction and make it positive
|
|
646
|
+
const sign = this.sign()
|
|
647
|
+
this.abs()
|
|
648
|
+
|
|
649
|
+
// Reduce the fraction
|
|
650
|
+
this.reduce()
|
|
651
|
+
|
|
652
|
+
// Check if numerator and denominator are roots of...
|
|
653
|
+
// otherwise, convert to numeric.
|
|
654
|
+
const controlNumerator = Math.floor(Math.pow(this.#numerator, Math.abs(1 / p))),
|
|
655
|
+
controlDenominator = Math.floor(Math.pow(this.#denominator, Math.abs(1 / p)))
|
|
656
|
+
|
|
657
|
+
this.#numerator = Math.pow(this.#numerator, Math.abs(1 / p))
|
|
658
|
+
this.#denominator = Math.pow(this.#denominator, Math.abs(1 / p))
|
|
659
|
+
|
|
660
|
+
if (controlNumerator !== this.#numerator
|
|
661
|
+
||
|
|
662
|
+
controlDenominator !== this.#denominator) {
|
|
663
|
+
// The fraction is not a perfect root - make it approximative
|
|
664
|
+
this.#numerator = this.#numerator / this.#denominator
|
|
665
|
+
this.#denominator = 1
|
|
666
|
+
this.exact = false
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
// Restore the sign
|
|
670
|
+
this.multiply(sign)
|
|
671
|
+
|
|
672
|
+
return this
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
public sign = (): 1 | -1 => {
|
|
676
|
+
return (this.#numerator * this.#denominator >= 0) ? 1 : -1
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
public sqrt = (): this => {
|
|
680
|
+
return this.root(2)
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
public subtract = (F: Fraction | number): Fraction => {
|
|
684
|
+
if (F instanceof Fraction) {
|
|
685
|
+
return this.add(F.clone().opposite())
|
|
686
|
+
} else {
|
|
687
|
+
return this.add(-F)
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
public get texWithSign(): string {
|
|
692
|
+
return this.isPositive() ? `+${this.tex}` : this.tex
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
public get tfrac(): this {
|
|
696
|
+
this.#type = FRAC_TYPE.tfrac
|
|
697
|
+
return this
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
public get value(): number {
|
|
701
|
+
const result = this.#numerator / this.#denominator
|
|
702
|
+
return result === 0 ? 0 : result
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
get withSign(): this {
|
|
706
|
+
this.#withSign = true
|
|
707
|
+
return this
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
get withoutSign(): this {
|
|
711
|
+
this.#withSign = false
|
|
712
|
+
return this
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
public zero = (): this => {
|
|
716
|
+
return this.fromNumber(0)
|
|
717
|
+
}
|
|
718
|
+
}
|