I want to create a random generator of math operations. I'm trying with ASCII codes but what happens is that it just concatenate the operands and operators as a String. Anyone has a suggestion for this?
let a = Math.floor(Math.random()*100)
let b = Math.floor(Math.random()*100)
let ascCode = Math.floor(Math.random()* (46 - 42)) + 42
let op = String.fromCharCode(ascCode)
let c = a + `${op}` + b;
console.log(c)
You can use eval:
The eval() function evaluates JavaScript code represented as a string.
let a = 1
let b = 2
let ascCode = Math.floor(Math.random()* (46 - 42)) + 42
let op = String.fromCharCode(ascCode)
let c = eval(a + `${op}` + b);
console.log(c)
But eval can be troublesome.
eval() is a dangerous function, which executes the code it's passed with the privileges of the caller. If you run eval() with a string that could be affected by a malicious party, you may end up running malicious code on the user's machine with the permissions of your webpage / extension. More importantly, a third-party code can see the scope in which eval() was invoked, which can lead to possible attacks in ways to which the similar Function is not susceptible.
eval() is also slower than the alternatives, since it has to invoke the JS interpreter, while many other constructs are optimized by modern JS engines.
msdn
Another solution would be to use some if:
let a = 1
let b = 2
let ascCode = Math.floor(Math.random()* (46 - 42)) + 42
let op = String.fromCharCode(ascCode)
let c = 0;
if (op == "*")
c = a + b;
if (op == "+")
c = a + b;
if (op == "-")
c = a - b;
/*etc*/
console.log(c)
or even a map where keys are operators and values are functions:
let a = 1
let b = 2
let ascCode = Math.floor(Math.random()* (46 - 42)) + 42
let op = String.fromCharCode(ascCode)
let operators = {
'+': (a, b) => a + b,
'-': (a, b) => a - b,
'*': (a, b) => a * b,
'/': (a, b) => a / b, // handle zero!
'%': (a, b) => a % b // handle zero!
};
console.log(operators[op](a,b))
This solution is similar to things discussed in the comments. It is a different, non-eval way of generating random math operations:
const ops = {
'+': (a, b) => a + b,
'-': (a, b) => a - b,
'*': (a, b) => a * b,
'/': (a, b) => a / b,
'%': (a, b) => a % b,
'>': (a, b) => a > b,
'<': (a, b) => a < b,
// etc
}
const randomOperation = ((ops) => {
const keys = Object.keys(ops)
const randomOpKey = () => keys[Math.floor(Math.random() * keys.length)]
const evalOp = (key, a, b) => ops[key](a, b)
return () => {
const op = randomOpKey()
const a = Math.floor(Math.random() * 100)
const b = Math.floor(Math.random() * 100)
return {
expression: `${a} ${op} ${b}`,
result: evalOp(op, a, b)
}
}
})(ops)
// demo
for (let i = 0; i < 20; i++) {
let {expression, result} = randomOperation()
console.log(`${expression} = ${result}`)
}
Note that what randomOperation returns is objects with two properties: expression as a string, and result as a value, which will be numeric or boolean. The demo code shows one way to use it. You have to manually maintain the list of operations, which is different than with the eval solutions.
I don't know what better suits your needs, but this should show that there are reasonable non-eval solutions possible.
What you could use (though this is definitely not a good practice), is eval(), which evaluates a string as javascript code.
(Another word of warning, eval is evil and shouldn't be used in production)
let a = Math.floor(Math.random()*100)
let b = Math.floor(Math.random()*100)
let ascCode = Math.floor(Math.random()* (46 - 42)) + 42
let op = String.fromCharCode(ascCode)
let c = eval(a + `${op}` + b);
console.log(c)
You should use built-in function eval()
let operators = ['+','-','*','/','%'];
let number1 = 5;
let number2 = 4;
function getRandomOperation(){
let randOpeator = operators[Math.floor(Math.random() * operators.length)];
return eval(`${number1} ${randOpeator} ${number2}`);
}
console.log(getRandomOperation());
You should evalute expression, using javascript eval function. It expects string as input.
const result = eval(c);
console.log(result);
Reference
I presume it happens because you are using concatenation when one from concatenated values is a string:
let op = String.fromCharCode(ascCode)
To obtain a number under variable c you have to make sure that ${op} is number as well.
Related
I'm trying to get this function done but something is wrong, it should return 50 for a=5,b=10 or 2 for a=1,b=1. However any other way to write this function would be interesting
function getLargestExpressionResult(a, b) {
const sum = a + b;
const prod = a * b;
const diff = a - b;
const quot = a \ b;
let res = sum;
if (prod > res) res = prod;
if (diff > res) res = diff;
if (quot > res) res = quot;
return res;
}
enter code here
You can use Math.max(). It can take multiple parameters and gives you max.
Also for division it is /
function getLargestExpressionResult(a, b) {
const sum = a + b;
const prod = a * b;
const diff = a - b;
const quot = a / b;
return Math.max(sum,prod,diff,quot);
}
console.log(getLargestExpressionResult(5, 10))
You don't really need to find maximum element on your own, you can simply use Math.max:
const getLargestExpressionResult = (a, b) => Math.max(a * b, a / b, a + b, a - b);
console.log(getLargestExpressionResult(5, 10));
console.log(getLargestExpressionResult(1, 1));
Also should be noticed division is /, not \.
Or if you need to avoid Math usage:
getLargestExpressionResult = (a, b) => {
const expressionValues = [ a + b, a - b, a * b, a / b ];
let max = expressionValues[0];
for (const value of expressionValues) {
if (value > max) max = value;
}
return max;
}
console.log(getLargestExpressionResult(5, 10));
console.log(getLargestExpressionResult(1, 1));
I cant seem to get my calculator to chain multiple operators together for example 5x5x5 should equal 125 but it just calculates 5x5 and will no longer calculate decimal numbers. Could anyone point me in the correct direction.
I have tried to assign the result to the firstNum but it seems to break the code.
button.forEach((button) =>
button.addEventListener('click', ()=> displayTotal(button.innerHTML)));
clearBtn.addEventListener('click', clear);
decmialBtn.addEventListener('click', appendDecimal);
functionBtn.forEach((button) =>
button.addEventListener('click', () => setOperator(button.innerHTML)));
equalsBtn.addEventListener('click', calculate)
let firstNum = "";
let secondNum = "";
let operatorSelection = "null";
let result = "";
function add(a, b){
return a + b
}
function subtract(a,b){
return a - b
}
function divide (a,b)
{
return a / b
}
function times (a,b){
return a*b
}
function operator(operator, numa, numb) {
switch(operator){
case '+':
return add(numa, numb);
break;
case '-':
return subtract(numa, numb);
break;
case '/':
return divide(numa,numb);
break;
case '*':
return times(numa,numb)
break;
}
}
function displayTotal (number){
userDisplay.value += number;
}
function clear (){
userDisplay.value = "";
}
function appendDecimal(){
userDisplay.value += ".";
}
function setOperator(operator){
firstNum = parseInt(userDisplay.value);
operatorSelection = operator;
result = firstNum;
clear()
}
function calculate(){
for (i = 0; i < 100; i++)
secondNum = parseInt(userDisplay.value);
result = operator(operatorSelection, firstNum, secondNum);
userDisplay.value = result;
[i];
}
For a simple JS calculator you could use the eval() function and it will handle all the operators for you taking PEMDAS in consideration, but you have to ensure the inpput is valid or it you won't work.
I have one on my Github if want an example:
https://github.com/gustavo-shigueo/calculator
Note: don't worry about the regexes I used, they are there just to prevent the user from typing stuff that would break the calculator
Here is an example of how I would do it:
operations = [
["*", (a, b) => +a * +b],
["/", (a, b) => +a / +b],
["+", (a, b) => +a + +b],
["-", (a, b) => +a - +b],
];
const calc = calcString => {
const split = [...calcString].reduce((prev, cur) => Number.isInteger(+cur) && Number.isInteger(+prev[prev.length - 1]) ? [...prev.slice(0, -1), prev[prev.length - 1] + cur] : [...prev, cur], [""]);
operations.forEach(([operator, funct]) => {
for (let i = 1; i < split.length - 1; i++) {
if (split[i] === operator) {
split[i - 1] = funct(split[i - 1], split[i + 1]);
split.splice(i, 2);
i--;
}
}
})
return split;
};
It doesn't support numbers with a dot/comma in them (e.g. 3.13) and no braces.
some explanation:
const split, I split the given string in numbers and operations, "3+45*4" would result in ["3", "+", "45", "*", "4"].
go over each operation in the given order to first do the "point calculation" and then + and -.
we go over the in 1. created array and look for our operation.
if we find one, we lool at the number before and after the operation and calculate the result given the 2 numbers and our operation type.
we overwrite those 3 elements with the result of our calculation.
we are done if all operations are done
I also have a more advanced version if you are interested
I am programming a calculator that takes a string representing a calculation and outputs the result (like the eval function).
At some point in my code I define the meaning of the different operations like this:
const _ops = [
[
["^", (a, b) => (+a) ** +b],
],
[
["*", (a, b) => +a * +b],
["/", (a, b) => +a / +b],
["%", (a, b) => +a % +b],
],
[
["+", (a, b) => +a + +b],
["-", (a, b) => +a - +b],
],
];
As you can see I am repeating the function part every time while only one character changes (except for the first time...)
(a, b) => +a ${operation} +b
Do you have any idea how I could do this without repeating the function declaration every time?
PS: If you can think of a better title, feel free to change it.
No, this is not possible in JavaScript without eval. This is because there is no way to treat an operator as a function. This is not the case e.g. in Haskell, where (*) represents the multiplication function, which you can carry around as a value, apply a value to get a partially-applied operator, and apply another value to get the result.
Using eval would look kind of like this.
const dynamicCalculation = (a ,b, operator) => {
if (operator === "^") operator = "**"
return eval("${+a} ${operator} ${+b}")
}
usage:
dynamicCalculation(1,2,"+") // => 3
dynamicCalculation(1,2,"-") // => -1
dynamicCalculation(1,2,"*") // => 2
switch:
const dynamicCalculation = (a ,b, operator) => {
let output;
switch(operator){
case "+":
output = a + b;
break;
case "-":
output = a - b;
break;
case "*":
output = a * b;
break;
case "/":
output = a / b;
break;
case "^":
output = a ** b;
break;
case "%":
output = a % b;
break;
}
return output
}
var toyProblem = function () {
var sol= 0;
var operators = ['+','-','*','/'];
console.log(sol)
for(var i in arguments){
for(var j in operators){
sol = eval(sol + (operators[j]) + arguments[i]);
}
}
return sol;
}
toyProblem(6, 0, 10, 3); //6 + 0 - 10 * 3 === -12)
I'm trying to loop through 4 math operators for an unknown number of input values. I'm thinking of using eval in a nest for loop as a way of going through both the unknown number of arguments while also changing the math operator. At the bottom is the solution that I want to arrive at. Is this a good way of going about this problem or am I barking up the wrong tree?
var toyProblem = function () {
var sol_str='';
var operators = ['+','-','*','/'];
for(var i in operators){
var prev_operator=(i-1);
if(sol_str!=''){sol_str+=operators[prev_operator];}
sol_str +=arguments[i];
}
console.log(sol_str);
return eval(sol_str);
}
console.log(toyProblem(6, 0, 10, 3));
Nesting the 2 loops will result in doing 6 + 6 - 6 * 6 / 6 + 0 - 0 * 0 / 0 + 10 - 10 * 10 / 10 + 3 - 3 * 3 / 3
I didn't find a way to do this without eval as looping through operations one by one would modify the operators priority so this is what I propose : Building an operation 'query' to be eval'd and returned.
Hope this helps
var toyProblem = function () {
var operation = '';
var operators = ['+','-','*','/'];
var args = Array.from(arguments);
args.forEach(function (arg, index) {
if (index > 0) {
operation += operators[index - 1];
}
operation += arg;
});
return eval(operation);
}
console.log(6 + 0 - 10 * 3);
console.log(toyProblem(6, 0, 10, 3)); //6 + 0 - 10 * 3 === -24)
Let's decompose the problem. You have a variadic function that accepts unknown number of arguments and applies an operator to each next argument depending on the index of that element.
Because the number of arguments can be greater than the number of operators, it's appropriate to use modulo operator to infinitely loop through the array of operators while going once through the list of arguments.
The eval operation takes a string, evaluates it, and returns the result of evaluation of the expression that string represents. So you're on the right track. But because eval function takes a string as the first argument, I'd recommend using template literals, it's supported in almost all browsers natively and doesn't need to be transpiled into good old ES5.
The function then would look like this:
function toyProblem(first = 0, ...args) {
const operators = ['+', '-', '*', '/'];
let sol = first;
for (let i in args) {
sol = eval(`${sol} ${operators[i % operators.length]} ${args[i]}`);
}
return sol;
}
However, as there is recommended in the comments, using eval isn't something you'd like to ship to users. Instead, I'd suggest using functions. Functions in Javascript are first-class citizens, so you can pass them as an argument.
Imagine that you have a function (a, b) => a + b instead of just a string "+". The code would then look like this:
function toyProblem(first = 0, ...args) {
const operations = [
(a, b) => a + b,
(a, b) => a - b,
(a, b) => a * b,
(a, b) => a / b,
];
let sol = first;
for (let i in args) {
sol = operations[i](sol, args[i]);
}
return sol;
}
You could go even further and make the function universal in terms of possible operations. Have fun!
Since you are hard coding the names of the operators you might as well hard code the functions and avoid eval. You put the functions into an array that will let you loop through. Then you can just reduce through the arguments with a simple one-liner, which will handle any amount of arguments:
const op = [
(a, b) => a + b,
(a, b) => a - b,
(a, b) => a * b,
(a, b) => a / b
]
function prob(...args){
return args.reduce((curr, acc, idx) => op[(idx - 1) % op.length](curr, acc))
}
console.log(prob(6, 0, 10, 3))
console.log(prob(6, 0, 10, 3, 20, 11, 15, 100))
To get product -12 the first three parts of the expression need to be evaluated within parentheses, else the result will be -24. You can use String.prototype.replace() to replace "," characters after calling .toString() on input array, replace the "," with the operator, return the expression (6 + 0 - 10) * 3 from Function() constructor
var toyProblem = function () {
var operators = ['+','-','*'];
var opts = operators.slice(0);
var n = [...arguments];
var res = n.toString().replace(/,/g, () => opts.shift());
var index = res.indexOf(operators[operators.length -1]);
return new Function(`return (${res.slice(0, index)})${res.slice(index)}`)();
}
var product = toyProblem(6, 0, 10, 3);
console.log(product);
I've been working with JavaScript for a few days now and have got to a point where I want to overload operators for my defined objects.
After a stint on google searching for this it seems you can't officially do this, yet there are a few people out there claiming some long-winded way of performing this action.
Basically I've made a Vector2 class and want to be able to do the following:
var x = new Vector2(10,10);
var y = new Vector2(10,10);
x += y; //This does not result in x being a vector with 20,20 as its x & y values.
Instead I'm having to do this:
var x = new Vector2(10,10);
var y = new Vector2(10,10);
x = x.add(y); //This results in x being a vector with 20,20 as its x & y values.
Is there an approach I can take to overload operators in my Vector2 class? As this just looks plain ugly.
As you've found, JavaScript doesn't support operator overloading. The closest you can come is to implement toString (which will get called when the instance needs to be coerced to being a string) and valueOf (which will get called to coerce it to a number, for instance when using + for addition, or in many cases when using it for concatenation because + tries to do addition before concatenation), which is pretty limited. Neither lets you create a Vector2 object as a result. Similarly, Proxy (added in ES2015) lets you intercept various object operations (including property access), but again won't let you control the result of += on Vector instances.
For people coming to this question who want a string or number as a result (instead of a Vector2), though, here are examples of valueOf and toString. These examples do not demonstrate operator overloading, just taking advantage of JavaScript's built-in handling converting to primitives:
valueOf
This example doubles the value of an object's val property in response to being coerced to a primitive, for instance via +:
function Thing(val) {
this.val = val;
}
Thing.prototype.valueOf = function() {
// Here I'm just doubling it; you'd actually do your longAdd thing
return this.val * 2;
};
var a = new Thing(1);
var b = new Thing(2);
console.log(a + b); // 6 (1 * 2 + 2 * 2)
Or with ES2015's class:
class Thing {
constructor(val) {
this.val = val;
}
valueOf() {
return this.val * 2;
}
}
const a = new Thing(1);
const b = new Thing(2);
console.log(a + b); // 6 (1 * 2 + 2 * 2)
Or just with objects, no constructors:
var thingPrototype = {
valueOf: function() {
return this.val * 2;
}
};
var a = Object.create(thingPrototype);
a.val = 1;
var b = Object.create(thingPrototype);
b.val = 2;
console.log(a + b); // 6 (1 * 2 + 2 * 2)
toString
This example converts the value of an object's val property to upper case in response to being coerced to a primitive, for instance via +:
function Thing(val) {
this.val = val;
}
Thing.prototype.toString = function() {
return this.val.toUpperCase();
};
var a = new Thing("a");
var b = new Thing("b");
console.log(a + b); // AB
Or with ES2015's class:
class Thing {
constructor(val) {
this.val = val;
}
toString() {
return this.val.toUpperCase();
}
}
const a = new Thing("a");
const b = new Thing("b");
console.log(a + b); // AB
Or just with objects, no constructors:
var thingPrototype = {
toString: function() {
return this.val.toUpperCase();
}
};
var a = Object.create(thingPrototype);
a.val = "a";
var b = Object.create(thingPrototype);
b.val = "b";
console.log(a + b); // AB
As T.J. said, you cannot overload operators in JavaScript. However you can take advantage of the valueOf function to write a hack which looks better than using functions like add every time, but imposes the constraints on the vector that the x and y are between 0 and MAX_VALUE. Here is the code:
var MAX_VALUE = 1000000;
var Vector = function(a, b) {
var self = this;
//initialize the vector based on parameters
if (typeof(b) == "undefined") {
//if the b value is not passed in, assume a is the hash of a vector
self.y = a % MAX_VALUE;
self.x = (a - self.y) / MAX_VALUE;
} else {
//if b value is passed in, assume the x and the y coordinates are the constructors
self.x = a;
self.y = b;
}
//return a hash of the vector
this.valueOf = function() {
return self.x * MAX_VALUE + self.y;
};
};
var V = function(a, b) {
return new Vector(a, b);
};
Then you can write equations like this:
var a = V(1, 2); //a -> [1, 2]
var b = V(2, 4); //b -> [2, 4]
var c = V((2 * a + b) / 2); //c -> [2, 4]
It's possible to do vector math with two numbers packed into one. Let me first show an example before I explain how it works:
let a = vec_pack([2,4]);
let b = vec_pack([1,2]);
let c = a+b; // Vector addition
let d = c-b; // Vector subtraction
let e = d*2; // Scalar multiplication
let f = e/2; // Scalar division
console.log(vec_unpack(c)); // [3, 6]
console.log(vec_unpack(d)); // [2, 4]
console.log(vec_unpack(e)); // [4, 8]
console.log(vec_unpack(f)); // [2, 4]
if(a === f) console.log("Equality works");
if(a > b) console.log("Y value takes priority");
I am using the fact that if you bit shift two numbers X times and then add or subtract them before shifting them back, you will get the same result as if you hadn't shifted them to begin with. Similarly scalar multiplication and division works symmetrically for shifted values.
A JavaScript number has 52 bits of integer precision (64 bit floats), so I will pack one number into he higher available 26 bits, and one into the lower. The code is made a bit more messy because I wanted to support signed numbers.
function vec_pack(vec){
return vec[1] * 67108864 + (vec[0] < 0 ? 33554432 | vec[0] : vec[0]);
}
function vec_unpack(number){
switch(((number & 33554432) !== 0) * 1 + (number < 0) * 2){
case(0):
return [(number % 33554432),Math.trunc(number / 67108864)];
break;
case(1):
return [(number % 33554432)-33554432,Math.trunc(number / 67108864)+1];
break;
case(2):
return [(((number+33554432) % 33554432) + 33554432) % 33554432,Math.round(number / 67108864)];
break;
case(3):
return [(number % 33554432),Math.trunc(number / 67108864)];
break;
}
}
The only downside I can see with this is that the x and y has to be in the range +-33 million, since they have to fit within 26 bits each.
Actually, there is one variant of JavaScript that does support operator overloading. ExtendScript, the scripting language used by Adobe applications such as Photoshop and Illustrator, does have operator overloading. In it, you can write:
Vector2.prototype["+"] = function( b )
{
return new Vector2( this.x + b.x, this.y + b.y );
}
var a = new Vector2(1,1);
var b = new Vector2(2,2);
var c = a + b;
This is described in more detail in the "Adobe Extendscript JavaScript tools guide" (current link here). The syntax was apparently based on a (now long abandoned) draft of the ECMAScript standard.
FYI paper.js solves this issue by creating PaperScript, a self-contained, scoped javascript with operator overloading of vectors, which it then processing back into javascript.
But the paperscript files need to be specifically specified and processed as such.
We can use React-like Hooks to evaluate arrow function with different values from valueOf method on each iteration.
const a = Vector2(1, 2) // [1, 2]
const b = Vector2(2, 4) // [2, 4]
const c = Vector2(() => (2 * a + b) / 2) // [2, 4]
// There arrow function will iterate twice
// 1 iteration: method valueOf return X component
// 2 iteration: method valueOf return Y component
const Vector2 = (function() {
let index = -1
return function(x, y) {
if (typeof x === 'function') {
const calc = x
index = 0, x = calc()
index = 1, y = calc()
index = -1
}
return Object.assign([x, y], {
valueOf() {
return index == -1 ? this.toString() : this[index]
},
toString() {
return `[${this[0]}, ${this[1]}]`
},
len() {
return Math.sqrt(this[0] ** 2 + this[1] ** 2)
}
})
}
})()
const a = Vector2(1, 2)
const b = Vector2(2, 4)
console.log('a = ' + a) // a = [1, 2]
console.log(`b = ${b}`) // b = [2, 4]
const c = Vector2(() => (2 * a + b) / 2) // [2, 4]
a[0] = 12
const d = Vector2(() => (2 * a + b) / 2) // [13, 4]
const normalized = Vector2(() => d / d.len()) // [0.955..., 0.294...]
console.log(c, d, normalized)
Library #js-basics/vector uses the same idea for Vector3.
I wrote a library that exploits a bunch of evil hacks to do it in raw JS. It allows expressions like these.
Complex numbers:
>> Complex()({r: 2, i: 0} / {r: 1, i: 1} + {r: -3, i: 2}))
<- {r: -2, i: 1}
Automatic differentiation:
Let f(x) = x^3 - 5x:
>> var f = x => Dual()(x * x * x - {x:5, dx:0} * x);
Now map it over some values:
>> [-2,-1,0,1,2].map(a=>({x:a,dx:1})).map(f).map(a=>a.dx)
<- [ 7, -2, -5, -2, 7 ]
i.e. f'(x) = 3x^2 - 5.
Polynomials:
>> Poly()([1,-2,3,-4]*[5,-6]).map((c,p)=>''+c+'x^'+p).join(' + ')
<- "5x^0 + -16x^1 + 27x^2 + -38x^3 + 24x^4"
For your particular problem, you would define a Vector2 function (or maybe something shorter) using the library, then write x = Vector2()(x + y);
https://gist.github.com/pyrocto/5a068100abd5ff6dfbe69a73bbc510d7
Whilst not an exact answer to the question, it is possible to implement some of the python __magic__ methods using ES6 Symbols
A [Symbol.toPrimitive]() method doesn't let you imply a call Vector.add(), but will let you use syntax such as Decimal() + int.
class AnswerToLifeAndUniverseAndEverything {
[Symbol.toPrimitive](hint) {
if (hint === 'string') {
return 'Like, 42, man';
} else if (hint === 'number') {
return 42;
} else {
// when pushed, most classes (except Date)
// default to returning a number primitive
return 42;
}
}
}
https://www.keithcirkel.co.uk/metaprogramming-in-es6-symbols/
Interesting is also experimental library operator-overloading-js . It does overloading in a defined context (callback function) only.