I want to achieve something like this in JavaScript:
input = 2455.55
f(input) = 2456
f(input) = 2460
f(input) = 2500
f(input) = 3000
f(input) = 2455.55
I am using the Math.round() method for now but only get to 2,546 with it. Wondering if there is a best way to achieve the rest.
You can divide your number by ten until you get a non-integer, round it up and then multiply by ten again the same amount of time. Something like this:
function roundUp(n) {
var n2 = n;
var i=0;
while (Number.isInteger(n2)) {
n2 /= 10;
i++;
}
return Math.round(n2) * Math.pow(10, i);
}
console.log(roundUp(2455.55)); // 2456
console.log(roundUp(2456)); // 2460
console.log(roundUp(2460)); // 2500
console.log(roundUp(2500)); // 3000
Based on your desired output it looks like you need to track the number of function calls. This doesn't seem to be an argument to your function.
Given the constraint that you have only a single argument, the implementation looks probably like
var lastNum = 0
var digitsToRound = 0
function roundUp(input) {
// Verify whether the function is called with the same argument as last call.
// Note that we cannot compare floating point numbers.
// See https://dev.to/alldanielscott/how-to-compare-numbers-correctly-in-javascript-1l4i
if (Math.abs(input - lastNum) < Number.EPSILON) {
// If the number of digitsToRound exceeds the number of digits in the input we want
// to reset the number of digitsToRound. Otherwise we increase the digitsToRound.
if (digitsToRound > (Math.log10(input) - 1)) {
digitsToRound = 0;
} else {
digitsToRound = digitsToRound + 1;
}
} else {
// The function was called with a new input, we reset the digitsToRound
digitsToRound = 0;
lastNum = input;
}
// Compute the factor by which we need to divide and multiply to round the input
// as desired.
var factor = Math.max(1, Math.pow(10, digitsToRound));
return Math.ceil(input / factor) * factor;
}
console.log(roundUp(2455.55)); // 2456
console.log(roundUp(2455.55)); // 2460
console.log(roundUp(2455.55)); // 2500
console.log(roundUp(2455.55)); // 3000
thanks, nice one! Inspired by your answer, I solved it like so:
function roundNumber(num, n) {
const divider = Math.pow(10, n);
return Math.round(num / divider) * divider;
};
Related
I have a floating point number (for example): 0.004178174922295
How could I get the decremental function to make a calculations from this number to 0 in specific amount of time (for example 1 second)?
Thanks.
Expected values:
0.004178174922295
0.004178174922294
0.004178174922293
...
0
As raina77ow and others pointed out in the comments, operations with decimal numbers are problematic in JS, approximations are made and the results may be inexact.
A workaround would be turn the infinitesimals into big integral numbers, work with them and convert them back at the end.
Is this what you were looking for? Please let me know.
EDIT
You can ask for the countdown to be done in a certain amount of time, it does work with reasonable numbers, but in Javascript the minimum interval is of 10 milliseconds, you can't call intervals shorter than that. With the example number you gave, 0.004178174922295, it's like counting down from 4178174922295 to zero. That would requiere almost 1325 years in 10 millisecond intervals (if my math is correct, either way I expect you were going to pass a much shorter lapse).
function infinitesimalCountDown(num, seconds) {
// I create a coeficient to convert the decimal to an int
// Will be a big number starting with "1" and followed by a bunch of zeroes
let coefString = '1';
for(let i=0; i<num.toString().length-2; i++) {
coefString += '0';
}
const coef = Number(coefString);
// This has the digits from the original original but it's an int
let counter = Math.round(num*coef);
// Now I can just treat it as an int and convert it back for the output
const icdInterval = setInterval(() => {
counter--;
console.log(counter/coef);
if(counter <= 0) clearInterval(icdInterval);
}, Math.round(seconds*1000/counter));
}
console.log("It works with a short number");
infinitesimalCountDown(0.0041, 10);
setTimeout(() => {
console.log("It doesn't work with a long number");
infinitesimalCountDown(0.004178174922295, 3000);
}, 12 * 1000);
If you are fine with the steps being the necessary for Javascript to be able to process it, you can do the following:
function infinitesimalCountDown(num, seconds) {
let coefString = '1'
for(let i=0; i<num.toString().length-2; i++) {
coefString += '0'
}
const coef = Number(coefString)
let counter = Math.round(num*coef)
let steps = seconds * 1000 / counter
steps = steps < 100 ? 100 : steps
let step = 1
if(steps == 100) {
step = counter / ((seconds * 1000) / steps)
}
console.log(step)
const icdInterval = setInterval(() => {
counter -= step;
if(counter <= 0) {
counter = 0
clearInterval(icdInterval)
}
console.log(counter/coef)
}, steps)
}
infinitesimalCountDown(0.004178174922295, 5)
If you can represent the input number as number type (so not have many decimals), you can do this using normal number subtraction.
Here, the important thing is to get the unit to be subtracted. You can get the unit using Math.pow.
And from this floating point guide, it is needed to round the counted number and that can be done using toFixed function.
let input = 0.004178174922295;
const decimalCount = input.toString().length - 2;
const unit = Math.pow(10, -1 * decimalCount);
console.log(input);
const loopInterval = setInterval(() => {
input = Number((input - unit).toFixed(decimalCount));
console.log(input);
if (input == 0) {
clearInterval(loopInterval);
}
}, 1000);
And if the input number has many decimals so it is received as string type (not able to present using number type), it is needed to do the subtraction using string as follows.
const input = '0.0041781749222934534534534535';
const inputArr = input.split('.');
const intNum = inputArr[0]; // Present integer
let decimals = inputArr[1]; // Present decimals after '.'
const unit = 1;
function replaceAt(str, index, replace) {
return str.substring(0, index) + replace + str.substring(index + 1);
}
console.log(input);
const loopInterval = setInterval(() => {
let index = decimals.length - 1;
while (parseInt(decimals[index]) < unit) {
decimals = replaceAt(decimals, index --, '9');
}
decimals = replaceAt(decimals, index, `${parseInt(decimals[index]) - unit}`);
console.log(`${intNum}.${decimals}`);
}, 1000);
I want the user to enter a number and print back the amount of digits of that number.
I know that I can use length, but my homework asking for while loop.
This is what I have so far:
var num;
var count = 0;
num = prompt('Enter number: ');
function counter(x, y) {
while (x > 0) {
y++;
x /= 10;
}
return y;
}
var result = counter(num, count);
console.log(result);
When I give the number 3456 (example), I get back the number 328. I want it to print back the number 4.
This line:
x /= 10;
Should be changed to:
x = Math.floor(x / 10);
The logic assumes integer division: 1234 is supposed to become 123, 12, 1 and 0. JavaScript does not have built in integer division so you need to use Math.floor to emulate it. Complete example with some fixes:
function countDigits(num) {
var count = 0;
while (num > 0) {
num = Math.floor(num / 10);
count++;
}
return count;
}
var num;
do {
num = Number(prompt("Enter number:"));
} while (Number.isNaN(num));
num = Math.abs(num); // just in case you want to handle -ve numbers
var result = countDigits(num);
console.log(result);
The problem is that the division operation will eventually end up converting x to a float and you'll have something like:
x / 10 === 0.1;
x / 10 === 0.01;
x / 10 === 0.001;
....
if you always parse (round) the result of the division to an integer, you'll get the expected result.
var num;
var count = 0;
num = prompt('Enter number: ');
function counter(x, y) {
while (x > 0) {
y++;
x = parseInt(x / 10);
}
return y;
}
var result = counter(num, count);
console.log(result);
You could check againt a number by taking the power of a decimal count.
function counter(value) {
var decimals = 0;
do {
decimals++;
} while (value >= 10 ** decimals)
return decimals;
}
console.log(counter(0));
console.log(counter(1));
console.log(counter(7));
console.log(counter(42));
console.log(counter(999));
console.log(counter(1000));
console.log(counter(1001));
First of all you should convert the input into a number, preferably using the Number function (using unary + has the same effect).
Secondly a division like 5 / 10 will return 0.5 which is bigger than 0. You should instead check if the number is bigger than or equal to 1.
function counter(num) {
num = Math.abs(num) / 10;
var count = 1;
while (num >= 1) {
count++;
num /= 10;
}
return count;
}
console.log(counter(+prompt('Enter number: ')));
You could also use a do while loop and avoid having an extra division outside the loop.
As others have pointed out, y doesn't need to be a parameter, it can be a local variable. But that's not your problem; let's add some extra logging to your loop:
function counter(x) {
let y=0;
while (x > 0) {
console.log("x=" + x + ", y=" + y);
y++;
x /= 10;
}
return y;
}
counter(3456);
The output looks like this:
x=3456, y=0
x=345.6, y=1
x=34.56, y=2
x=3.4560000000000004, y=3
x=0.3456, y=4
x=0.03456, y=5
...
You wanted the loop to stop at 0.3456, but that's still more than 0. (This mistake actually gives you a chance to learn something extra: can you explain why the loop ever finishes at all?)
Hopefully this will give you enough of a hint to complete the homework assignment - remember that debugging is an extremely important part of programming.
Please don't use cycles to measure length of an integer...
Use math instead! Logarithm will do much better job for you.
function numberLength(number) {
return Math.floor(Math.log10(Math.abs(number))) + 1
}
console.log(numberLength(YOUR_NUMBER));
This code returns NaN when the input is 0. I think it depends on your philosophy what length the 0 should have, so I am leaving that case unhandled.
I am generating 4 digit random number by using Math.floor(Math.random() * 9999). Now I have another requirement. I have to get the number of random number to be generated in textbox. eg: If they enter 5 in textbox it has to return 5 four-digit random number. Any idea how to do it? any reference?
Simply call the method a couple of times, depending on input. Note that you need to use below random number creation method instead of yours to guarantee 4 digit numbers.
function getRand() {
return Math.floor(Math.random() * (9999 - 1000) + 1000);
}
document.getElementById('btn').addEventListener('click', () => {
const length = document.getElementById('foo').value;
const numbers = Array.from({length}, getRand);
document.getElementById('bar').innerText = numbers.join(', ');
});
<input id="foo" type="number">
<button id="btn">Get</button>
<div id="bar"></div>
You can simply call your 4 digit random number generator function() n time (n is given number in input field) as below:
for(let i=1;i<=this.n;i++) {
this.ara.push(this.random());
}
random() {
return Math.floor(Math.random()*(9999-1000) + 1000);
}
See this typescript implementation (Angular).
Call getRandoms with n = 5, and high = 9999. Handle the 5-element return array as you wish.
// pseudo-randomly generate an integer in the range low to high
function getRandom( high, low ) {
// default low is 0
if ('undefined' == typeof low) low = 0;
var range = high - low + 1;
var r = Math.floor( range*Math.random() + .5);
return Math.min(low + r, high);
};
// get n pseudo-random number in the range low to high
function getRandoms( n, high, low ) {
// default low is 0
if ('undefined' == typeof low) low = 0;
var randoms = new Array(); // initialize return
for (var i = 0; i < n; i++) {
randoms.push(getRandom(high, low));
}
return randoms;
};
I have the following two scenarios where I want to compare a certain calculated value to float value 0.05.
In the first scenario, the value is being converted into String to get the value in two decimal place and then converting it back into a number for comparison.
var soneFunction = function(value)
{
var a = ((Math.round(value * 10) / 10) - value).toFixed(2);
if(Number(a) === 0.05)
a = -0.05;
return a;
};
In the second scenario, I am not doing any string-number conversion but using mathematical functions.
var soneFunction = function(value)
{
var roundingValue = (Math.round(value * 10) / 10) - value;
// fix the value till 2 decimal places
var a = Math.round((roundingValue) * 100) / 100;
if(a === 0.05)
a = -0.05;
return a;
};
I am curious to know which one is better?
UPDATE:
By better, I meant performance and memory consumption wise.
I think you can use
let parseFloatWithPrecision = function (value, precision){
var floatValue = parseFloat(value) || 0.0 ;
floatValue = floatValue.toFixed(precision);
return parseFloat(floatValue);
}
let compare = function(val){
if(parseFloatWithPrecision(val, 2) == 0.05)
return -0.05;
return val;
}
I have a variable that has a number between 1-3.
I need to randomly generate a new number between 1-3 but it must not be the same as the last one.
It happens in a loop hundreds of times.
What is the most efficient way of doing this?
May the powers of modular arithmetic help you!!
This function does what you want using the modulo operator:
/**
* generate(1) will produce 2 or 3 with probablity .5
* generate(2) will produce 1 or 3 with probablity .5
* ... you get the idea.
*/
function generate(nb) {
rnd = Math.round(Math.random())
return 1 + (nb + rnd) % 3
}
if you want to avoid a function call, you can inline the code.
Here is a jsFiddle that solves your problem : http://jsfiddle.net/AsMWG/
I've created an array containing 1,2,3 and first I select any number and swap it with the last element. Then I only pick elements from position 0 and 1, and swap them with last element.
var x = 1; // or 2 or 3
// this generates a new x out of [1,2,3] which is != x
x = (Math.floor(2*Math.random())+x) % 3 + 1;
You can randomly generate numbers with the random number generator built in to javascript. You need to use Math.random().
If you're push()-ing into an array, you can always check if the previously inserted one is the same number, thus you regenerate the number. Here is an example:
var randomArr = [];
var count = 100;
var max = 3;
var min = 1;
while (randomArr.length < count) {
var r = Math.floor(Math.random() * (max - min) + min);
if (randomArr.length == 0) {
// start condition
randomArr.push(r);
} else if (randomArr[randomArr.length-1] !== r) {
// if the previous value is not the same
// then push that value into the array
randomArr.push(r);
}
}
As Widor commented generating such a number is equivalent to generating a number with probability 0.5. So you can try something like this (not tested):
var x; /* your starting number: 1,2 or 3 */
var y = Math.round(Math.random()); /* generates 0 or 1 */
var i = 0;
var res = i+1;
while (i < y) {
res = i+1;
i++;
if (i+1 == x) i++;
}
The code is tested and it does for what you are after.
var RandomNumber = {
lastSelected: 0,
generate: function() {
var random = Math.floor(Math.random()*3)+1;
if(random == this.lastSelected) {
generateNumber();
}
else {
this.lastSelected = random;
return random;
}
}
}
RandomNumber.generate();