I'm trying to create a function that performs Sigma notation calculations in JavaScript. (If you don't know Sigma notation, it will be clear what I'm trying to do below.) My goal is to make a function that can be written as easily as Sigma notation and return the solution that the Sigma notation would calculate. Ideally, I would like calls to the function to only have to provide the starting value, ending value, and the calculation to be performed on each number in the set of numbers before summing them as arguments.
For example,
thisIsMySigmaNotationFunction(1, 4, 2i+1)
would return:
(2(1)+1) + (2(2)+1) + (2(3)+1) + (2(4)+1) = 24
Here is the code I created so far, which works, but I have to create a separate function to use as the 2i+1 argument. I'm wondering if there is a way to avoid this and call the function as above since 2i+1 might need to change to i/(i+1) or other calculations in the future and it would be great to not have to create a separate function to insert as an argument each time.
function sigmaCalculation(start, end, whatToSum){
var sum = 0;
for (var i = start; i <= end; i++){
sum += whatToSum(i);
};
console.log(sum);
}
function calculationToSum(this1){
return 2*this1+1;
}
6 Answers
If it helps at all, you don't need to make named functions for every time you call this, you can use anonymous functions:
sigmaCalculation(1, 4, function(x) { return 2 * x + 1; });
Which can be pretty compact.
Now if you want to do i/(i+1), you just change your call to:
sigmaCalculation(1, 4, function(x) { return x / (x + 1); });
Arrow functions now make this less annoying.
function sigma(start, end, modifier) {
const length = end - start + 1;
const map = (v, k) => modifier ? modifier(k + start) : k + start;
const sum = (a, b) => a + b;
return Array.from({ length }, map).reduce(sum);
}
sigma(3, 5); // 12
sigma(3, 5, i => i+2); // 18
sigma(3, 5, i => i*2); // 24
sigma(3, 5, i => i/(i+1)); // 2.3833333333333333
Adding an anonymous function does the job. We can even perform different calculations each time we call the function by changing calculations at the function call.
function sigmaCal(start, end, calculation){
var sigma=0;
for(var i=start; i<=end; i++){
sigma += calculation(i);
}
console.log(sigma);
}
sigmaCal(1,4, function(x){ return 2*x +1;});
Output: 24
To be able to using a string-based input instead of a function, you can use JavaScript's eval:
function sigmaCalculation(start, end, whatToSum){
var sum = 0;
for (var i = start; i <= end; i++){
sum += eval(whatToSum.replace("i", i));
};
console.log(sum);
}
sigmaCalculation(0, 5, "2*i+1");
Note that this is not very safe, especially when getting input from a user, as eval basically runs any and all JavaScript code.
thisIsMySigmaNotationFunction(1, 4, 2i+1)
That's syntactically invalid. The only way to avoid passing a function (like in @MattBurland's answer) is to create the function dynamically, e.g. from a string. I've built a little helper function based on Osteele's functional library:
function F(body) {
var args = body.match(/2i+1/g).sort();
return new Function(args, "return "+body.replace(/(\d+)([a-z])/g, "$1*$2"));
}
With that, you can write
thisIsMySigmaNotationFunction(1, 4, F("2i+1"))
I have a slightly different approach to @Cezary Wojcik which takes a string and evals it but refuses to eval any non-mathematical expression: (it also adds support for exponents notated with n^x syntax)
function sigmaCalc(start,end,exp){
var sum = 0;
for (var i = start; i <= end; i++) {
sum += (exp.replace('^','**').match(/^[\d\+\-\*\/\(\)i]+$/)) ? eval(exp.replace('i',i)) : NaN }
return sum;
}
function execCalc() {
const min = new Number(document.querySelector('input[name=min]').value);
const max = new Number(document.querySelector('input[name=max]').value);
const exp = document.querySelector('input[name=exp]').value;
document.getElementById('result').innerText = `Result: ${sigmaCalc(min, max, exp)}`;
}
<form>
<label for="min">Min: <input name="min" min="0" type="number" value="1" placeholder="1"></label><br>
<label for="min">Max: <input name="max" min="0" type="number" value="10" placeholder="10"></label><br>
<label for="min">Exp: <input name="exp" type="text" value="4*(i-1)+4" placeholder="4*(i-1)+4"></label><br>
<input type="submit" value="calculate" onclick="event.preventDefault(); execCalc();">
</form>
<br>
<br>
<div id="result">Result: 220</div>