Why is my millisecond conversion wrong? - javascript

I have a timer app that counts time passed in milliseconds, converts that to a formatted string, then displays it. Elsewhere, I have a function that converts that same string to milliseconds for some other math I have to do. Seems counter-intuitive, I know, but it mostly works.
Anyways, this is the function that takes a string like 14.55 (14 seconds and ~550 milliseconds) and returns the time in milliseconds, but it's not doing it right.
function toMS(str) {
if(str.includes(":")) {
const [mins, secms] = str.split(":");
const [sec, ms] = secms.split(".");
return ((+mins * 60) + +sec) * 1000 + +ms;
} else {
const [sec, ms] = str.split(".");
return (+sec) * 1000 + +ms;
}
}
If I pass in something like 10.77, it returns 10077 instead of 10770 like it should. What's wrong with it?

Why don't you use parseFloat?
function toMS(str) {
if(str.includes(":")) {
const [mins, secms] = str.split(":");
const sec = parseFloat(secms);
return ((+mins * 60) + sec) * 1000;
} else {
return parseFloat(str) * 1000;
}
}

0.1 seconds is equal to 100 ms, not 1ms. Remember that 0.1s can be also written as 1/10 of a second, 1/10 * 1000ms = 100ms.
It means that you have to multiplicate the decimal part for 100 in order to get the correct result.
function toMS(str) {
if(str.includes(":")) {
const [mins, secms] = str.split(":");
const [sec, ms] = secms.split(".");
return ((+mins * 60) + +sec) * 1000 + +ms;
} else {
const [sec, ms] = str.split(".");
return (+sec) * 1000 + ms * 100;
}
}
Note: You don't need the + to convert your variable, since the * is enough to coerce it to number.
You can also apply the DRY principle in this way:
function toMS(str) {
let mins = 0;
if(str.includes(":")) {
[mins, str] = str.split(":");
}
const [sec, ms] = str.split(".");
return mins * 60000 + sec * 1000 + ms * 100;
}

If you're worried about rounding errors with the parseFloat solution here's a pure string implementation:
ms = +(ms.concat("00").substring(0,3));
So, what are we doing?
Pad the millisecond string with "0". We pad with 2 zeros to cater for the following situations:
a. There are more than 3 digits - in which case all the padded zeros will be ignored later
b. There are exactly 3 digits - all the padded zeros will be ignored later
c. There are exactly 2 digits - the extra zero will be ignored
d. There is exactly 1 digit - both zeros are needed
e. There are no digits at all - both zeros will be converted to 0 later
We take only the first 3 digits. This will automatically ignore both the case of any extra zeros and if ms was accidentally specified with more accuracy than required (eg. if someone entered 1.1234)
We convert to number using the unary + operator

Related

Javascript | Floating point numbers + interval loop

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);

What does (+var) means [duplicate]

This question already has answers here:
What is unary + used for in Javascript?
(4 answers)
What does a + prefix do in this context?
(5 answers)
Closed 9 years ago.
I'm new into the javascript world and I have not found any information about this notation.
I found it in that topic (see the answer): Convert HH:MM:SS string to seconds only in javascript.
// minutes are worth 60 seconds. Hours are worth 60 minutes.
var seconds = (+a[0]) * 60 * 60 + (+a[1]) * 60 + (+a[2]);
Also I wanted to use that code to convert 'HH:MM:SS' string to seconds. But, it seems unsafe for me. If the user inserts 'XX:03:SS', the value will be NaN which is not correct (at least for me). So I decided to improved it with:
function convertHHMMSSToSeconds(time) {
// initialize seconds
var seconds = 0;
//ensure time
if (!time) {
return seconds;
}
try {
var hmsTab = time.split(':'); // split it at the colons
// ensure that the hmsTab contains 3 values (hh,mm,ss)
if (!hmsTab || hmsTab.length !== 3) {
return seconds;
}
// initialize hh, mm and ss
var hh = hmsTab[0] > 0 && hmsTab[0] < 60? +hmsTab[0] : 0;
var mm = hmsTab[1] > 0 && hmsTab[1] < 60 ? +hmsTab[1] : 0;
var ss = hmsTab[2] > 0 && hmsTab[2] < 60 ? +hmsTab[2] : 0;
// return 0 if one variable is not valid
if(+hmsTab[0] !== hh ||+hmsTab[1] !== mm || +hmsTab[2] !== ss) {
return seconds;
}
// minutes are worth 60 seconds. Hours are worth 60 minutes.
seconds = (hh * 60 * 60) + (mm * 60) + ss;
}catch (error)
{
seconds = 0;
}
return seconds && seconds>0 ? seconds : 0;
}
So my question still remains, what does (+var) mean.
Regards,
The + sign in front of a variable, will cast that variable to a number. Example:
var x = "3";
var y = x + 10; // 310
var z = +x + 10 // 13
+var is the application of the unary identity operator to the value of var. The identity operator can be thought of as similar to a function that returns its only parameter:
function identity(operand) {
return operand;
}
However, the identity operator only acts on numeric values. Since Javascript is a weak-typed language, applying a numeric function to a non-numeric value will cause the non-numeric value to be coerced into an equivalent numeric value. In the most common case for coercing using the identity operator, a string containing a number is parsed into a number.
While quick to type and easy to remember, coercion with the identity operator is not very robust. Here are some sample outputs:
+'150' // 150
+'150z' // NaN
+'z150' // NaN
+'015' // 15 -- note that it doesn't interpret as octal*
+'015z' // NaN
+'z015' // NaN
+'0xf' // 15 -- note that it interprets as hexadecimal
+'0xfz' // NaN
+'z0xf' // NaN
+'NaN' // NaN
+'undefined' // NaN
Compare the same inputs with parseInt:
parseInt('150') // 150
parseInt('150z') // 150
parseInt('z150') // NaN
parseInt('015') // 15 -- note that it still doesn't interpret as octal*
parseInt('015z') // 15
parseInt('z015') // NaN
parseInt('0xf') // 15 -- note that it still interprets as hexadecimal
parseInt('0xfz') // 15
parseInt('z0xf') // NaN
parseInt('NaN') // NaN
parseInt('undefined') // NaN
parseInt also gives you more control over the result:
parseInt('015', 8) // 13
parseInt('z0xf', 36) // 1634163
parseInt('1010', 2) // 10
* In EMCAScript 5. Previous versions would default to octal when dealing with leading zeroes.
Strings are not the only thing which can be coerced into numbers with the identity operator, although they are the most common, and the conversion is the most sensible. Other coercions might make sense, or they might not. Example:
+[] // 0
+[150] // 150
+['150'] // 150
+['150z'] // NaN
+[1, 2] // NaN
+{} // NaN
+null // 0
+true // 1
+false // 0
+NaN // NaN
+undefined // NaN
+function(){} // NaN
A way of convertion to number:
+n === Number(n)
Its shortest form to convert a variable to number

Rounding up to the nearest 0.05 in JavaScript

Question
Does anyone know of a way to round a float to the nearest 0.05 in JavaScript?
Example
BEFORE | AFTER
2.51 | 2.55
2.50 | 2.50
2.56 | 2.60
Current Code
var _ceil = Math.ceil;
Math.ceil = function(number, decimals){
if (arguments.length == 1)
return _ceil(number);
multiplier = Math.pow(10, decimals);
return _ceil(number * multiplier) / multiplier;
}
Then elsewhere...
return (Math.ceil((amount - 0.05), 1) + 0.05).toFixed(2);
Which is resulting in...
BEFORE | AFTER
2.51 | 2.55
2.50 | 2.55
2.56 | 2.65
Multiply by 20, then divide by 20:
(Math.ceil(number*20)/20).toFixed(2)
Rob's answer with my addition:
(Math.ceil(number*20 - 0.5)/20).toFixed(2)
Otherwise it always rounds up to the nearest 0.05.
** UPDATE **
Sorry has been pointed out this is not what the orig poster wanted.
I would go for the standard of actually dividing by the number you're factoring it to, and rounding that and multiplying it back again after. That seems to be a proper working method which you can use with any number and maintain the mental image of what you are trying to achieve.
var val = 26.14,
factor = 0.05;
val = Math.round(val / factor) * factor;
This will work for tens, hundreds or any number. If you are specifically rounding to the higher number then use Math.ceil instead of Math.round.
Another method specifically for rounding just to 1 or more decimal places (rather than half a place) is the following:
Number(Number(1.5454545).toFixed(1));
It creates a fixed number string and then turns it into a real Number.
I would write a function that does it for you by
move the decimal over two places (multiply by 100)
then mod (%) that inflatedNumber by 5 and get the remainder
subtract the remainder from 5 so that you know what the 'gap'(ceilGap) is between your number and the next closest .05
finally, divide your inflatedNumber by 100 so that it goes back to your original float, and voila, your num will be rounded up to the nearest .05.
function calcNearestPointZeroFive(num){
var inflatedNumber = num*100,
remainder = inflatedNumber % 5;
ceilGap = 5 - remainder
return (inflatedNumber + ceilGap)/100
}
If you want to leave numbers like 5.50 untouched you can always add this checker:
if (remainder===0){
return num
} else {
var ceilGap = 5 - remainder
return (inflatedNumber + ceilGap)/100
}
You need to put -1 to round half down and after that multiply by -1 like the example down bellow.
<script type="text/javascript">
function roundNumber(number, precision, isDown) {
var factor = Math.pow(10, precision);
var tempNumber = number * factor;
var roundedTempNumber = 0;
if (isDown) {
tempNumber = -tempNumber;
roundedTempNumber = Math.round(tempNumber) * -1;
} else {
roundedTempNumber = Math.round(tempNumber);
}
return roundedTempNumber / factor;
}
</script>
<div class="col-sm-12">
<p>Round number 1.25 down: <script>document.write(roundNumber(1.25, 1, true));</script>
</p>
<p>Round number 1.25 up: <script>document.write(roundNumber(1.25, 1, false));</script></p>
</div>
I ended up using this function in my project, successfully:
roundToNearestFiveCents( number: any ) {
return parseFloat((Math.round(number / 0.05) * 0.05).toFixed(2));
}
Might be of use to someone wanting to simply round to the nearest 5 cents on their monetary results, keeps the result a number, so if you perform addition on it further it won't result in string concatenation; also doesn't unnecessarily round up as a few of the other answers pointed out. Also limits it to two decimals, which is customary with finance.
My solution and test:
let round = function(number, precision = 2, rounding = 0.05) {
let multiply = 1 / rounding;
return parseFloat((Math.round(number * multiply) / multiply)).toFixed(precision);
};
https://jsfiddle.net/maciejSzewczyk/7r1tvhdk/40/
Even though the OP is not explicit about banker rounding, rounding up to the nearest $0.05 (5 cents) should be compatible with banker rounding. What suggested by Arth is more accurate than the accepted answer by Rob W.
(Math.ceil(number*20 - 0.5)/20).toFixed(2)
With banker rounding, you need a basic banker rounding function as suggested at Gaussian/banker's rounding in JavaScript, and I rewrite in TypeScript:
static bankerRound(num: number, decimalPlaces?: number) {
const d = decimalPlaces || 0;
const m = Math.pow(10, d);
const n = +(d ? num * m : num).toFixed(8);
const i = Math.floor(n), f = n - i;
const e = 1e-8;
const r = (f > 0.5 - e && f < 0.5 + e) ?
((i % 2 === 0) ? i : i + 1) : Math.round(n);
return d ? r / m : r;
}
static roundTo5cents(num: number) {
const r = bankerRound(Math.ceil(num * 20 - 0.5) / 20, 2);
return r;
}
The correctness of this algorithm could be verified through MBS Online, e.g. http://www9.health.gov.au/mbs/ready_reckoner.cfm?item_num=60

JQuery create a random 16 digit number possible?

As the title says ... is it possible to create a random 16 digit number with jquery?
Just use:
Math.floor(Math.random()*1E16)
EDIT :
Note that there is about a 1/10 chance of a lower number of digits. If Math.random() generates something like 0.0942104924071337 then 0.0942104924071337 * 1E16 is 0942104924071337 which evaluates to 942104924071337; a 15 digit number.
The only way to 100% guarantee that the number is 16 digits in length is to have it be formed as a string. Using this method I would recommend #rjmunro's answer:
number = (Math.random()+' ').substring(2,10)+(Math.random()+' ').substring(2,10);
Not with jQuery, no, but you can do it with plain javascript.
If you want exactly 16 digits (possibly including leading 0s), I would start with Math.random(), convert to a string, pick 8 digits, and concatenate 2 runs together.
number = (Math.random() + '').substring(2,10)
+ (Math.random() + '').substring(2,10);
No, use JAVASCRIPT!
jQuery is not some magic genie.
This is a task which is much better suited for raw javascript. For example
var str = '';
var i;
for (i = 0; i < 16; i++) {
var number = Math.floor(Math.random() * 10) % 10;
str += number;
}
I just tried with #rjmunro 's answer.
Unfortunately, it does generate string less than 16digits,
but very rare, approxly once in 10 million times.
Here is my testing code, runs in nodejs:
'use strict';
var fs = require('fs');
var totalTimes = 100000000;
var times = totalTimes;
var fileName;
var writeStream;
while (times > 0) {
var key = (Math.random() + ' ').substring(2,10) + (Math.random() + ' ').substring(2,10);
times --;
if (key.length !== 16) {
var msg = 'a flaw key gened: ' + key + '\n';
// create a log file at first time
if (!fileName) {
fileName = 'log/flaw_key_' + new Date() + '.txt';
}
writeStream = fs.createWriteStream(fileName);
writeStream.write(msg);
writeStream.end();
}
if (times === 0) {
console.log(totalTimes + ' times key gened');
}
}
Also #Dimitri Mikadze 's answer generate less length string as well, so I eventually adopt a way with some concept of his solution:
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
/**
* Gen random digits string in specific length
* #param {Int} length of string
*
* #return {String}
*
*/
function genString(length) {
var times = length;
var key = '';
while (times > 0) {
times --;
key += getRandomInt(0, 9);
}
return key;
}
genString(16); // a 16 digits string
u can use this function to generate random digits, just pass minimum and maximum parameters
function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
random 16 digit, usage
randomInt(0, 9999999999999999);
I know this question is old but this simple function will guarantee a 16 (or however many you want) character string every time without the 10% failure rate of other solutions. Can change it to a number if you need to.
function generate() {
let string = ""
while (string.length < 16) {
let number = Math.floor(Math.random() * 10).toString()
string += number
}
return string
}
I think this way is more beautiful:
const generateFixedLengthNumberInString = length =>
[...Array(length).keys()].reduce(
previousValue =>
previousValue + String(Math.floor(Math.random() * 10) % 10),
);
console.log(generateFixedLengthNumberInString(16))
// prints "0587139224228340"

JavaScript, Generate a Random Number that is 9 numbers in length

I'm looking for an efficient, elegant way to generate a JavaScript variable that is 9 digits in length:
Example: 323760488
You could generate 9 random digits and concatenate them all together.
Or, you could call random() and multiply the result by 1000000000:
Math.floor(Math.random() * 1000000000);
Since Math.random() generates a random double precision number between 0 and 1, you will have enough digits of precision to still have randomness in your least significant place.
If you want to ensure that your number starts with a nonzero digit, try:
Math.floor(100000000 + Math.random() * 900000000);
Or pad with zeros:
function LeftPadWithZeros(number, length)
{
var str = '' + number;
while (str.length < length) {
str = '0' + str;
}
return str;
}
Or pad using this inline 'trick'.
why don't just extract digits from the Math.random() string representation?
Math.random().toString().slice(2,11);
/*
Math.random() -> 0.12345678901234
.toString() -> "0.12345678901234"
.slice(2,11) -> "123456789"
*/
(requirement is that every javascript implementation Math.random()'s precision is at least 9 decimal places)
Also...
function getRandom(length) {
return Math.floor(Math.pow(10, length-1) + Math.random() * 9 * Math.pow(10, length-1));
}
getRandom(9) => 234664534
Three methods I've found in order of efficiency:
(Test machine running Firefox 7.0 Win XP)
parseInt(Math.random()*1000000000, 10)
1 million iterations: ~626ms. By far the fastest - parseInt is a native function vs calling the Math library again. NOTE: See below.
Math.floor(Math.random()*1000000000)
1 million iterations: ~1005ms. Two function calls.
String(Math.random()).substring(2,11)
1 million iterations: ~2997ms. Three function calls.
And also...
parseInt(Math.random()*1000000000)
1 million iterations: ~362ms.
NOTE: parseInt is usually noted as unsafe to use without radix parameter. See https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/parseInt or google "JavaScript: The Good Parts". However, it seems the parameter passed to parseInt will never begin with '0' or '0x' since the input is first multiplied by 1000000000. YMMV.
Math.random().toFixed(length).split('.')[1]
Using toFixed alows you to set the length longer than the default (seems to generate 15-16 digits after the decimal. ToFixed will let you get more digits if you need them.
In one line(ish):
var len = 10;
parseInt((Math.random() * 9 + 1) * Math.pow(10,len-1), 10);
Steps:
We generate a random number that fulfil 1 ≤ x < 10.
Then, we multiply by Math.pow(10,len-1) (number with a length len).
Finally, parseInt() to remove decimals.
Thought I would take a stab at your question. When I ran the following code it worked for me.
<script type="text/javascript">
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
} //The maximum is exclusive and the minimum is inclusive
$(document).ready(function() {
$("#random-button").on("click", function() {
var randomNumber = getRandomInt(100000000, 999999999);
$("#random-number").html(randomNumber);
});
</script>
Does this already have enough answers?
I guess not. So, this should reliably provide a number with 9 digits, even if Math.random() decides to return something like 0.000235436:
Math.floor((Math.random() + Math.floor(Math.random()*9)+1) * Math.pow(10, 8))
Screen scrape this page:
9 random numbers
function rand(len){var x='';
for(var i=0;i<len;i++){x+=Math.floor(Math.random() * 10);}
return x;
}
rand(9);
If you mean to generate random telephone number, then they usually are forbidden to start with zero.
That is why you should combine few methods:
Math.floor(Math.random()*8+1)+Math.random().toString().slice(2,10);
this will generate random in between 100 000 000 to 999 999 999
With other methods I had a little trouble to get reliable results as leading zeroes was somehow a problem.
I know the answer is old, but I want to share this way to generate integers or float numbers from 0 to n. Note that the position of the point (float case) is random between the boundaries. The number is an string because the limitation of the MAX_SAFE_INTEGER that is now 9007199254740991
Math.hRandom = function(positions, float = false) {
var number = "";
var point = -1;
if (float) point = Math.floor(Math.random() * positions) + 1;
for (let i = 0; i < positions; i++) {
if (i == point) number += ".";
number += Math.floor(Math.random() * 10);
}
return number;
}
//integer random number 9 numbers
console.log(Math.hRandom(9));
//float random number from 0 to 9e1000 with 1000 numbers.
console.log(Math.hRandom(1000, true));
function randomCod(){
let code = "";
let chars = 'abcdefghijlmnopqrstuvxwz';
let numbers = '0123456789';
let specialCaracter = '/{}$%&#*/()!-=?<>';
for(let i = 4; i > 1; i--){
let random = Math.floor(Math.random() * 99999).toString();
code += specialCaracter[random.substring(i, i-1)] + ((parseInt(random.substring(i, i-1)) % 2 == 0) ? (chars[random.substring(i, i-1)].toUpperCase()) : (chars[random.substring(i, i+1)])) + (numbers[random.substring(i, i-1)]);
}
code = (code.indexOf("undefined") > -1 || code.indexOf("NaN") > -1) ? randomCod() : code;
return code;
}
With max exclusive: Math.floor(Math.random() * max);
With max inclusive: Math.round(Math.random() * max);
To generate a number string with length n, thanks to #nvitaterna, I came up with this:
1 + Math.floor(Math.random() * 9) + Math.random().toFixed(n - 1).split('.')[1]
It prevents first digit to be zero.
It can generate string with length ~ 50 each time you call it.
var number = Math.floor(Math.random() * 900000000) + 100000000
var number = Math.floor(Math.random()*899999999 + 100000000)
For a number of 10 characters
Math.floor(Math.random() * 9000000000) + 1000000000
From https://gist.github.com/lpf23/9762508
This answer is intended for people who are looking to generate a 10 digit number (without a country code)

Categories

Resources