How to solve equation using javascript/nodejs? - javascript

I have an equation : 100 + (y * 5) = 200
I have to find the value of y = (200 -100)/5, but the main thing is operators sign may changes ( for eg: 100 * (y -5) = 200 ),
So How to write a program such that if the equation is passed, it solve and gives the value of x, irrespective of whatever operators are used.
Any help is appreciated.
I have tried below in node js and have to solve equation :
var fs = require('fs');
fs.readFile('equation.json',
// callback function that is called when reading file is done
function(err, data) {
// json data
var jsonData = data;
// parse json
var jsonParsed = JSON.parse(jsonData);
//operators array
var operators = {
"add":"+",
"subtract":"-",
"multiply":"*",
"divide":"/",
"equal":"="
};
var eq,op1,op2,equation;
for(opt in operators){
if(jsonParsed.op == opt){
eq = operators.equal;
}
//looking for first operator
if(jsonParsed.lhs.op == opt){
if(opt=="add"){
op1 = operators.add;
}
else if(opt=="subtract"){
op1 = operators.subtract;
}
else if(opt=="multiply"){
op1 = operators.multiply;
}
else if(opt=="divide"){
op1 = operators.divide;
}
}
//looking for second operator
if(jsonParsed.lhs.rhs.op == opt){
if(opt=="add"){
op2 = operators.add;
}
else if(opt=="subtract"){
op2 = operators.subtract;
}
else if(opt=="multiply"){
op2 = operators.multiply;
}
else if(opt=="divide"){
op2 = operators.divide;
}
}
}
//console.log(eq);
//console.log(op1);
//console.log(op2)
//parsing expression
equation = jsonParsed.lhs.lhs + op1 +"(" + jsonParsed.lhs.rhs.lhs + op2 + jsonParsed.lhs.rhs.rhs + ")" + eq + jsonParsed.rhs;
console.log(equation);
});
JSON
{
"op": "equal",
"lhs": {
"op": "add",
"lhs": 1,
"rhs": {
"op": "multiply",
"lhs": "x",
"rhs": 10
}
},
"rhs": 21
}

Systems of linear equations are most easily and generally solved on computers using matrices.
There is a webpage here that goes into how this works:
https://www.aplustopper.com/solving-systems-linear-equations-using-matrices/
There are also matrix packages for JavaScript available on the internet, like this one
https://mathjs.org/docs/datatypes/matrices.html
Disclosure: I have no association with either of these websites. This is how I did it in Java (using NASA's matrix package for Java) back in the day.

Related

aes-cmac in javascript not giving the same results as in python

I'm writing code to read/write to NTAG424 DNA NFC tags. I'm doing this completely in javascript, because I want to be able to use it in a react native app.
In NTAG 424 DNA and NTAG 424 DNA TagTamper features and hints they show the results you should be getting for every step. But they use a python solution.
The input message is A55A0001008013C56268A548D8FBBF237CCCAA20EC7E6E48C3DEF9A4C675360F and the output (according to the manual) is 1309C877509E5A215007FF0ED19CA564. Whereas I get 7CCEF6FEB32F34CA48CB685ECAA0F32C.
Because I need to be able to use this code commercially, I cannot just use any library.
function generateSubkeys(key) {
const cipher = crypto.createCipheriv("aes-128-ecb", key, "");
const cryptedKey = cipher.update(iv);
let subkey1 = bt.bitShiftLeft(cryptedKey);
if (msb(cryptedKey[0]) & 0x80) {
subkey1 = xor(subkey1, 0x87);
}
let subkey2 = bt.bitShiftLeft(subkey1);
if (msb(subkey1[0]) & 0x80) {
subkey2 = xor(subkey2, 0x87);
}
return { subkey1: subkey1, subkey2: subkey2 };
}
function msb(bytes) {
return bytes >>> 31;
}
function aes(key, message) {
const cipher = crypto.createCipheriv(
"aes-" + key.length * 8 + "-cbc",
key,
iv
);
var result = cipher.update(message);
cipher.final();
return result;
}
function aesCmac(key, message) {
const { subkey1, subkey2 } = generateSubkeys(Buffer.from(key, "hex"));
let numBlocks = Math.ceil(message.length / blockSize);
var lastBlockRemainder = message.length % blockSize;
if (numBlocks === 0) {
numBlocks = 1;
}
var messageArray = getMessageArray(message, numBlocks, lastBlockRemainder);
if (lastBlockRemainder === 0) {
messageArray[numBlocks - 1] = xor(messageArray[numBlocks - 1], subkey1);
} else {
messageArray[numBlocks - 1] = xor(messageArray[numBlocks - 1], subkey2);
}
var c = aes(
key,
Buffer.concat(messageArray.slice(0, messageArray.length - 1))
);
let c_xor_m = xor(c, messageArray[messageArray.length - 1]);
c = aes(key, c_xor_m);
return c;
}
function getMessageArray(message, numBlocks, lastBlockRemainder) {
var index = 0;
var messageArray = [];
if (lastBlockRemainder !== 0) {
let padding = "80" + "00".repeat(16 - lastBlockRemainder - 1);
let appendToMessage = Buffer.from(padding, "hex");
message = Buffer.concat([message, appendToMessage]);
}
for (index = 0; index < numBlocks; index++) {
let messageBlock = message.slice(
index * blockSize,
(index + 1) * blockSize
);
messageArray.push(messageBlock);
}
return messageArray;
}
I already tried the one mentioned here AES-CMAC module for Node.js? and completely rewriting the code to my own version of an AES-CMAC algorithm. In both the one I tried and the one I made (with the help of NIST Special Publication 800-38B), I get the same results.
Now I'm stuck between thinking either my code is wrong, or the python crypto library (where I don't completely understand the code) is wrong.
Can anyone help me figure out which of the two is true? And in case my code is wrong, help me fix it.
I found the answer: The Crypto library in javascript has an aes-cbc cipher, that says (and it does) accepts buffers and arrays. But the outcomes of both are different.
When I used a UInt8Array I got the right outcome. I completely rewrote an aes-cmac algorithm, just to figure out this what all I needed.

How to dynamically select pre-defined variables in a JS for-if loop?

I have a JSON object that contains Forex trades each with the following key:values
[...]
orderType: 0
orderLots: "1.00"
orderSymbol: "AUDCAD"
[...]
I now want to define a loop that iterates over each object and returns both the traded short and long volume for the major currencies (EUR|GBP|AUD|CHF|JPY|USD|CAD).
Each trade consists of a base currency in the example given: AUD and a counter currency in the example given: CAD
Each trade is either long (orderTypes 0, 2, 4) or short (orderTypes 1, 3, 5)
Each trade has a trade volume expressed in orderLots where 1.00 equals 100.000 traded units
Now the idea for the loop is as follows:
Check if it is a currency pair that contains two major currencies (e.g. EURUSD, AUDCAD, etc.)
If so, calculate the traded volume for the base and counter currency
If not, calculate the traded volume either for the base or counter currency, depending on which one is the major
My issue (see at the bottom of the code snippet) is that I don't know how to pick the pre-defined variables dynamically as needed. Otherwise I will have to set up dozens of else if statements.
// define variables
var eurVolumeBought = 0
var eurVolumeSold = 0
var usdVolumeBought = 0
var usdVolumeSold = 0
[...]
var chfVolumeBought = 0
var chfVolumeSold = 0
// iterate each trade in returned JSON object
for (var i = 0; i < tradesTotal; i++) {
symbol = trades[i].fields.orderSymbol
// returns e.g. AUD/CAD
symbolBase = symbol.slice(0, 3)
// returns e.g. AUD
symbolCounter = symbol.slice(3, 6)
// returns e.g. CAD
lots = trades[i].fields.orderLots
// returns e.g. 1.00
orderType = trades[i].fields.orderType
// orderTypes 0, 2, 4 are long trades and 1, 3, 5 are short trades accordingly
// check for main pairs where that contain two major currencies
if (symbolBase.match(/^(EUR|GBP|AUD|CHF|JPY|USD|CAD)$/) && symbolCounter.match(/^(EUR|GBP|AUD|CHF|JPY|USD|CAD)$/){
// Create logic for long trades
if (orderType == '0' || orderType == '2' || orderType == '4') {
// >>>> here i run into issues <<<<
// In the example given, we have a AUDCAD long trade of 100.000 units.
// Thus, I want to dynamically pick the audVolumeBought and cadVolumeSold variables
// to increase them accordingly. My foolish approach right now is as follows:
symbolBase = symbolBase.toLowerCase()
(symbolBase + 'volumeBought') = lots * 100.000 // I try to grab audVolumeBought variable here
}
}
Edit to #kastenbutts comment:
The resulting variable's values will be pushed in a chart.JS chart.
So for each trade object there will be either one or two calculations and that's it.
Using
result[symbolBase + 'volumeBought'] = result[symbolBase + 'volumeBought'] + (lots * 100.000)
returns NaN
As a first step you could collect all trades for each currency in an object:
let result = {}; // Each key in this object will correspond to a currency
for (var i = 0; i < tradesTotal; i++) {
symbol = trades[i].fields.orderSymbol
symbolBase = symbol.slice(0, 3)
symbolCounter = symbol.slice(3, 6)
lots = trades[i].fields.orderLots
orderType = trades[i].fields.orderType
if (symbolBase.match(/^(EUR|GBP|AUD|CHF|JPY|USD|CAD)$/) && symbolCounter.match(/^(EUR|GBP|AUD|CHF|JPY|USD|CAD)$/){
if (orderType == '0' || orderType == '2' || orderType == '4') {
symbolBase = symbolBase.toLowerCase()
if(result.hasOwnProperty(symbolBase + 'volumeBought')) {
result[symbolBase + 'volumeBought'] += lots * 100.000
}
else {
result[symbolBase + 'volumeBought'] = lots * 100.000
}
}
// ... handle short case
}
As a next step you need to transform the data into a chart object as required by ChartJs. If you want a simple bar chart you would do it like this:
let data = [];
let label = [];
for(let cur in result) {
label.push(cur);
data.push(result[cur]);
}
let barChart = {
type: 'bar',
data: {
labels: labels,
datasets: [{
data: data
}]
}
}
Note: I'm not sure if that exactly fits the logic you require. But it might be a good starting point.
Here is a solution with just three if expressions:
var ma=['EUR','GBP','AUD','CHF','JPY','USD','CAD'];
var volumeBought={}, volumeSold={};
var jo=[
{fields:{orderType: 0,orderLots: "1.00",orderSymbol: "AUDCAD"}},
{fields:{orderType: 1,orderLots: "0.80",orderSymbol: "USDEUR"}},
{fields:{orderType: 2,orderLots: "1.40",orderSymbol: "EURAUD"}},
{fields:{orderType: 3,orderLots: "2.20",orderSymbol: "AUDCAD"}},
{fields:{orderType: 4,orderLots: "1.10",orderSymbol: "CADDKK"}},
{fields:{orderType: 5,orderLots: "1.30",orderSymbol: "GBPUSD"}},
{fields:{orderType: 0,orderLots: "3.04",orderSymbol: "DKKCAD"}},
{fields:{orderType: 1,orderLots: "1.10",orderSymbol: "USDCHF"}},
{fields:{orderType: 2,orderLots: "0.90",orderSymbol: "JPYEUR"}},
{fields:{orderType: 3,orderLots: "0.40",orderSymbol: "AUDJPY"}},
{fields:{orderType: 4,orderLots: "2.30",orderSymbol: "CHFGBP"}},
{fields:{orderType: 5,orderLots: "3.10",orderSymbol: "EURUSD"}},
{fields:{orderType: 0,orderLots: "4.25",orderSymbol: "AUDNGN"}},
{fields:{orderType: 1,orderLots: "0.60",orderSymbol: "USDGBP"}},
{fields:{orderType: 2,orderLots: "1.70",orderSymbol: "GBPEUR"}}
];
jo.forEach(({fields})=>{
if (!(fields.orderType%2)) {
var sld=fields.orderSymbol.substr(0,3),
bgt=fields.orderSymbol.substr(3,6),
lots=fields.orderLots*100000;
if (ma.indexOf(sld)>-1)volumeSold[sld]=(volumeSold[sld]||0) + lots
if (ma.indexOf(bgt)>-1)volumeBought[bgt]=(volumeBought[bgt]||0) + lots
}
});
console.log('sold:',JSON.stringify(volumeSold))
console.log('bought:',JSON.stringify(volumeBought))
Most of the above code deals with generating some sample data. The actual work happens in just a few lines at the bottom. I collect the "sold" and "bought" quantities whenever the given conditions ("long trade" and "major currency") are fulfilled. The result is displayed as a JSON string, but it really is available as a JS object which of course can be used in many different ways.
The expression volumeSold[sld]=(volumeSold[sld]||0) + lots will add the value of lots to the object's property, regardless of whether it existed before or not (in that case it is initialised with "0" first).
I finally got a working solution. For the sake of completeness, find it below:
let resultBought = {}
let resultSold = {}
for (var i = 0; i < tradesTotal; i++) {
symbol = trades[i].fields.orderSymbol
// returns e.g. EUR/USD
symbolBase = symbol.slice(0, 3)
// returns e.g. EUR
symbolCounter = symbol.slice(3, 6)
// returns e.g. USD
lots = trades[i].fields.orderLots
// returns e.g. 1.00
orderType = trades[i].fields.orderType
// orderTypes 0, 2, 4 are long trades, 1, 3, 5 shorts accordingly
// check for major pairs where XXX/YYY = defined currencies
if (symbolBase.match(/^(EUR|GBP|AUD|CHF|JPY|USD|CAD)$/) && symbolCounter.match(/^(EUR|GBP|AUD|CHF|JPY|USD|CAD)$/)) {
// Long Trades Major Pairs
if (orderType == '0' || orderType == '2' || orderType == '4') {
// Base currency
if(resultBought.hasOwnProperty(symbolBase + 'VolumeBought')) {
resultBought[symbolBase + 'VolumeBought'] += lots * 100.000
}
else {
resultBought[symbolBase + 'VolumeBought'] = lots * 100.000
}
// Counter currency
if(resultSold.hasOwnProperty(symbolCounter + 'VolumeSold')) {
resultSold[symbolCounter + 'VolumeSold'] += lots * 100.000
}
else {
resultSold[symbolCounter + 'VolumeSold'] = lots * 100.000
}
// Short Trades Major Pairs
} else if (orderType == '1' || orderType == '3' || orderType == '5') {
// Base currency
if(resultSold.hasOwnProperty(symbolBase + 'VolumeSold')) {
resultSold[symbolBase + 'VolumeSold'] += lots * 100.000
}
else {
resultSold[symbolBase + 'VolumeSold'] = lots * 100.000
}
// Counter currency
if(resultBought.hasOwnProperty(symbolCounter + 'VolumeBought')) {
resultBought[symbolCounter + 'VolumeBought'] += lots * 100.000
}
else {
resultBought[symbolCounter + 'VolumeBought'] = lots * 100.000
}
}
// consider the non major pairs
} else if (symbolBase.match(/^(EUR|GBP|AUD|CHF|JPY|USD|CAD)$/) || symbolCounter.match(/^(EUR|GBP|AUD|CHF|JPY|USD|CAD)$/)) {
if (orderType == '0' || orderType == '2' || orderType == '4') {
if(resultBought.hasOwnProperty(symbolBase + 'VolumeBought')) {
resultBought[symbolBase + 'VolumeBought'] += lots * 100.000
}
else {
resultBought[symbolBase + 'VolumeBought'] = lots * 100.000
}
} else if (orderType == '1' || orderType == '3' || orderType == '5') {
if(resultSold.hasOwnProperty(symbolBase + 'VolumeSold')) {
resultSold[symbolBase + 'VolumeSold'] += lots * 100.000
}
else {
resultSold[symbolBase + 'VolumeSold'] = lots * 100.000
}
}
}
}

Find all permutations of a set of numbers and operators

I was given a code challenge to do that was related to recursion and was unable to complete it. My experience with these types of questions is very slim and this one just stumped me. Could any of you help me out just for my own education, as I've already failed the challenge?
The description:
Given a string of numbers and operators, print out all the different ways you can add parentheses to force the order of operations to be explicit, and the result for running the operations in that order.
Assume:
No weird inputs, everything is separated by one space.
Supported operators are +, *, -, = (for the = operator, if the values are the same return 1, otherwise return 0)
Print your results sorted numerically
Don't worry about the input expression size being too large
Your code should be written in javascript
Don't use eval or external libraries
Example:
node test.js "2 - 1 - 1"
((2-1)-1) = 0
(2-(1-1)) = 2
node test.js "2 * 3 - 4 * 5";
(2*(3-(4*5))) = -34
((2*3)-(4*5)) = -14
((2*(3-4))*5) = -10
(2*((3-4)*5)) = -10
(((2*3)-4)*5) = 10
node test.js "2 + 2 = 2"
((2+2)=2) = 0
(2+(2=2)) = 3
This is where I'm at so far. I'm far from getting the right output, but I feel like the logic is starting to get there. I've adapted this code from a similar, but different question.
var args = process.argv.slice(2)[0].split(" "),
numberOfOperators = 0;
args.forEach(function(val, index, array) {
if (isNaN(val)) {
++numberOfOperators;
}
});
args = args.join("");
var recurse = function(openParenCount, closeParenCount, input, pointer) {
if (openParenCount === 0 && closeParenCount === 0) {
console.log(input + "\n");
}
if (openParenCount > 0) {
input = input.slice(0, pointer) + "(" + input.slice(pointer, input.length);
recurse(openParenCount - 1, closeParenCount + 1, input, pointer+1);
}
if (closeParenCount > 0) {
input = input.slice(0, pointer+openParenCount+3) + ")" + input.slice(pointer+openParenCount+3, input.length+1);
recurse(openParenCount, closeParenCount - 1, input, pointer+3);
}
}
recurse(numberOfOperators, 0, args, 0);
a little hint:
var AP = [];
var input = process.argv.slice(2)[0];
var args = input.replace(/\s+/g, "").split(/([^\d\.]+)/g);
recurse(args, []).forEach(function(v){ console.log(v); });
function recurse(arr, into){
if(arr.length === 1){
into.push(arr[0]);
}else{
for(var i=0, j=arr.length-2; i<j; i+=2){
recurse(
AP.concat(
arr.slice(0, i),
"(" + arr.slice(i, i+3).join(" ") + ")",
arr.slice(i+3)
),
into
)
}
}
return into
}
This Implementation still has a few "bugs", and these by intent; I'm not going to do your "homework".
If you have more than 2 operators in your Equasion, the result will contain duplicates, 2nd It is not sorted, and since it is just splitting and concatenating strings, it can't compute any result.
But it shows you a way how you can implement the recursion.

Javascript rounding failure

This is the rounding function we are using (which is taken from stackoverflow answers on how to round). It rounds half up to 2dp (by default)
e.g. 2.185 should go to 2.19
function myRound(num, places) {
if (places== undefined) {
// default to 2dp
return Math.round(num* 100) / 100;
}
var mult = Math.pow(10,places);
return Math.round(num* mult) / mult;
}
It has worked well but now we have found some errors in it (in both chrome and running as jscript classic asp on IIS 7.5).
E.g.:
alert(myRound(2.185)); // = 2.19
alert (myRound(122.185)); // = 122.19
alert (myRound(511.185)); // = 511.19
alert (myRound(522.185)); // = 522.18 FAIL!!!!
alert (myRound(625.185)); // = 625.18 FAIL!!!!
Does anyone know:
Why this happens.
How we can round half up to 2 dp without random rounding errors like this.
update: OK, the crux of the problem is that in js, 625.185 * 100 = 62518.499999
How can we get over this?
Your problem is not easily resolved. It occurs because IEEE doubles use a binary representation that cannot exactly represent all decimals. The closest internal representation to 625.185 is 625.18499999999994543031789362430572509765625, which is ever so slightly less than 625.185, and for which the correct rounding is downwards.
Depending on your circumstances, you might get away with the following:
Math.round(Math.round(625.185 * 1000) / 10) / 100 // evaluates to 625.19
This isn't strictly correct, however, since, e.g., it will round, 625.1847 upwards to 625.19. Only use it if you know that the input will never have more than three decimal places.
A simpler option is to add a small epsilon before rounding:
Math.round(625.185 * 100 + 1e-6) / 100
This is still a compromise, since you might conceivably have a number that is very slightly less than 625.185, but it's probably more robust than the first solution. Watch out for negative numbers, though.
Try using toFixed function on value.
example is below:
var value = parseFloat(2.185);
var fixed = value.toFixed(2);
alert(fixed);
I tried and it worked well.
EDIT: You can always transform string to number using parseFloat(stringVar).
EDIT2:
function myRound(num, places) {
return parseFloat(num.toFixed(places));
}
EDIT 3:
Updated answer, tested and working:
function myRound(num, places) {
if (places== undefined) {
places = 2;
}
var mult = Math.pow(10,places + 1);
var mult2 = Math.pow(10,places);
return Math.round(num* mult / 10) / mult2;
}
EDIT 4:
Tested on most examples noted in comments:
function myRound(num, places) {
if (places== undefined) {
places = 2;
}
var mult = Math.pow(10,places);
var val = num* mult;
var intVal = parseInt(val);
var floatVal = parseFloat(val);
if (intVal < floatVal) {
val += 0.1;
}
return Math.round(val) / mult;
}
EDIT 5:
Only solution that I managed to find is to use strings to get round on exact decimal.
Solution is pasted below, with String prototype extension method, replaceAt.
Please check and let me know if anyone finds some example that is not working.
function myRound2(num, places) {
var retVal = null;
if (places == undefined) {
places = 2;
}
var splits = num.split('.');
if (splits && splits.length <= 2) {
var wholePart = splits[0];
var decimalPart = null;
if (splits.length > 1) {
decimalPart = splits[1];
}
if (decimalPart && decimalPart.length > places) {
var roundingDigit = parseInt(decimalPart[places]);
var previousDigit = parseInt(decimalPart[places - 1]);
var increment = (roundingDigit < 5) ? 0 : 1;
previousDigit = previousDigit + increment;
decimalPart = decimalPart.replaceAt(places - 1, previousDigit + '').substr(0, places);
}
retVal = parseFloat(wholePart + '.' + decimalPart);
}
return retVal;
}
String.prototype.replaceAt = function (index, character) {
return this.substr(0, index) + character + this.substr(index + character.length);
}
OK, found a "complete" solution to the issue.
Firstly, donwnloaded Big.js from here: https://github.com/MikeMcl/big.js/
Then modified the source so it would work with jscript/asp:
/* big.js v2.1.0 https://github.com/MikeMcl/big.js/LICENCE */
var Big = (function ( global ) {
'use strict';
:
// EXPORT
return Big;
})( this );
Then did my calculation using Big types and used the Big toFixed(dp), then converted back into a number thusly:
var bigMult = new Big (multiplier);
var bigLineStake = new Big(lineStake);
var bigWin = bigLineStake.times(bigMult);
var strWin = bigWin.toFixed(2); // this does the rounding correctly.
var win = parseFloat(strWin); // back to a number!
This basically uses Bigs own rounding in its toFixed, which seems to work correctly in all cases.
Shame Big doesnt have a method to convert back to a number without having to go through a string.

Solving Linear Equations & similar Algebra Problems with JavaScript

I'm new to JavaScript and I am trying to write a simple script that solves linear equations. So far my script solves linear equations that are plus and minus only such as "2x + 28 - 18x = 36 - 4x + 10". I want it to also be able to solve linear equations/algebra problems that contain multiplication and division such as "2x * 3x = 4 / 2x".
I kind of have an idea of what to do next but I think the script I have right now maybe overly complex and it's only going to make it more complicated to add the multiplication and division.
Below is my script. I'm hoping for a few pointers on how I could improve and simplify what I already have and what the best way to add multiplication and division?
My script on JS Bin: http://jsbin.com/ufekug/1/edit
My script:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Problem Solver</title>
<script>
window.onload = function() {
// Total Xs on each side of equation
// Example problem: 5x + 2 = 10 - 2x
var leftSideXTotal = 0; // 5
var rightSideXTotal = 0; // -2
// Total integers on each side of equation
// Example problem: 5x + 2 = 10 - 2x
var leftSideIntTotal = 0; // 2
var rightSideIntTotal = 0; // 10
// Enter a math problem to solve
var problem = "5x + 2 = 10 - 2x";
// Remove all spaces in problem
// Example problem: 5x + 2 = 10 - 2x
problem = problem.replace(/\s/g,''); // 5x+2=10-2x
// Add + signs in front of all - signs
// Example problem: 5x + 2 = 10 - 2x
problem = problem.replace(/-/gi, "+-"); // 5x+2=10+-2x
// Split problem into left and right sides
// Example problem: 5x + 2 = 10 - 2x
var problemArray = problem.split("=");
var problemLeftSide = problemArray[0]; // 5x+2
var problemRightSide = problemArray[1]; // 10+-2x
// Split values on each side into an array
var problemLeftSideValues = problemLeftSide.split("+");
var problemRightSideValues = problemRightSide.split("+");
// Go through the left side values and add them up
for (var i = 0; i < problemLeftSideValues.length; i++) {
// Current value
var currentValue = problemLeftSideValues[i];
// Length of current value
var currentValueLength = currentValue.length;
if (currentValue.charAt(currentValueLength - 1) == "x") { //Check if current value is a X value
// Remove X from end of current value
currentValue = currentValue.split("x");
// Add to total Xs on left side
leftSideXTotal = Number(leftSideXTotal) + Number(currentValue[0]);
} else {
// Add to total integers on left side
leftSideIntTotal = Number(leftSideIntTotal) + Number(problemLeftSideValues[i]);
}
}
// Go through the right side values and add them up
for (var i = 0; i < problemRightSideValues.length; i++) {
// Current value
var currentValue = problemRightSideValues[i];
// Length of current value
var currentValueLength = currentValue.length;
if (currentValue.charAt(currentValueLength - 1) == "x") { //Check if current value is a X value
// Remove X from end of current value
currentValue = currentValue.split("x");
// Add to total Xs on right side
rightSideXTotal = Number(rightSideXTotal) + Number(currentValue[0]);
} else {
// Add to total integers on right side
rightSideIntTotal = Number(rightSideIntTotal) + Number(problemRightSideValues[i]);
}
}
// Compute
var totalXs = (leftSideXTotal - rightSideXTotal)
var totalIntegers = (rightSideIntTotal - leftSideIntTotal)
var solution = (totalIntegers / totalXs)
// Display solution
document.getElementById("divSolution").innerText = solution;
}
</script>
</head>
<body>
<div id="divSolution"></div>
</body>
</html>
You need to write (or use) an operator-precedence parser.
The idea is to turn the equation into a tree, e.g.
x + 3 = 3x - 2
Is really the structure
=
/ \
+ -
/ \ / \
x 3 * 2
/ \
3 x
Where each operator describes an operation between two "branches" of the tree. Using a javascript object it shouldn't be difficult to create the structure:
function tree(lterm,op,rterm) {
t.operator = op;
t.left = lterm;
t.right = rterm;
return t;
}
expression = tree("x", "/", tree("x","+",3) ); // x / (x+3)
Then by manipulating the tree you can resolve the equation, or carry out calculations. To evaluate an expression (with no unknowns), you run through the tree starting at the terminals, and upwards from intersection to intersection. You can replace a section of the tree with a result, or annotate it with a result - add a result variable to the tree object.
Here are some useful methods to include in a tree class:
getLeft
getRight
prettyPrint
evaluate
evaluate("x",5) // x=5, now evaluate
...
It's not just linear operations that can be "parsed" this way. Better parsers will have a list of operators that includes =*/+- but also unary operators: - ( ) sin cos...
I haven't used an operator-precedence parser in javascript, but some must exist prewritten. Surely a kind soul on this site will add a good link or two to my answer.
BTW, the tree approach has many applications. In a spreadsheet:
A2 = A1+B1
In a boolean solver:
A = not (B or C)
C = true
In XML parsing:
<main>
<part>A</part>
<part>B</part>
</main>
I have defined two functions:
getTotalX() : It will give you the count of x for any input string.
getTotalScalars() : It will give you the total of scalars (numbers).
And finally, your updated code (it still does only addition and subtraction):
<script>
window.onload = function() {
// Total Xs on each side of equation
// Example problem: 5x + 2 = 10 - 2x
var leftSideXTotal = 0; // 5
var rightSideXTotal = 0; // -2
// Total integers on each side of equation
// Example problem: 5x + 2 = 10 - 2x
var leftSideIntTotal = 0; // 2
var rightSideIntTotal = 0; // 10
// Enter a math problem to solve
var problem = "5x + 2 = 10 - 2x";
// Remove all spaces in problem
// Example problem: 5x + 2 = 10 - 2x
problem = problem.replace(/\s/g,''); // 5x+2=10-2x
// Add + signs in front of all - signs
// Example problem: 5x + 2 = 10 - 2x
problem = problem.replace(/-/gi, "+-"); // 5x+2=10+-2x
// Split problem into left and right sides
// Example problem: 5x + 2 = 10 - 2x
var problemArray = problem.split("=");
var problemLeftSide = problemArray[0]; // 5x+2
var problemRightSide = problemArray[1]; // 10+-2x
leftSideXTotal = getTotalX(problemLeftSide);
leftSideIntTotal = getTotalScalars(problemLeftSide);
rightSideXTotal = getTotalX(problemRightSide);
rightSideIntTotal = getTotalScalars(problemRightSide);
// Compute
var totalXs = (leftSideXTotal - rightSideXTotal)
var totalIntegers = (rightSideIntTotal - leftSideIntTotal)
var solution = (totalIntegers / totalXs)
// Display solution
document.getElementById("divSolution").innerText = solution;
// Find the total number of X in the string
function getTotalX(data) {
data = data.replace(/\s/g,'');
xCount = 0;
if(data.indexOf('x') != -1) {
if (data.indexOf('+') != -1) {
data = data.split('+');
for(var i = 0; i < data.length; i++) {
xCount += getTotalX(data[i]);
}
} else if (data.indexOf('-') != -1) {
data = data.split('-');
// Single negative
if(data[0] == "") {
xCount -= getTotalX(data[1]);
} else {
xCount += getTotalX(data[0]);
for(var i = 1; i < data.length; i++) {
xCount -= getTotalX(data[i]);
}
}
} else {
xCount = parseInt(data.split('x')[0]);
}
}
return xCount;
}
// Find the total of scalars
function getTotalScalars(data) {
data = data.replace(/\s/g,'');
intCount = 0;
if (data.indexOf('+') != -1) {
data = data.split('+');
for(var i = 0; i < data.length; i++) {
intCount += getTotalScalars(data[i]);
}
} else if (data.indexOf('-') != -1) {
data = data.split('-');
// Single negative
if(data[0] == "") {
intCount -= getTotalScalars(data[1]);
} else {
intCount += getTotalScalars(data[0]);
for(var i = 1; i < data.length; i++) {
intCount -= getTotalScalars(data[i]);
}
}
} else {
if(data.indexOf('x') == -1) {
intCount = parseInt(data.split('x')[0]);
} else {
intCount = 0;
}
}
return intCount;
}
}
</script>

Categories

Resources