/**
* @method
* @file number.js
* @desc Perform common expression operations and provide fractional classes.
* @createDate 2018.7.11.
* @author yhzheng
*/
"use strict";
// require
var dataStruct = require("./dataStruct");
/**
* @var inf
* @desc This is for Express infinity
*/
// set default the value of inf
var inf = 100;
/**
* @class fractions
* @classdesc This is for Provides a fractional class object so that fractions can be computed.
* @desc It's for create object and init object.
*/
class fractions
{
constructor(info){
var denominator = info.denominator;
var numerator = info.numerator;
this.denominator = denominator;
this.numerator = numerator;
if (this.denominator === 0){
var err = new Error("Denominator can't is 0!");
throw err;
}
}
/**
* @method
* @returns number The value of this fractions
* @desc For get value of this fractions
*/
value(){
return (this.numerator / this.denominator);
}
/**
* @method
* @returns {fractions} This is the reduction fraction of this fraction
* @desc For get the reduction fraction of this fraction
*/
reduction(){
var newFractions = new fractions({
denominator: (this.denominator / maximum(this.denominator,this.numerator)),
numerator: (this.numerator / maximum(this.denominator,this.numerator))
});
return newFractions;
}
/**
* @method
* @desc For Set this fraction to he reduction fraction of this fraction
*/
toReduction(){
var reductionNumber = this.reduction();
this.denominator = reductionNumber.denominator;
this.numerator = reductionNumber.numerator;
}
}
/**
* @method
* @param {string} exp The expression of the string arithmetic.
* @returns number This is the result of your expression
* @desc For parse the expression of the string arithmetic and get the result.
*/
function expression(exp) {
var lines = exp.split("\n");
var exps = exp.split(/={5,}/g);
if (exps.length > 1){// many expressions
var reses = [];
for (var i = 0 ; i < exps.length ; i++){
reses.push(expression(exps[i]));
}
return reses;
} else {// just one expressions
if (exp.search(/[_\\]/g) === -1 && exp.search(/[a-zA-z]\s*\([\s\S]*\)\s*=/g) === -1 && exp.search(/={2,}/g) === -1 && exp.search(/-{2,}/g) === -1){// four arithmetic operation
/*
* {
* opt: "xx",
* priority: xx
* }
*/
exp = exp.replace(/\(\s*(-\d+\.{0,1}\d*\s*)\)/g,"0" + "$1");
var optArr = [
{opt: '+',priority: 1},
{opt: '-',priority: 1},
{opt: '*',priority: 2},
{opt: '/',priority: 2},
{opt: '%',priority: 2},
];
function priority(opt){
for(var i = 0 ; i < 4 ; i++)
if(opt == optArr[i].opt)
return optArr[i].priority;
return -1;
}
function isNum(c){
return c >= '0' && c <= '9';
}
function toNum(str,pos) {
var sztmp = "";
do {
sztmp += str.charAt(pos);
pos++;
} while((str[pos] >='0' && str[pos]<='9') || str[pos] == '.' || str[pos] == "^");
var sztmpArr = sztmp.split("^");
sztmp = sztmpArr[sztmpArr.length - 1] * 1;
for (var i = sztmpArr.length - 2 ; i >= 0 ; i--){
sztmp = Math.pow(sztmpArr[i] * 1,sztmp);
}
return {num: sztmp * 1,index: pos};
}
var num = new dataStruct.stack();
var opt = new dataStruct.stack();
var i = 0;
while (true){
if (exp.charAt(i).search(/\s/g) !== -1){
i++;
} else if (isNum(exp.charAt(i))){
var tmp = toNum(exp,i);
num.push(tmp.num);
i = tmp.index;
} else {
if (exp.length <= i && opt.empty()){
break;
}
if (opt.empty()){
opt.push(exp.charAt(i));
i++;
} else {
if (exp.charAt(i) == "(" || priority(exp.charAt(i)) > priority(opt.top())){
opt.push(exp.charAt(i));
i++;
} else if (exp.charAt(i) == ")" && opt.top() == "("){
opt.pop();
i++;
} else {
var opttmp = opt.top();
opt.pop();
var numa = num.top();
num.pop();
var numb = num.top();
num.pop();
var res;
switch (opttmp){
case "+":
res = numb + numa;
break;
case "-":
res = numb - numa;
break;
case "*":
res = numb * numa;
break;
case "/":
res = numb / numa;
break;
case "%":
res = numb % numa;
break;
default:
var err = new Error("Don't have this operator!");
throw err;
break;
}
num.push(res);
}
}
}
}
return num.top();
} else if (exp.search(/==/g) !== -1) {// sigma
/*
* style of sigma:
* z
* ==
* \
* | expression
* /
* ==
* x=y
*/
if (lines[1] != "==") {
var index;
var fills = [];
var tmp;
for (var i = 0; i < lines.length; i++) {
if (lines[i].search(/\s*==\s*/) !== -1) {
index = i - 1;
break;
}
}
for (var i = 0; i < index; i++) {
if (lines[i].search(/^\s*$/) !== -1)
continue;
tmp = lines[i].replace(/\s*(\S)\s*=\s*(\S)\s*/g, "$1=$2").split("=");
fills.push({
name: tmp[0],
value: tmp[1]
});
}
var count = lines[index];
if (count.search(/inf/g) !== -1 || count.search(/∞/g) !== -1) {
count = inf;
} else {
count *= 1;
}
var expression_ = "";
for (var i = (index + 3); i < (lines.length - 3); i++) {
expression_ += lines[i].replace(/^\s\|\s*([\s\S]*)/g, "$1");
if ((i + 1) < (lines.length - 3)) {
expression_ += "\n";
}
}
for (var i = 0 ; i < fills.length ; i++){
expression_ = expression.replace(new RegExp(fills[i].name),fills[i].value);
}
var lastLine = lines[lines.length - 1].split(/\s*=\s*/g);
return sigma(expression_, count, {
name: lastLine[0],
value: lastLine[1]
});
} else {
var count = lines[0];
if (count.search(/inf/g) !== -1 || count.search(/∞/g) !== -1) {
count = inf;
} else {
count *= 1;
}
var expression_ = "";
for (var i = 3; i < (lines.length - 3); i++) {
expression_ += lines[i].replace(/^\s\|\s*([\s\S]*)/g, "$1");
if ((i + 1) < (lines.length - 3)) {
expression_ += "\n";
}
}
var lastLine = lines[lines.length - 1].split(/\s*=\s*/g);
count++;
return sigma(expression_, count, {
name: lastLine[0],
value: lastLine[1]
});
}
} else if (exp.search(/-{3,}/g) !== -1){
var maxLine = "";
for (var i = 0 ; i < lines.length ; i++){
if (lines[i].search(/^-+$/g) !== -1){
if (lines[i].length > maxLine.length){
maxLine = lines[i];
}
}
}
var tmp = exp.split(maxLine);
var up = tmp[0],down = tmp[1];
return expression(up) / expression(down);
} else {
console.log("Now that this method is not available, you can send a brief introduction of the detailed information of this method to zhengyh2018@gmail.com by email, and we will understand the message as soon as possible and make improvements (please set the title to [emath add methods).)");
}
}
}
/**
* @method
* @param {number} num The value of inf
* @desc Set the value of inf
*/
function setInf(num) {
inf = num;
}
/**
* @method
* @param {string} exp The string expression of sigma
* @param {number} count The while count
* @param {object} init The information for init.
* @returns The sum of sigma
* @desc The sigma function<br/>
* Demo: sigma("i^2",3,{
* name: "i",
* value: 0
* });// return: 7
*/
function sigma(exp,count,init) {
var sum = 0;
var newExp;
for (var i = 0 ; i < count ; i++){
newExp = exp.replace(new RegExp(init.name),init.value);
sum += expression(newExp);
init.value++;
}
return sum;
}
/**
* @method
* @param {number} a First number
* @param {number} b Second number
* @returns The maximum common factor of a and b
* @desc To get the maximum common factor of a and b
*/
function MCF(a,b) {
var primeOfA = primeFact(a);
var primeOfB = primeFact(b);
var commonFactors = commonFactor(primeOfA,primeOfB);
var max = commonFactors[0];
for (var i = 1 ; i < commonFactors.length ; i++){
if (max < commonFactors[i]){
max = commonFactors[i];
}
}
return max;
}
/**
* @method
* @param {number} a First number
* @param {number} b Second number
* @returns The least common multiple of a and b
* @desc To get the least common multiple of a and b
*/
function LCM(a,b) {
var MCFA = MCF(a,b);
a /= MCFA;
b /= MCFA;
return (a * b * MCFA);
}
/**
* @method
* @param {number} a First number
* @param {number} b Second number
* @returns The common factors of a and b
* @desc To get the common factors of a and b
*/
function commonFactor(a,b) {
var commonFactors = [];
for (var i in a){
for (var j in b){
if (a[i] == b[j]){
commonFactors.push(a[i]);
break;
}
}
}
return commonFactors;
}
/**
* @method
* @param {number} n Number
* @returns The primes factor of number
* @desc To get the primes factor of number
*/
function primeFact(n) {
var primeNumbers = [];
var arr = prime(Math.sqrt(n));
for (var i in arr){
if (n % i == 0){
primeNumbers.push(arr[i]);
n /= i;
}
}
if (n != 1){
primeNumbers.push(n);
}
return primeNumbers;
}
/**
* @method
* @param {number} max Number
* @returns The primes(2~max)
* @desc To get the primes(2~max)
*/
function prime(max) {
var primes = [];
for (var i = 2 ; i < max ; i++){
if (isPrime(i)){
primes.push(i);
}
}
return primes;
}
/**
* @method
* @param {number} n Number
* @returns bool the number is prime
* @desc To get the number is prime
*/
function isPrime(n) {
var yes = true;
for (var i = 2 ; i < Math.sqrt(n) ; i++){
if (n % i == 0){
yes = false;
break;
}
}
return yes;
}
module.exports.fractions = fractions;
module.exports.expression = expression;
module.exports.setInf = setInf;
module.exports.sigma = sigma;
module.exports.MCF = MCF;
module.exports.LCM = LCM;
module.exports.commonFactor = commonFactor;
module.exports.primeFact = primeFact;
module.exports.prime = prime;
module.exports.isPrime = isPrime;