pimath 0.0.40 → 0.0.41
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/pi.js +288 -92
- package/dist/pi.js.map +1 -1
- package/dist/pi.min.js +1 -1
- package/dist/pi.min.js.map +1 -1
- package/docs/assets/search.js +1 -1
- package/esm/index.d.ts +2 -2
- package/esm/index.js +2 -2
- package/esm/maths/algebra/equation.d.ts +6 -2
- package/esm/maths/algebra/equation.js +49 -9
- package/esm/maths/algebra/equation.js.map +1 -1
- package/esm/maths/algebra/polynom.d.ts +2 -1
- package/esm/maths/algebra/polynom.js +98 -62
- package/esm/maths/algebra/polynom.js.map +1 -1
- package/esm/maths/algebra/rational.d.ts +10 -0
- package/esm/maths/algebra/rational.js +101 -10
- package/esm/maths/algebra/rational.js.map +1 -1
- package/esm/maths/coefficients/fraction.d.ts +3 -1
- package/esm/maths/coefficients/fraction.js +33 -4
- package/esm/maths/coefficients/fraction.js.map +1 -1
- package/esm/maths/coefficients/{nthroot.d.ts → nthRoot.d.ts} +5 -5
- package/esm/maths/coefficients/{nthroot.js → nthRoot.js} +5 -5
- package/esm/maths/coefficients/{nthroot.js.map → nthRoot.js.map} +1 -1
- package/package.json +1 -1
- package/src/index.ts +2 -2
- package/src/maths/algebra/equation.ts +58 -12
- package/src/maths/algebra/polynom.ts +100 -68
- package/src/maths/algebra/rational.ts +136 -20
- package/src/maths/coefficients/fraction.ts +39 -5
- package/src/maths/coefficients/{nthroot.ts → nthRoot.ts} +5 -5
- package/tests/algebra/equation.test.ts +38 -0
- package/tests/algebra/monom.test.ts +1 -4
- package/tests/algebra/rationnal.test.ts +29 -5
- package/tests/coefficients/fraction.test.ts +43 -1
- package/tests/geometry/circle.test.ts +4 -2
|
@@ -2,22 +2,28 @@ import {Polynom} from "./polynom";
|
|
|
2
2
|
import {literalType, Monom} from "./monom";
|
|
3
3
|
import {Numeric} from "../numeric";
|
|
4
4
|
import {Fraction} from "../coefficients/fraction";
|
|
5
|
-
import {
|
|
5
|
+
import {NthRoot} from "../coefficients/nthRoot";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Equation is a class to manage equations...
|
|
9
9
|
*/
|
|
10
|
-
interface ISolution {
|
|
10
|
+
export interface ISolution {
|
|
11
11
|
tex: string,
|
|
12
12
|
value: number,
|
|
13
13
|
exact: unknown
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
export enum PARTICULAR_SOLUTION {
|
|
17
|
+
real="\\mathbb{R}",
|
|
18
|
+
varnothing="\\varnothing"
|
|
19
|
+
}
|
|
20
|
+
|
|
16
21
|
export class Equation {
|
|
17
22
|
private _polynom: Polynom; // Used to solve the equation // TODO: remove the private value ?
|
|
23
|
+
|
|
18
24
|
// Undetermined texSolutions.
|
|
19
|
-
private _varnothing: string =
|
|
20
|
-
private _real: string =
|
|
25
|
+
private _varnothing: string = PARTICULAR_SOLUTION.varnothing;
|
|
26
|
+
private _real: string = PARTICULAR_SOLUTION.real;
|
|
21
27
|
|
|
22
28
|
/**
|
|
23
29
|
* Create an Equation using two polynoms.
|
|
@@ -397,9 +403,29 @@ export class Equation {
|
|
|
397
403
|
default:
|
|
398
404
|
this._solveDegree3plus();
|
|
399
405
|
}
|
|
406
|
+
|
|
407
|
+
// cleanup the solutions.
|
|
408
|
+
this._solutions = Equation.makeSolutionsUnique(this._solutions)
|
|
400
409
|
return this;
|
|
401
410
|
};
|
|
402
411
|
|
|
412
|
+
static makeSolutionsUnique(solutions: ISolution[], sorted?: boolean):ISolution[] {
|
|
413
|
+
let solutionAsTex:string[] = [],
|
|
414
|
+
uniqueSolutions = solutions.filter(sol=>{
|
|
415
|
+
if(!solutionAsTex.includes(sol.tex)){
|
|
416
|
+
solutionAsTex.push(sol.tex)
|
|
417
|
+
return true
|
|
418
|
+
}else{
|
|
419
|
+
return false
|
|
420
|
+
}
|
|
421
|
+
})
|
|
422
|
+
|
|
423
|
+
if(sorted===true){
|
|
424
|
+
uniqueSolutions.sort((a, b)=>a.value-b.value)
|
|
425
|
+
}
|
|
426
|
+
return uniqueSolutions
|
|
427
|
+
}
|
|
428
|
+
|
|
403
429
|
test = (values: literalType): Boolean => {
|
|
404
430
|
return this.left.evaluate(values).isEqual(this.right.evaluate(values))
|
|
405
431
|
}
|
|
@@ -526,12 +552,13 @@ export class Equation {
|
|
|
526
552
|
}
|
|
527
553
|
} else {
|
|
528
554
|
this._solutions = [{
|
|
529
|
-
tex: v.
|
|
555
|
+
tex: v.tex,
|
|
530
556
|
value: v.value,
|
|
531
557
|
exact: v
|
|
532
558
|
}]
|
|
533
559
|
}
|
|
534
|
-
}
|
|
560
|
+
}
|
|
561
|
+
else {
|
|
535
562
|
if (m1.value === 0) {
|
|
536
563
|
// In this case, the coefficient of the x variable is zero.
|
|
537
564
|
if (m0.value === 0 && this.isAlsoEqual()) {
|
|
@@ -565,7 +592,7 @@ export class Equation {
|
|
|
565
592
|
let aF = this._polynom.monomByDegree(2, letter).coefficient,
|
|
566
593
|
bF = this._polynom.monomByDegree(1, letter).coefficient,
|
|
567
594
|
cF = this._polynom.monomByDegree(0, letter).coefficient,
|
|
568
|
-
delta: number, nthDelta:
|
|
595
|
+
delta: number, nthDelta: NthRoot,
|
|
569
596
|
lcm = Numeric.lcm(aF.denominator, bF.denominator, cF.denominator),
|
|
570
597
|
a = aF.multiply(lcm).value,
|
|
571
598
|
b = bF.multiply(lcm).value,
|
|
@@ -594,7 +621,7 @@ export class Equation {
|
|
|
594
621
|
}
|
|
595
622
|
]
|
|
596
623
|
} else {
|
|
597
|
-
nthDelta = new
|
|
624
|
+
nthDelta = new NthRoot(delta).reduce();
|
|
598
625
|
if (nthDelta.hasRadical()) {
|
|
599
626
|
// -b +- coeff\sqrt{radical}
|
|
600
627
|
// -------------------------
|
|
@@ -696,7 +723,6 @@ export class Equation {
|
|
|
696
723
|
}];
|
|
697
724
|
}
|
|
698
725
|
|
|
699
|
-
|
|
700
726
|
// Handle now the inequations.
|
|
701
727
|
if (!this.isStrictEqual()) {
|
|
702
728
|
if (this._solutions.length === 2) {
|
|
@@ -763,9 +789,29 @@ export class Equation {
|
|
|
763
789
|
return this._solutions;
|
|
764
790
|
};
|
|
765
791
|
|
|
766
|
-
private _solveDegree3plus = (): ISolution[] => {
|
|
767
|
-
//
|
|
768
|
-
|
|
792
|
+
private _solveDegree3plus = (letter?: string): ISolution[] => {
|
|
793
|
+
// Push everything to the left
|
|
794
|
+
// factorize
|
|
795
|
+
// solve each factors.
|
|
796
|
+
let equ = this.clone().moveLeft()
|
|
797
|
+
equ.left.factorize()
|
|
798
|
+
|
|
799
|
+
this._solutions = []
|
|
800
|
+
|
|
801
|
+
equ.left.factors.forEach(factor=>{
|
|
802
|
+
if(factor.degree(letter).leq(2)) {
|
|
803
|
+
let factorAsEquation = new Equation(factor, 0)
|
|
804
|
+
factorAsEquation.solve()
|
|
805
|
+
factorAsEquation.solutions.forEach(solution => {
|
|
806
|
+
this._solutions.push(solution)
|
|
807
|
+
})
|
|
808
|
+
}else{
|
|
809
|
+
console.log(factor.tex, ': cannot actually get the solution of this equation')
|
|
810
|
+
}
|
|
811
|
+
})
|
|
812
|
+
|
|
813
|
+
// TODO: check equation resolution for more than degree 2
|
|
814
|
+
// this._solutions = [{tex: 'solve x - not yet handled', value: NaN, exact: false}]; // ESLint remove system :(
|
|
769
815
|
return this._solutions;
|
|
770
816
|
};
|
|
771
817
|
}
|
|
@@ -6,6 +6,7 @@ import {literalType, Monom} from './monom';
|
|
|
6
6
|
import {Shutingyard, ShutingyardType, Token} from '../shutingyard';
|
|
7
7
|
import {Numeric} from '../numeric';
|
|
8
8
|
import {Fraction} from "../coefficients/fraction";
|
|
9
|
+
import {Equation, ISolution} from "./equation";
|
|
9
10
|
|
|
10
11
|
export type PolynomParsingType = string | Polynom | number | Fraction | Monom
|
|
11
12
|
|
|
@@ -65,6 +66,9 @@ export class Polynom {
|
|
|
65
66
|
get texFactors(): string {
|
|
66
67
|
this.factorize()
|
|
67
68
|
|
|
69
|
+
if(this.factors.length===0){
|
|
70
|
+
return this.tex
|
|
71
|
+
}
|
|
68
72
|
let tex = ''
|
|
69
73
|
for (let f of this.factors) {
|
|
70
74
|
if (f.monoms.length > 1) {
|
|
@@ -773,6 +777,7 @@ export class Polynom {
|
|
|
773
777
|
}
|
|
774
778
|
|
|
775
779
|
let securityLoop = P.degree().clone().multiply(2).value
|
|
780
|
+
let result
|
|
776
781
|
// securityLoop = 0
|
|
777
782
|
|
|
778
783
|
while (securityLoop >= 0) {
|
|
@@ -791,8 +796,8 @@ export class Polynom {
|
|
|
791
796
|
for (let m1d of m1) {
|
|
792
797
|
for (let m2d of m2) {
|
|
793
798
|
// if(m1d.degree()===m2d.degree()){continue}
|
|
794
|
-
let dividerPolynom = new Polynom()
|
|
795
|
-
|
|
799
|
+
let dividerPolynom = new Polynom()
|
|
800
|
+
|
|
796
801
|
dividerPolynom.monoms = [m1d.clone(), m2d.clone()]
|
|
797
802
|
result = P.euclidian(dividerPolynom)
|
|
798
803
|
|
|
@@ -813,77 +818,104 @@ export class Polynom {
|
|
|
813
818
|
}
|
|
814
819
|
}
|
|
815
820
|
|
|
821
|
+
if(!P.isOne()){factors.push(P.clone())}
|
|
822
|
+
|
|
816
823
|
this.factors = factors
|
|
817
824
|
return factors;
|
|
818
825
|
}
|
|
819
826
|
|
|
820
827
|
// TODO: get zeroes for more than first degree and for more than natural degrees
|
|
821
|
-
getZeroes = ():
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
828
|
+
getZeroes = (): ISolution[] => {
|
|
829
|
+
let equ = new Equation(this.clone(), 0)
|
|
830
|
+
equ.solve()
|
|
831
|
+
return equ.solutions
|
|
832
|
+
|
|
833
|
+
//
|
|
834
|
+
// const Z: Fraction[] = [];
|
|
835
|
+
//
|
|
836
|
+
// // ISolution: {tex: string, value: number, exact: boolean|Fraction|...}
|
|
837
|
+
//
|
|
838
|
+
// switch (this.degree().value) {
|
|
839
|
+
// case 0:
|
|
840
|
+
// if (this._monoms[0].coefficient.value === 0) {
|
|
841
|
+
// return [{
|
|
842
|
+
// tex: '\\mathbb{R}',
|
|
843
|
+
// value: NaN,
|
|
844
|
+
// exact: false
|
|
845
|
+
// }];
|
|
846
|
+
// } else {
|
|
847
|
+
// return [{
|
|
848
|
+
// tex: '\\varnothing',
|
|
849
|
+
// value: NaN,
|
|
850
|
+
// exact: false
|
|
851
|
+
// }];
|
|
852
|
+
// }
|
|
853
|
+
// case 1:
|
|
854
|
+
// // There is only one monoms,
|
|
855
|
+
// if (this._monoms.length === 1) {
|
|
856
|
+
// return [{
|
|
857
|
+
// tex: '0',
|
|
858
|
+
// value: 0,
|
|
859
|
+
// exact: new Fraction().zero()
|
|
860
|
+
// }];
|
|
861
|
+
// } else {
|
|
862
|
+
// const P = this.clone().reduce().reorder();
|
|
863
|
+
// const coeff = P.monoms[1].coefficient.opposed().divide(P.monoms[0].coefficient)
|
|
864
|
+
// return [{
|
|
865
|
+
// tex: coeff.tex,
|
|
866
|
+
// value: coeff.value,
|
|
867
|
+
// exact: coeff
|
|
868
|
+
// }];
|
|
869
|
+
// }
|
|
870
|
+
// // TODO: Determine the zeros of an equation of second degree.
|
|
871
|
+
// //case 2:
|
|
872
|
+
// default:
|
|
873
|
+
// // Make sure the polynom is factorized.
|
|
874
|
+
// if (this._factors.length === 0) {
|
|
875
|
+
// this.factorize()
|
|
876
|
+
// }
|
|
877
|
+
//
|
|
878
|
+
// let zeroes:Fraction[] = [], zeroesAsTex = [];
|
|
879
|
+
// for (let P of this._factors) {
|
|
880
|
+
// if (P.degree().greater(2)) {
|
|
881
|
+
// // TODO: get zeroes of polynom with a degree greater than 2.
|
|
882
|
+
//
|
|
883
|
+
// } else if (P.degree().value === 2) {
|
|
884
|
+
// let A = P.monomByDegree(2).coefficient,
|
|
885
|
+
// B = P.monomByDegree(1).coefficient,
|
|
886
|
+
// C = P.monomByDegree(0).coefficient,
|
|
887
|
+
// D = B.clone().pow(2).subtract(A.clone().multiply(C).multiply(4));
|
|
888
|
+
//
|
|
889
|
+
// if (D.value > 0) {
|
|
890
|
+
// /*console.log('Two zeroes for ', P.tex); */
|
|
891
|
+
// let x1 = (-(B.value) + Math.sqrt(D.value)) / (2 * A.value),
|
|
892
|
+
// x2 = (-(B.value) - Math.sqrt(D.value)) / (2 * A.value);
|
|
893
|
+
//
|
|
894
|
+
// zeroes.push(new Fraction(x1.toFixed(3)).reduce());
|
|
895
|
+
// zeroes.push(new Fraction(x2.toFixed(3)).reduce());
|
|
896
|
+
// } else if (D.value === 0) {
|
|
897
|
+
// /*console.log('One zero for ', P.tex); */
|
|
898
|
+
// } else {
|
|
899
|
+
// console.log('No zero for ', P.tex);
|
|
900
|
+
// }
|
|
901
|
+
// } else {
|
|
902
|
+
// for (let z of P.getZeroes()) {
|
|
903
|
+
// // Check if the zero is already in the list.
|
|
904
|
+
// // if (z === false || z === true) {
|
|
905
|
+
// // continue;
|
|
906
|
+
// // }
|
|
907
|
+
// if (zeroesAsTex.indexOf(z.frac) === -1) {
|
|
908
|
+
// zeroes.push(z);
|
|
909
|
+
// zeroesAsTex.push(z.frac);
|
|
910
|
+
// }
|
|
911
|
+
// }
|
|
912
|
+
// }
|
|
913
|
+
// }
|
|
914
|
+
//
|
|
915
|
+
//
|
|
916
|
+
// return zeroes;
|
|
917
|
+
// }
|
|
918
|
+
// return Z;
|
|
887
919
|
};
|
|
888
920
|
|
|
889
921
|
// TODO: analyse the next functions to determine if they are useful or not...
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import {Polynom} from "./polynom";
|
|
7
7
|
import {Fraction} from "../coefficients/fraction";
|
|
8
8
|
import {literalType} from "./monom";
|
|
9
|
-
import {
|
|
9
|
+
import {Equation, ISolution, PARTICULAR_SOLUTION} from "./equation";
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Rational class can handle rational polynoms
|
|
@@ -41,9 +41,6 @@ export class Rational {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
get texFactors(): string {
|
|
44
|
-
this._numerator.factorize()
|
|
45
|
-
this._denominator.factorize()
|
|
46
|
-
|
|
47
44
|
return `\\dfrac{ ${this._numerator.texFactors} }{ ${this._denominator.texFactors} }`
|
|
48
45
|
}
|
|
49
46
|
|
|
@@ -56,16 +53,13 @@ export class Rational {
|
|
|
56
53
|
|
|
57
54
|
domain = (): string => {
|
|
58
55
|
let zeroes = this._denominator.getZeroes();
|
|
59
|
-
if (zeroes.length === 0 || zeroes[0] ===
|
|
60
|
-
return
|
|
61
|
-
} else if (zeroes[0] ===
|
|
62
|
-
return
|
|
56
|
+
if (zeroes.length === 0 || zeroes[0].tex === PARTICULAR_SOLUTION.real) {
|
|
57
|
+
return PARTICULAR_SOLUTION.real
|
|
58
|
+
} else if (zeroes[0].tex === PARTICULAR_SOLUTION.varnothing) {
|
|
59
|
+
return PARTICULAR_SOLUTION.varnothing
|
|
63
60
|
} else {
|
|
64
61
|
return '\\mathbb{R}\\setminus\\left{' +
|
|
65
|
-
zeroes.map(x =>
|
|
66
|
-
return (typeof x === 'boolean') ? '' : x.frac
|
|
67
|
-
})
|
|
68
|
-
.join(';') + '\\right}'
|
|
62
|
+
zeroes.map(x => x.tex).join(';') + '\\right}'
|
|
69
63
|
}
|
|
70
64
|
}
|
|
71
65
|
|
|
@@ -76,6 +70,18 @@ export class Rational {
|
|
|
76
70
|
return this;
|
|
77
71
|
}
|
|
78
72
|
|
|
73
|
+
derivative = (letter?: string): Rational => {
|
|
74
|
+
let N = this._numerator.clone(),
|
|
75
|
+
D = this._denominator.clone(),
|
|
76
|
+
dN = N.clone().derivative(letter),
|
|
77
|
+
dD = D.clone().derivative(letter)
|
|
78
|
+
|
|
79
|
+
this._numerator = dN.clone().multiply(D).subtract(N.clone().multiply(dD))
|
|
80
|
+
this._denominator = D.clone().pow(2)
|
|
81
|
+
|
|
82
|
+
return this
|
|
83
|
+
}
|
|
84
|
+
|
|
79
85
|
simplify = (P: Polynom): Rational => {
|
|
80
86
|
let NumeratorEuclidien = this._numerator.euclidian(P);
|
|
81
87
|
if (!NumeratorEuclidien.reminder.isZero()) {
|
|
@@ -131,14 +137,13 @@ export class Rational {
|
|
|
131
137
|
let {quotient, reminder} = this._numerator.clone().euclidian(this._denominator)
|
|
132
138
|
|
|
133
139
|
// quotient is positive => it will be infinite.
|
|
134
|
-
if(quotient.degree(letter).isStrictlyPositive()){
|
|
135
|
-
return value===Infinity ? quotient.limitToInfinity(letter):quotient.limitToNegativeInfinity(letter)
|
|
140
|
+
if (quotient.degree(letter).isStrictlyPositive()) {
|
|
141
|
+
return value === Infinity ? quotient.limitToInfinity(letter) : quotient.limitToNegativeInfinity(letter)
|
|
136
142
|
// return quotient.monomByDegree(undefined, letter).coefficient.sign()===1?(new Fraction()).infinite():(new Fraction()).infinite().opposed()
|
|
137
|
-
}else{
|
|
143
|
+
} else {
|
|
138
144
|
return quotient.monomByDegree(undefined, letter).coefficient
|
|
139
145
|
}
|
|
140
|
-
}
|
|
141
|
-
else {
|
|
146
|
+
} else {
|
|
142
147
|
let evalValues: literalType = {},
|
|
143
148
|
evalValuesOffset: literalType = {},
|
|
144
149
|
theLimit: Fraction | number,
|
|
@@ -151,7 +156,7 @@ export class Rational {
|
|
|
151
156
|
theLimit = FR._numerator.evaluate(evalValues)
|
|
152
157
|
.divide(FR._denominator.evaluate(evalValues))
|
|
153
158
|
|
|
154
|
-
return theLimit.isInfinity()?theLimit.abs():theLimit
|
|
159
|
+
return theLimit.isInfinity() ? theLimit.abs() : theLimit
|
|
155
160
|
} else {
|
|
156
161
|
if (offset === 'above') {
|
|
157
162
|
evalValuesOffset[letter === undefined ? 'x' : letter] = (new Fraction(value)).add(0.000001)
|
|
@@ -165,11 +170,122 @@ export class Rational {
|
|
|
165
170
|
.divide(FR._denominator.evaluate(evalValuesOffset)).sign()
|
|
166
171
|
|
|
167
172
|
if (theLimit.isInfinity()) {
|
|
168
|
-
return theSign===1?theLimit.abs():theLimit.abs().opposed()
|
|
169
|
-
}else{
|
|
173
|
+
return theSign === 1 ? theLimit.abs() : theLimit.abs().opposed()
|
|
174
|
+
} else {
|
|
170
175
|
return theLimit
|
|
171
176
|
}
|
|
172
177
|
}
|
|
173
178
|
}
|
|
174
179
|
}
|
|
180
|
+
|
|
181
|
+
makeTableOfSigns = (): { factors: Polynom[], zeroes: ISolution[], signs: (string[])[], tex: string } => {
|
|
182
|
+
// Factorize the numerator and the denominator
|
|
183
|
+
this._numerator.factorize()
|
|
184
|
+
this._denominator.factorize()
|
|
185
|
+
|
|
186
|
+
let zeroes = Equation.makeSolutionsUnique([...this._numerator.getZeroes(), ...this._denominator.getZeroes()], true),
|
|
187
|
+
NFactors = this._numerator.factors,
|
|
188
|
+
DFactors = this._denominator.factors
|
|
189
|
+
|
|
190
|
+
let tableOfSigns: (string[])[] = [],
|
|
191
|
+
result: string[] = []
|
|
192
|
+
|
|
193
|
+
NFactors.forEach(factor => {
|
|
194
|
+
tableOfSigns.push(this._makeOneLineOfTableOfSigns(factor, zeroes, 'z'))
|
|
195
|
+
})
|
|
196
|
+
DFactors.forEach(factor => {
|
|
197
|
+
tableOfSigns.push(this._makeOneLineOfTableOfSigns(factor, zeroes, 'd'))
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
// Empty line
|
|
201
|
+
tableOfSigns.push([])
|
|
202
|
+
|
|
203
|
+
// Add the final row as cumulative
|
|
204
|
+
let resultLine: string[] = tableOfSigns[0].map((x, index) => {
|
|
205
|
+
if (index === 0) {
|
|
206
|
+
return ''
|
|
207
|
+
}
|
|
208
|
+
if (index === tableOfSigns[0].length - 1) {
|
|
209
|
+
return ''
|
|
210
|
+
}
|
|
211
|
+
if (index % 2 === 0) {
|
|
212
|
+
return 't'
|
|
213
|
+
}
|
|
214
|
+
return '+'
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
for (let current of tableOfSigns) {
|
|
218
|
+
for (let i = 0; i < current.length; i++) {
|
|
219
|
+
if (i % 2 === 0) {
|
|
220
|
+
// t, z or d
|
|
221
|
+
if (resultLine[i] === 'd') {
|
|
222
|
+
continue
|
|
223
|
+
}
|
|
224
|
+
if (current[i] !== 't') {
|
|
225
|
+
resultLine[i] = current[i]
|
|
226
|
+
}
|
|
227
|
+
} else {
|
|
228
|
+
// + or -
|
|
229
|
+
if (current[i] === '-') {
|
|
230
|
+
resultLine[i] = resultLine[i] === '+' ? '-' : '+'
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Add the variation line.
|
|
237
|
+
// TODO: add the variation line.
|
|
238
|
+
|
|
239
|
+
tableOfSigns.push(resultLine)
|
|
240
|
+
|
|
241
|
+
let tos = {
|
|
242
|
+
factors: [...NFactors, ...DFactors],
|
|
243
|
+
zeroes: zeroes,
|
|
244
|
+
signs: tableOfSigns,
|
|
245
|
+
tex: ''
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
this._makeTexFromTableOfSigns(tos)
|
|
249
|
+
|
|
250
|
+
return tos
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
private _makeTexFromTableOfSigns = (tos: { factors: Polynom[], zeroes: ISolution[], signs: (string[])[], tex: string }): string => {
|
|
254
|
+
|
|
255
|
+
let tex = `\\begin{tikzpicture}
|
|
256
|
+
\\tkzTabInit[lgt=3,espcl=2,deltacl=0]{/1.2,\\(${tos.factors.map(x => x.tex).join('\\)/1,\\(')}\\)/1,/.1,\\(f(x)\\)/1.2}{{\\scriptsize \\hspace{1cm} \\(-\\infty\\)},\\(${tos.zeroes.map(x => x.tex).join('\\),\\(')}\\),{\\scriptsize \\hspace{-1cm} \\(+\\infty\\)}}`
|
|
257
|
+
tos.signs.forEach(list => {
|
|
258
|
+
tex += (`\n\\tkzTabLine{${list.join(',')}}`)
|
|
259
|
+
})
|
|
260
|
+
tex += `\n\\end{tikzpicture}`
|
|
261
|
+
|
|
262
|
+
tos.tex = tex
|
|
263
|
+
|
|
264
|
+
return tex
|
|
265
|
+
}
|
|
266
|
+
private _makeOneLineOfTableOfSigns = (factor: Polynom, zeroes: ISolution[], zeroSign: string): string[] => {
|
|
267
|
+
let oneLine: string[] = [],
|
|
268
|
+
// TODO : check if there is no zero ?
|
|
269
|
+
currentZero = factor.getZeroes().map(x=>x.tex)
|
|
270
|
+
|
|
271
|
+
// First +/- sign, before the first zero
|
|
272
|
+
oneLine.push('')
|
|
273
|
+
oneLine.push(factor.evaluate(zeroes[0].value - 1).sign() === 1 ? '+' : '-')
|
|
274
|
+
|
|
275
|
+
for (let i = 0; i < zeroes.length; i++) {
|
|
276
|
+
// Add the zero if it's the current one
|
|
277
|
+
oneLine.push(currentZero.includes(zeroes[i].tex) ? zeroSign : 't')
|
|
278
|
+
|
|
279
|
+
// + / - sign after the current zero
|
|
280
|
+
if (i < zeroes.length - 1) {
|
|
281
|
+
oneLine.push(factor.evaluate((zeroes[i].value + zeroes[i + 1].value) / 2).sign() === 1 ? '+' : '-')
|
|
282
|
+
} else if (i === zeroes.length - 1) {
|
|
283
|
+
oneLine.push(factor.evaluate(zeroes[i].value + 1).sign() === 1 ? '+' : '-')
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
}
|
|
287
|
+
oneLine.push('')
|
|
288
|
+
|
|
289
|
+
return oneLine
|
|
290
|
+
}
|
|
175
291
|
}
|
|
@@ -21,10 +21,6 @@ export class Fraction {
|
|
|
21
21
|
return this;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
get isFraction() {
|
|
25
|
-
return true;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
24
|
// ------------------------------------------
|
|
29
25
|
// Getter and setter
|
|
30
26
|
// ------------------------------------------
|
|
@@ -350,6 +346,44 @@ export class Fraction {
|
|
|
350
346
|
return M
|
|
351
347
|
}
|
|
352
348
|
|
|
349
|
+
static average = (...fractions: (Fraction|number)[]): Fraction => {
|
|
350
|
+
let M = new Fraction().zero()
|
|
351
|
+
|
|
352
|
+
for(let f of fractions){
|
|
353
|
+
M.add(f)
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
M.divide(fractions.length)
|
|
357
|
+
|
|
358
|
+
return M
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
static unique = (fractions: Fraction[], sorted?: boolean): Fraction[] => {
|
|
362
|
+
// TODO: make sure it's wokring -> test !
|
|
363
|
+
let unique:{[Key:string]:boolean} = {},
|
|
364
|
+
distinct: Fraction[] = []
|
|
365
|
+
fractions.forEach(x => {
|
|
366
|
+
if(!unique[x.clone().reduce().tex]){
|
|
367
|
+
distinct.push(x.clone())
|
|
368
|
+
unique[x.tex]=true
|
|
369
|
+
}
|
|
370
|
+
})
|
|
371
|
+
|
|
372
|
+
if(sorted) {
|
|
373
|
+
return Fraction.sort(distinct)
|
|
374
|
+
}else{
|
|
375
|
+
return distinct
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
static sort = (fractions: Fraction[], reverse?:boolean): Fraction[] => {
|
|
379
|
+
// Todo make sure it's the correct order, not reverse -> make a test
|
|
380
|
+
let sorted = fractions.sort((a, b)=>a.value-b.value)
|
|
381
|
+
|
|
382
|
+
if(reverse){sorted.reverse()}
|
|
383
|
+
|
|
384
|
+
return sorted
|
|
385
|
+
}
|
|
386
|
+
|
|
353
387
|
// ------------------------------------------
|
|
354
388
|
// Mathematical operations specific to fractions
|
|
355
389
|
// ------------------------------------------
|
|
@@ -470,7 +504,7 @@ export class Fraction {
|
|
|
470
504
|
return Math.abs(this._numerator) === Infinity;
|
|
471
505
|
}
|
|
472
506
|
isFinite = (): boolean => {
|
|
473
|
-
return !this.isInfinity();
|
|
507
|
+
return !this.isInfinity() && !this.isNaN();
|
|
474
508
|
}
|
|
475
509
|
isSquare = (): boolean => {
|
|
476
510
|
return Math.sqrt(this._numerator) % 1 === 0 && Math.sqrt(this._denominator) % 1 === 0
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* NthRoot is something like "a+b\sqrt{3}
|
|
3
3
|
*/
|
|
4
|
-
export class
|
|
4
|
+
export class NthRoot {
|
|
5
5
|
private _radical: number;
|
|
6
6
|
private _nth: number;
|
|
7
7
|
private _coefficient: number;
|
|
@@ -80,7 +80,7 @@ export class Nthroot {
|
|
|
80
80
|
// ------------------------------------------
|
|
81
81
|
// Creation / parsing functions
|
|
82
82
|
// ------------------------------------------
|
|
83
|
-
parse = (radical: number, nthroot?: number, coefficient?: number):
|
|
83
|
+
parse = (radical: number, nthroot?: number, coefficient?: number): NthRoot => {
|
|
84
84
|
this._coefficient = (coefficient === undefined) ? 1 : coefficient;
|
|
85
85
|
this._nth = (nthroot === undefined) ? 2 : nthroot;
|
|
86
86
|
this._radical = (radical === undefined) ? 1 : radical;
|
|
@@ -94,7 +94,7 @@ export class Nthroot {
|
|
|
94
94
|
// ------------------------------------------
|
|
95
95
|
// Mathematical operations
|
|
96
96
|
// ------------------------------------------
|
|
97
|
-
reduce = ():
|
|
97
|
+
reduce = (): NthRoot => {
|
|
98
98
|
// Max value to test.
|
|
99
99
|
let V = Math.floor(Math.pow(this._radical, 1 / this._nth));
|
|
100
100
|
while (V > 1) {
|
|
@@ -112,7 +112,7 @@ export class Nthroot {
|
|
|
112
112
|
return this;
|
|
113
113
|
};
|
|
114
114
|
|
|
115
|
-
multiply = (N:
|
|
115
|
+
multiply = (N: NthRoot): NthRoot => {
|
|
116
116
|
this._radical *= N.radical;
|
|
117
117
|
return this.reduce();
|
|
118
118
|
};
|