Calculating the average of several function invocations using closures - javascript

I am doing a coding challenge that reads like this:
Create a function runningAverage() that returns a callable function object. Update the series with each given value and calculate the current average.
rAvg = runningAverage();
rAvg(10) = 10.0;
rAvg(11) = 10.5;
rAvg(12) = 11;
I got a working solution, yet they also want the results to be rounded like this:
rAvg(13) = 13.50678; => 13.50
rAvg(13) = 13.50; => 13.50
rAvg(13) = 13.5; => 13.5
rAvg(13) = 13; => 13
Here is my code:
function runningAverage() {
let number = 0;
let numbOfFunctionCalls = 0;
return function (y) {
number += y;
numbOfFunctionCalls ++;
let average = (number/numbOfFunctionCalls);
let averageArray = average.toString().split('.');
//to get the number of decimal places
//e.g 11.543 ==> ['11', '543']
if ((Array.from(averageArray[1]).length) >= 2) {
return average.toPrecision(2);
}
else if ((Array.from(averageArray[1]).length) = 1) {
return average.toPrecision(1);
}
else {
return average;
}
}
}
I tested parts of the function separately and it seems to work, yet when I invoke it I get the message 'cannot convert undefined or null to object'.

This sounds like a fun coding challenge!
In this case, you want toFixed(), not toPrecision(). toPrecision() essentially allows you determine how many digits TOTAL (including those on the left of the decimal point) should appear, whereas toFixed() focuses on the number of digits to the right of the decimal point. Feel free to look these two methods up on MDN. When you read that toPrecision() may return exponential notation, this should make you pause and think, "That's weird. Why does this happen? When does this happen?", rather than "this detail is unimportant."
Your .length = 1 comparison needs to be modified to a ===.
Your code currently fails if an integer is the first number provided to rAvg(). In your first conditional, Array.from(undefined) may run, which is not permissible in JavaScript. You should consider ways to only work with "the digits to the right of the decimal" only if "there are digits to the right of the decimal."

Here is a working solution including all the suggestions, in case someone is interested:
function runningAverage() {
let number = 0;
let numbOfFunctionCalls = 0;
return function (y) {
number += y;
numbOfFunctionCalls ++;
let average = (number/numbOfFunctionCalls);
let numIsDecimal = average.toString().includes('.');
if (numIsDecimal) {
let averageArray = average.toString().split('.');
//to get the number of decimal places
//e.g 11.543 ==> ['11', '543']
if ((Array.from(averageArray[1]).length) >= 2) {
return Number(average.toFixed(2));
}
if ((Array.from(averageArray[1]).length) === 1) {
return Number(average.toFixed(1));
}
}
else {
return Number(average);
}
}
}

Not sure if this works but try it
function runningAverage() {
let number = 0;
let numbOfFunctionCalls = 0;
return function (y) {
number += y;
numbOfFunctionCalls ++;
let average = (number/numbOfFunctionCalls);
let averageArray = average.toString().split('.');
if ((Array.from(averageArray[1]).length) >= 2) {
return Math.round(average.toPrecision(2) * 2) / 2;
} else if ((Array.from(averageArray[1]).length) == 1) {
return Math.round(average.toPrecision(1) * 2) / 2;
} else {
return Math.round(average * 2) / 2;
};
};
};

Related

Recursive approach to Persistent bugger problem returns undefined

I've been trying to solve the following problem in codewars using recursion:
Write a function, persistence, that takes in a positive parameter num and returns its multiplicative persistence, which is the number of times you must multiply the digits in num until you reach a single digit.
For example (Input --> Output):
39 --> 3 (because 3*9 = 27, 2*7 = 14, 1*4 = 4 and 4 has only one digit)
999 --> 4 (because 9*9*9 = 729, 7*2*9 = 126, 1*2*6 = 12, and finally 1*2 = 2)
4 --> 0 (because 4 is already a one-digit number)
Here's what I've tried:
var numOfIterations = 0;
function persistence(num) {
//code me
var i;
var digits=[];
var result = 1;
if (num.toString().length==1) {
return numOfIterations;
} else {
numOfIterations++;
digits = Array.from(String(num), Number);
for (i=0;i<digits.size;i++) {
result=result*digits[i];
}
persistence(result);
}
}
But for some reason, instead of returning the number of iterations, it returns undefined. I've been told that I'm not using recursion correctly, but I just can't find the problem.
Other answers have explained what's wrong with your code. I just want to point out a simpler implementation:
const multiplyDigits = (n) =>
n < 10 ? n : (n % 10) * multiplyDigits (n / 10 | 0);
const persistence = (n) =>
n < 10 ? 0 : 1 + persistence (multiplyDigits (n));
[39, 999, 4] .forEach (t => console .log (`${t}:\t${persistence (t)}`));
multiplyDigits does just what it says, recursively multiplying the final digit by the number left when you remove that last digit (Think of | 0 as like Math .floor), and stopping when n is a single digit.
persistence checks to see if we're already a single digit, and if so, returns zero. If not, we add one to the value we get when we recur on the multiple of the digits.
I've been told that I'm not using recursion correctly
You're recursing, but you're not returning the result of that recursion. Imagine for a moment just this structure:
function someFunc() {
if (someCondition) {
return 1;
} else {
anotherFunc();
}
}
If someCondition is false, what does someFunc() return? Nothing. So it's result is undefined.
Regardless of any recursion, at its simplest if you want to return a result from a function then you need to return it:
function persistence(num) {
//...
if (num.toString().length==1) {
//...
} else {
//...
return persistence(result); // <--- here
}
}
As #David wrote in his answer, you were missing the return of the recursive call to itself.
Plus you were using digits.size instead of digits.length.
Anyway consider that one single digit being zero will collpse the game because that's enough to set the result to zero despite how many digits the number is made of.
To deal with the reset of numOfIterations, at first I tried using function.caller to discriminate between recursive call and direct call and set the variable accordingly. Since that method is deprecated as shown here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller
I opted for the optional argument iteration that gets set to zero as default, to keep track of that value while it goes down the call stack. This solution still fulfills the fact that the caller doesn't need to know a new interface for the function to work.
//var numOfIterations = 0;
function persistence(num, iteration=0) {
/*
Commented strategy using the function.caller
working but deprecated so I can't recommend anymore
used optional argument iteration instead
//gets the name of the caller scope
let callerName = persistence.caller?.name;
//if it's different from the name of this function
if (callerName !== 'persistence')
//reset the numOfIterations
numOfIterations = 0;
*/
var digits=[];
if (num.toString().length==1){
return iteration;
} else {
var result = 1;
digits = Array.from(String(num), Number);
for (let i=0;i<digits.length;i++) {
result = result * digits[i];
}
return persistence(result, iteration+1);
}
}
console.log( persistence(39) ); //-> 3
console.log( persistence(999 ) ); //-> 4
console.log( persistence(4) ); //-> 0
You can do something like this
const persistenceTailRecursive = (num, iterations = 0) => {
const str = '' + num;
if(str.length === 1){
return iterations;
}
return persistenceTailRecursive(str.split('').reduce((res, a) => res * parseInt(a), 1), iterations + 1)
}
const persistence = (num) => {
const str = '' + num;
if(str.length === 1){
return 0;
}
return 1 + persistence(str.split('').reduce((res, a) => res * parseInt(a), 1))
}
console.log(persistenceTailRecursive(93))
console.log(persistenceTailRecursive(999))
console.log(persistence(93))
console.log(persistence(999))
There are 2 versions
1 tailRecursive call the same method with the exact signature (preventing stackoverflow in some languages like scala)
2 basic the result is calculated at the end

Trying to find sum of factorial number using big-int npm gives wrong answer

I am doing euler problem where you need to find the sum of integers of a factorial number. so for example 10! is 3 + 6 + 2 + 8 + 8 + 0 + 0 = 27.
I wrote this using big-int library to deal with large numbers.
factorialize =(num)=> {
if (num < 0) {
return -1;
}
else if (num == 0) {
return 1;
}
else {
return (num * factorialize(num - 1));
}
}
findFactorialSum=(x)=>{
let total=0;
let result = bigInt(factorialize(x));
// let result=factorialize(x).toString().split("").map(el => parseInt(el));
// result.split("");
let converted = result.toString().split("").map(el => parseInt(el));
console.log(converted);
for(let i=0;i<=converted.length-1;i++)
{
total=total+converted[i]
}
console.log(total);
return total;
}
this works for small factorials and gives right answers but as soon as you go for something bigger then 12 it gives wrong answers, for example for 100 I get 683 but the answer according to the site should be 648 ><. I am guessing the big int library i am using returns wrong number but it worked for smaller numbers so I don't see what the issue can be.
I'm assuming the BigInt library you are using takes a big number as a string. Something like
bigint("23837458934509644434537504952635462348")
You are doing
let result = bigInt(factorialize(x));
The call to factorialize(100) has already overflowed Javascript's MAX_SAFE_INTEGER and passes the wrong string to the bigInt call.
You have to use BigInts to calculate the factorial as well.
Additionally to Jeril's answer which is your curlpit, you can also use reduce to calculate the sum of an Array. Demo:
const factorialize = (bigNum) => {
if (bigNum.lt(0)) {
return bigInt(-1);
} else if (bigNum.eq(0)) {
return bigInt(1);
} else {
return bigNum.times(factorialize(bigNum.minus(1)));
}
};
const findFactorialSum = (x) => {
const result = factorialize(bigInt(x)),
total = result.toString().split('')
.reduce((sum, digit) => sum + +digit, 0);
console.log(result.toString().split('').join('+') + ' = ' + total);
return total;
};
findFactorialSum(10); // 27
findFactorialSum(15); // 45
findFactorialSum(20); // 54
<script src="https://peterolson.github.io/BigInteger.js/BigInteger.min.js"></script>

Need help writing code to convert decimal to binary without the use of the toString

I'm trying to create my own decimal to binary converter with the method of decrementing the inputted variable (decimal value), by dividing it by 2 and storing the remainder (like 2nd grade math remainder), which is always either 0 or 1. Each of the remainder values i thin should be stored in an array and I think maybe put in backwards so that the most significant digit is first in the array (this is because when decrementing the remainer values are filled in left to right). Soooo yea i dont really know how to store the remainder values in an array using a function
Thanks in advance and if something is confusing then feel free to ask because im not even sure if this is the best method of doing this its just what i came up with
function decimalToBinary(num) {
var bin = 0;
while (num > 0) {
bin = num % 2 + bin;
num >>= 1; // basically /= 2 without remainder if any
}
alert("That decimal in binary is " + bin);
}
Your code is almost correct. The main problem is that bin starts out as 0; when you add a digit, they are added numerically, so your code ends up just counting the binary 1s: in this manner, 10 is initial 0, and +1+0+1+0, resulting in 2. You want to handle it as a string: ""+1+0+1+0 results in 1010. So, the only needed change is:
var bin = "";
If you want to solve it using arrays, with minimal changes to your code, it would be:
function decimalToBinary(num) {
var bin = [];
while (num > 0) {
bin.unshift(num % 2);
num >>= 1; // basically /= 2 without remainder if any
}
alert("That decimal in binary is " + bin.join(''));
}
Here, I use .unshift to add an element to the head of the array (and renumbering the remaining elements); .join() to collect them all into a string.
Or this:
function decimalToBinary(num) {
var bin = [];
while (num > 0) {
bin[bin.length] = num % 2;
num >>= 1; // basically /= 2 without remainder if any
}
alert("That decimal in binary is " + bin.reverse().join(''));
}
This is not as good, but illustrates some more things you can do with arrays: taking their length, setting an arbitrary element, and flipping them around.
I have written a custom Decimal to Binary method:
function toBinary (input) {
let options = [1];
let max = 0;
let i = 1;
while(i) {
max = Math.pow(2, i);
if (max > input) break;
options.push(max);
i++;
}
let j = options.length;
let result = new Array(j);
result.fill("0");
while(j >= 0) {
if (options[j] <= input) {
result[j] = "1"
input = input - options[j];
}
j--;
}
return [...result].reverse().join("");
}
//Test the toBin method with built-in toString(2)
toBinary(100) === (100).toString(2) // true
toBinary(1) === (1).toString(2) // true
toBinary(128) === (128).toString(2) // true

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.

Round number up to the nearest multiple of 3

How would I go about rounded a number up the nearest multiple of 3?
i.e.
25 would return 27
1 would return 3
0 would return 3
6 would return 6
if(n > 0)
return Math.ceil(n/3.0) * 3;
else if( n < 0)
return Math.floor(n/3.0) * 3;
else
return 3;
Simply:
3.0*Math.ceil(n/3.0)
?
Here you are!
Number.prototype.roundTo = function(num) {
var resto = this%num;
if (resto <= (num/2)) {
return this-resto;
} else {
return this+num-resto;
}
}
Examples:
y = 236.32;
x = y.roundTo(10);
// results in x = 240
y = 236.32;
x = y.roundTo(5);
// results in x = 235
I'm answering this in psuedocode since I program mainly in SystemVerilog and Vera (ASIC HDL). % represents a modulus function.
round_number_up_to_nearest_divisor = number + ((divisor - (number % divisor)) % divisor)
This works in any case.
The modulus of the number calculates the remainder, subtracting that from the divisor results in the number required to get to the next divisor multiple, then the "magic" occurs. You would think that it's good enough to have the single modulus function, but in the case where the number is an exact multiple of the divisor, it calculates an extra multiple. ie, 24 would return 27. The additional modulus protects against this by making the addition 0.
As mentioned in a comment to the accepted answer, you can just use this:
Math.ceil(x/3)*3
(Even though it does not return 3 when x is 0, because that was likely a mistake by the OP.)
Out of the nine answers posted before this one (that have not been deleted or that do not have such a low score that they are not visible to all users), only the ones by Dean Nicholson (excepting the issue with loss of significance) and beauburrier are correct. The accepted answer gives the wrong result for negative numbers and it adds an exception for 0 to account for what was likely a mistake by the OP. Two other answers round a number to the nearest multiple instead of always rounding up, one more gives the wrong result for negative numbers, and three more even give the wrong result for positive numbers.
This function will round up to the nearest multiple of whatever factor you provide.
It will not round up 0 or numbers which are already multiples.
round_up = function(x,factor){ return x - (x%factor) + (x%factor>0 && factor);}
round_up(25,3)
27
round up(1,3)
3
round_up(0,3)
0
round_up(6,3)
6
The behavior for 0 is not what you asked for, but seems more consistent and useful this way. If you did want to round up 0 though, the following function would do that:
round_up = function(x,factor){ return x - (x%factor) + ( (x%factor>0 || x==0) && factor);}
round_up(25,3)
27
round up(1,3)
3
round_up(0,3)
3
round_up(6,3)
6
Building on #Makram's approach, and incorporating #Adam's subsequent comments, I've modified the original Math.prototype example such that it accurately rounds negative numbers in both zero-centric and unbiased systems:
Number.prototype.mround = function(_mult, _zero) {
var bias = _zero || false;
var base = Math.abs(this);
var mult = Math.abs(_mult);
if (bias == true) {
base = Math.round(base / mult) * _mult;
base = (this<0)?-base:base ;
} else {
base = Math.round(this / _mult) * _mult;
}
return parseFloat(base.toFixed(_mult.precision()));
}
Number.prototype.precision = function() {
if (!isFinite(this)) return 0;
var a = this, e = 1, p = 0;
while (Math.round(a * e) / e !== a) { a *= 10; p++; }
return p;
}
Examples:
(-2).mround(3) returns -3;
(0).mround(3) returns 0;
(2).mround(3) returns 3;
(25.4).mround(3) returns 24;
(15.12).mround(.1) returns 15.1
(n - n mod 3)+3
$(document).ready(function() {
var modulus = 3;
for (i=0; i < 21; i++) {
$("#results").append("<li>" + roundUp(i, modulus) + "</li>")
}
});
function roundUp(number, modulus) {
var remainder = number % modulus;
if (remainder == 0) {
return number;
} else {
return number + modulus - remainder;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Round up to nearest multiple of 3:
<ul id="results">
</ul>
A more general answer that might help somebody with a more general problem: if you want to round numbers to multiples of a fraction, consider using a library. This is a valid use case in GUI where decimals are typed into input and for instance you want to coerce them to multiples of 0.25, 0.2, 0.5 etc. Then the naive approach won't get you far:
function roundToStep(value, step) {
return Math.round(value / step) * step;
}
console.log(roundToStep(1.005, 0.01)); // 1, and should be 1.01
After hours of trying to write up my own function and looking up npm packages, I decided that Decimal.js gets the job done right away. It even has a toNearest method that does exactly that, and you can choose whether to round up, down, or to closer value (default).
const Decimal = require("decimal.js")
function roundToStep (value, step) {
return new Decimal(value).toNearest(step).toNumber();
}
console.log(roundToStep(1.005, 0.01)); // 1.01
RunKit example
Using remainder operator (modulus):
(n - 1 - (n - 1) % 3) + 3
By the code given below use can change any numbers and you can find any multiple of any number
let numbers = [8,11,15];
let multiple = 3
let result = numbers.map(myFunction);
function myFunction(n){
let answer = Math.round(n/multiple) * multiple ;
if (answer <= 0)
return multiple
else
return answer
}
console.log("Closest Multiple of " + multiple + " is " + result);
if(x%3==0)
return x
else
return ((x/3|0)+1)*3

Categories

Resources