Round number up to the nearest multiple of 3 - javascript

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

Related

JavaScript - Factorial explanation

I wanted someone to basically help me understand what each line of code is doing and help me comment each line (if applicable) so that it can help explain to another person what it's doing. It'd be awesome if one can just give second eyes and ensure that the code is actually good - I'm trying to get my head around Factorial/Recursion, and did some research and found these solutions for this.
I was given this scenario:
For positive n, factorial is n! = n(n−1)!   (e.g. 5! = 5 * 4
* 3 * 2 * 1)*
Here's what I've found for this scenario:
// Prompt user to enter a number to calculate the factorial
var num = prompt("What number do you want to find the factorial of?");
var factorial = function(n) {
if (n == 0) {
return 1;
} else {
product = 1;
for (i = 1; i < n; i++) {
product *= i;
}
return product;
}
}
console.log(factorial(num));
Recursive
Create a recursive algorithm to calculate the factorial using every second
number as shown in examples below:
5! = 5 * 3 * 1 = 15
6! = 6 * 4 * 2 = 48
As for the cursive part, this is added onto the above code and is written in the following -
//  recursive
var factorial = function(n) {
if (n == 0) {
return 1;
} else {
return n * factorial(n - 1);
}
}
console.log(factorial(num));
Would appreciate your assistance on this - Apologies if this has already been answered, please direct me to another thread if this has been already posted. Thanks!
You don't need recursion for that:
/**
* Calculate factorial, optionally using a difference other than 1 with previous value.
* Example: factorial(6, 2) // 6*4*2 = 48
*/
var factorial = function(n, d) {
if (!d) {d = 1;}
var product = 1;
while (n > 1) {
product *= n;
n -= d;
}
return product;
};
console.log(factorial(6, 2)); // 48
console.log(factorial(6)); // 720
Note: Declare local variables inside the function with keyword 'var'. Otherwise they become globals and the second time you attempt to use a function may produce wrong results.
Usually, writing a function for Factorial is an exercise on writing recursive function. The first example code is not recursive and just an overly complicated way of calculating a factorial by multiplying the numbers iteratively so I'll skip that.
The second code is recursive, and it is following the recursive definition of factorial in your usual mathematics:
f: N => N, f(x) = x! = { x < 1 : 1, else : x (x - 1)! }
Or equivalently in JavaScript:
let fac = n => n < 1 ? 1 : n * fac(n - 1);
An expansion of an example computation would look like:
5!
5(4!)
5(4(3!))
5(4(3(2!)))
5(4(3(2(1))))
5(4(3(2(1(0!)))))
5(4(3(2(1(1)))))
120

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

Calculating cubic root for negative number

So, to be short,
3√(-8) = (-8)1/3
console.log(Math.pow(-8,1/3));
//Should be -2
But when I test it out, it outputs
NaN
Why? Is it a bug or it is expected to be like this in the first place? I am using JavaScript to draw graphs, but this messes up the graph.
You can use this snippet to calculate it. It also works for other powers, e.g. 1/4, 1/5, etc.
function nthroot(x, n) {
try {
var negate = n % 2 == 1 && x < 0;
if(negate)
x = -x;
var possible = Math.pow(x, 1 / n);
n = Math.pow(possible, n);
if(Math.abs(x - n) < 1 && (x > 0 == n > 0))
return negate ? -possible : possible;
} catch(e){}
}
nthroot(-8, 3);
Source: http://gotochriswest.com/blog/2011/05/06/cube-root-an-beyond/
A faster approach for just calculating the cubic root:
Math.cbrt = function(x) {
var sign = x === 0 ? 0 : x > 0 ? 1 : -1;
return sign * Math.pow(Math.abs(x), 1 / 3);
}
Math.cbrt(-8);
Update
To find an integer based cubic root, you can use the following function, inspired by this answer:
// positive-only cubic root approximation
function cbrt(n)
{
var a = n; // note: this is a non optimized assumption
while (a * a * a > n) {
a = Math.floor((2 * a + (n / (a * a))) / 3);
}
return a;
}
It starts with an assumption that converges to the closest integer a for which a^3 <= n. This function can be adjusted in the same way to support a negative base.
There's no bug; you are raising a negative number to a fractional power; hence, the NaN.
The top hit on google for this is from Dr Math the explanation is pretty good. It says for for real numbers (not complex numbers anyway), a negative number raised to a fractional power may not be a real number. The simplest example is probably
-4 ^ (1/2)
which is essentially computing the square root of -4. Even though the cubic root of -8 does have real solutions, I think that most software libraries find it more efficient not to do all the complex arithmetic and return NaN only when the imaginary part is nonzero and give you the nice real answer otherwise.
EDIT
Just to make absolutely clear that NaN is the intended result, see the official ECMAScript 5.1 Specification, Section 15.8.2.13. It says:
If x<0 and x is finite and y is finite and y is not an integer, the result is NaN.
Again, even though SOME instances of raising negative numbers to fractional powers have exactly one real root, many languages just do the NaN thing for all cases of negative numbers to fractional roots.
Please do not think JavaScript is the only such language. C++ does the same thing:
If x is finite negative and y is finite but not an integer value, it causes a domain error.
Two key problems:
Mathematically, there are multiple cubic roots of a negative number: -2, but also 2 complex roots (see cube roots of unity).
Javascript's Math object (and most other standard math libraries) will not do fractional powers of negative numbers. It converts the fractional power to a float before the function receives it, so you are asking the function to compute a floating point power of a negative number, which may or may not have a real solution. So it does the pragmatic thing and refuses to attempt to calculate such a value.
If you want to get the correct answer, you'll need to decide how mathematically correct you want to be, and write those rules into a non-standard implementation of pow.
All library functions are limited to avoid excessive calculation times and unnecessary complexity.
I like the other answers, but how about overriding Math.pow so it would be able to work with all nth roots of negative numbers:
//keep the original method for proxying
Math.pow_ = Math.pow;
//redefine the method
Math.pow = function(_base, _exponent) {
if (_base < 0) {
if (Math.abs(_exponent) < 1) {
//we're calculating nth root of _base, where n === 1/_exponent
if (1 / _exponent % 2 === 0) {
//nth root of a negative number is imaginary when n is even, we could return
//a string like "123i" but this would completely mess up further computation
return NaN;
}/*else if (1 / _exponent % 2 !== 0)*/
//nth root of a negative number when n is odd
return -Math.pow_(Math.abs(_base), _exponent);
}
}/*else if (_base >=0)*/
//run the original method, nothing will go wrong
return Math.pow_(_base, _exponent);
};
Fiddled with some test cases, give me a shout if you spot a bug!
So I see a bunch of methods that revolve around Math.pow(...) which is cool, but based on the wording of the bounty I'm proposing a slightly different approach.
There are several computational approximations for solving roots, some taking quicker steps than others. Ultimately the stopping point comes down to the degree of precision desired(it's really up to you/the problem being solved).
I'm not going to explain the math in fine detail, but the following are implementations of cubed root approximations that passed the target test(bounty test - also added negative range, because of the question title). Each iteration in the loop (see the while(Math.abs(xi-xi0)>precision) loops in each method) gets a step closer to the desired precision. Once precision is achieved a format is applied to the number so it's as precise as the calculation derived from the iteration.
var precision = 0.0000000000001;
function test_cuberoot_fn(fn) {
var tested = 0,
failed = 0;
for (var i = -100; i < 100; i++) {
var root = fn(i*i*i);
if (i !== root) {
console.log(i, root);
failed++;
}
tested++;
}
if (failed) {
console.log("failed %d / %d", failed, tested);
}else{
console.log("Passed test");
}
}
test_cuberoot_fn(newtonMethod);
test_cuberoot_fn(halleysMethod);
Newton's approximation Implementation
function newtonMethod(cube){
if(cube == 0){//only John Skeet and Chuck Norris
return 0; //can divide by zero, we'll have
} //to settle for check and return
var xi = 1;
var xi0 = -1;
while(Math.abs(xi-xi0)>precision){//precision = 0.0000000000001
xi0=xi;
xi = (1/3)*((cube/(xi*xi))+2*xi);
}
return Number(xi.toPrecision(12));
}
Halley's approximation Implementation
note Halley's approximation takes quicker steps to solving the cube, so it's computationally faster than newton's approximation.
function halleysMethod(cube){
if(cube == 0){//only John Skeet and Chuck Norris
return 0; //can divide by zero, we'll have
} //to settle for check and return
var xi = 1;
var xi0 = -1;
while(Math.abs(xi-xi0)>precision){//precision = 0.0000000000001
xi0=xi;
xi = xi*((xi*xi*xi + 2*cube)/(2*xi*xi*xi+cube));
}
return Number(xi.toPrecision(12));
}
It's Working in Chrome Console
function cubeRoot(number) {
var num = number;
var temp = 1;
var inverse = 1 / 3;
if (num < 0) {
num = -num;
temp = -1;
}
var res = Math.pow(num, inverse);
var acc = res - Math.floor(res);
if (acc <= 0.00001)
res = Math.floor(res);
else if (acc >= 0.99999)
res = Math.ceil(res);
return (temp * res);
}
cubeRoot(-64) // -4
cubeRoot(64) // 4
As a heads up, in ES6 there is now a Math.cbrt function.
In my testing in Google chrome it appears to work almost twice as fast as Math.pow. Interestingly I had to add up the results otherwise chrome did a better job of optimizing away the pow function.
//do a performance test on the cube root function from es6
var start=0, end=0, k=0;
start = performance.now();
k=0;
for (var i=0.0; i<10000000.0; i+=1.0)
{
var j = Math.cbrt(i);
//k+=j;
}
end = performance.now();
console.log("cbrt took:" + (end-start),k);
k=0;
start = performance.now();
for (var i=0.0; i<10000000.0; i+=1.0)
{
var j = Math.pow(i,0.33333333);
//k+=j;
}
end = performance.now();
console.log("pow took:" + (end-start),k);
k=0;
start = performance.now();
for (var i=0.0; i<10000000.0; i+=1.0)
{
var j = Math.cbrt(i);
k+=j;
}
end = performance.now();
console.log("cbrt took:" + (end-start),k);
k=0;
start = performance.now();
for (var i=0.0; i<10000000.0; i+=1.0)
{
var j = Math.pow(i,0.33333333);
k+=j;
}
end = performance.now();
console.log("pow took:" + (end-start),k);
Result:
cbrt took:468.28200000163633 0
pow took:77.21999999921536 0
cbrt took:546.8039999977918 1615825909.5248165
pow took:869.1149999940535 1615825826.7510242
//aren't cube roots of negative numbers the same as positive, except for the sign?
Math.cubeRoot= function(n, r){
var sign= (n<0)? -1: 1;
return sign*Math.pow(Math.abs(n), 1/3);
}
Math.cubeRoot(-8)
/* returned value: (Number)
-2
*/
Just want to highlight that in ES6 there is a native cubic root function. So you can just do this (check the support here)
Math.cbrt(-8) will return you -2
this works with negative number and negative exponent:
function nthRoot(x = 0, r = 1) {
if (x < 0) {
if (r % 2 === 1) return -nthRoot(-x, r)
if (r % 2 === -1) return -1 / nthRoot(-x, -r)
}
return x ** (1 / r)
}
examples:
nthRoot( 16, 2) 4
nthRoot( 16, -2) 0.25
nthRoot(-16, 2) NaN
nthRoot(-16, -2) NaN
nthRoot( 27, 3) 3
nthRoot( 27, -3) 0.3333333333333333
nthRoot(-27, 3) -3
nthRoot(-27, -3) -0.3333333333333333

How do I get the decimal places of a floating point number in Javascript?

What I would like to have is the almost opposite of Number.prototype.toPrecision(), meaning that when i have number, how many decimals does it have? E.g.
(12.3456).getDecimals() // 4
For anyone wondering how to do this faster (without converting to string), here's a solution:
function precision(a) {
var e = 1;
while (Math.round(a * e) / e !== a) e *= 10;
return Math.log(e) / Math.LN10;
}
Edit: a more complete solution with edge cases covered:
function precision(a) {
if (!isFinite(a)) return 0;
var e = 1, p = 0;
while (Math.round(a * e) / e !== a) { e *= 10; p++; }
return p;
}
One possible solution (depends on the application):
var precision = (12.3456 + "").split(".")[1].length;
If by "precision" you mean "decimal places", then that's impossible because floats are binary. They don't have decimal places, and most values that have a small number of decimal places have recurring digits in binary, and when they're translated back to decimal that doesn't necessarily yield the original decimal number.
Any code that works with the "decimal places" of a float is liable to produce unexpected results on some numbers.
There is no native function to determine the number of decimals. What you can do is convert the number to string and then count the offset off the decimal delimiter .:
Number.prototype.getPrecision = function() {
var s = this + "",
d = s.indexOf('.') + 1;
return !d ? 0 : s.length - d;
};
(123).getPrecision() === 0;
(123.0).getPrecision() === 0;
(123.12345).getPrecision() === 5;
(1e3).getPrecision() === 0;
(1e-3).getPrecision() === 3;
But it's in the nature of floats to fool you. 1 may just as well be represented by 0.00000000989 or something. I'm not sure how well the above actually performs in real life applications.
Basing on #blackpla9ue comment and considering numbers exponential format:
function getPrecision (num) {
var numAsStr = num.toFixed(10); //number can be presented in exponential format, avoid it
numAsStr = numAsStr.replace(/0+$/g, '');
var precision = String(numAsStr).replace('.', '').length - num.toFixed().length;
return precision;
}
getPrecision(12.3456); //4
getPrecision(120.30003300000); //6, trailing zeros are truncated
getPrecision(15); //0
getPrecision(120.000)) //0
getPrecision(0.0000005); //7
getPrecision(-0.01)) //2
Try the following
function countDecimalPlaces(number) {
var str = "" + number;
var index = str.indexOf('.');
if (index >= 0) {
return str.length - index - 1;
} else {
return 0;
}
}
Based on #boolean_Type's method of handling exponents, but avoiding the regex:
function getPrecision (value) {
if (!isFinite(value)) { return 0; }
const [int, float = ''] = Number(value).toFixed(12).split('.');
let precision = float.length;
while (float[precision - 1] === '0' && precision >= 0) precision--;
return precision;
}
Here are a couple of examples, one that uses a library (BigNumber.js), and another that doesn't use a library. Assume you want to check that a given input number (inputNumber) has an amount of decimal places that is less than or equal to a maximum amount of decimal places (tokenDecimals).
With BigNumber.js
import BigNumber from 'bignumber.js'; // ES6
// const BigNumber = require('bignumber.js').default; // CommonJS
const tokenDecimals = 18;
const inputNumber = 0.000000000000000001;
// Convert to BigNumber
const inputNumberBn = new BigNumber(inputNumber);
// BigNumber.js API Docs: http://mikemcl.github.io/bignumber.js/#dp
console.log(`Invalid?: ${inputNumberBn.dp() > tokenDecimals}`);
Without BigNumber.js
function getPrecision(numberAsString) {
var n = numberAsString.toString().split('.');
return n.length > 1
? n[1].length
: 0;
}
const tokenDecimals = 18;
const inputNumber = 0.000000000000000001;
// Conversion of number to string returns scientific conversion
// So obtain the decimal places from the scientific notation value
const inputNumberDecimalPlaces = inputNumber.toString().split('-')[1];
// Use `toFixed` to convert the number to a string without it being
// in scientific notation and with the correct number decimal places
const inputNumberAsString = inputNumber.toFixed(inputNumberDecimalPlaces);
// Check if inputNumber is invalid due to having more decimal places
// than the permitted decimal places of the token
console.log(`Invalid?: ${getPrecision(inputNumberAsString) > tokenDecimals}`);
Assuming number is valid.
let number = 0.999;
let noOfPlaces = number.includes(".") //includes or contains
? number.toString().split(".").pop().length
: 0;
5622890.31 ops/s (91.58% slower):
function precision (n) {
return (n.toString().split('.')[1] || '').length
}
precision(1.0123456789)
33004904.53 ops/s (50.58% slower):
function precision (n) {
let e = 1
let p = 0
while(Math.round(n * e) / e !== n) {
e *= 10
p++
}
return p
}
precision(1.0123456789)
62610550.04 ops/s (6.25% slower):
function precision (n) {
let cur = n
let p = 0
while(!Number.isInteger(cur)) {
cur *= 10
p++
}
return p
}
precision(1.0123456789)
66786361.47 ops/s (fastest):
function precision (n) {
let cur = n
let p = 0
while(Math.floor(cur) !== cur) {
cur *= 10
p++
}
return p
}
precision(1.0123456789)
Here is a simple solution
First of all, if you pass a simple float value as 12.1234 then most of the below/above logics may work but if you pass a value as 12.12340, then it may exclude a count of 0. For e.g, if the value is 12.12340 then it may give you a result of 4 instead of 5. As per your problem statement, if you ask javascript to split and count your float value into 2 integers then it won't include trailing 0s of it.
Let's satisfy our requirement here with a trick ;)
In the below function you need to pass a value in string format and it will do your work
function getPrecision(value){
a = value.toString()
console.log('a ->',a)
b = a.split('.')
console.log('b->',b)
return b[1].length
getPrecision('12.12340') // Call a function
For an example, run the below logic
value = '12.12340'
a = value.toString()
b = a.split('.')
console.log('count of trailing decimals->',b[1].length)
That's it! It will give you the exact count for normal float values as well as the float values with trailing 0s!
Thank you!
This answer adds to Mourner's accepted solution by making the function more robust. As noted by many, floating point precision makes such a function unreliable. For example, precision(0.1+0.2) yields 17 rather than 1 (this might be computer specific, but for this example see https://jsfiddle.net/s0v17jby/5/).
IMHO, there are two ways around this: 1. either properly define a decimal type, using e.g. https://github.com/MikeMcl/decimal.js/, or 2. define an acceptable precision level which is both OK for your use case and not a problem for the js Number representation (8 bytes can safely represent a total of 16 digits AFAICT). For the latter workaround, one can write a more robust variant of the proposed function:
const MAX_DECIMAL_PRECISION = 9; /* must be <= 15 */
const maxDecimalPrecisionFloat = 10**MAX_DECIMAL_PRECISION;
function precisionRobust(a) {
if (!isFinite(a)) return 0;
var e = 1, p = 0;
while ( ++p<=MAX_DECIMAL_PRECISION && Math.round( ( Math.round(a * e) / e - a ) * maxDecimalPrecisionFloat ) !== 0) e *= 10;
return p-1;
}
In the above example, the maximum precision of 9 means this accepts up to 6 digits before the decimal point and 9 after (so this would work for numbers less than one million and with a maximum of 9 decimal points). If your use-case numbers are smaller then you can choose to make this precision even greater (but with a maximum of 15). It turns out that, for calculating precision, this function seems to do OK on larger numbers as well (though that would no longer be the case if we were, say, adding two rounded numbers within the precisionRobust function).
Finally, since we now know the maximum useable precision, we can further avoid infinite loops (which I have not been able to replicate but which still seem to cause problems for some).

Truncate (not round off) decimal numbers in javascript

I am trying to truncate decimal numbers to decimal places. Something like this:
5.467 -> 5.46
985.943 -> 985.94
toFixed(2) does just about the right thing but it rounds off the value. I don't need the value rounded off. Hope this is possible in javascript.
Dogbert's answer is good, but if your code might have to deal with negative numbers, Math.floor by itself may give unexpected results.
E.g. Math.floor(4.3) = 4, but Math.floor(-4.3) = -5
Use a helper function like this one instead to get consistent results:
truncateDecimals = function (number) {
return Math[number < 0 ? 'ceil' : 'floor'](number);
};
// Applied to Dogbert's answer:
var a = 5.467;
var truncated = truncateDecimals(a * 100) / 100; // = 5.46
Here's a more convenient version of this function:
truncateDecimals = function (number, digits) {
var multiplier = Math.pow(10, digits),
adjustedNum = number * multiplier,
truncatedNum = Math[adjustedNum < 0 ? 'ceil' : 'floor'](adjustedNum);
return truncatedNum / multiplier;
};
// Usage:
var a = 5.467;
var truncated = truncateDecimals(a, 2); // = 5.46
// Negative digits:
var b = 4235.24;
var truncated = truncateDecimals(b, -2); // = 4200
If that isn't desired behaviour, insert a call to Math.abs on the first line:
var multiplier = Math.pow(10, Math.abs(digits)),
EDIT: shendz correctly points out that using this solution with a = 17.56 will incorrectly produce 17.55. For more about why this happens, read What Every Computer Scientist Should Know About Floating-Point Arithmetic. Unfortunately, writing a solution that eliminates all sources of floating-point error is pretty tricky with javascript. In another language you'd use integers or maybe a Decimal type, but with javascript...
This solution should be 100% accurate, but it will also be slower:
function truncateDecimals (num, digits) {
var numS = num.toString(),
decPos = numS.indexOf('.'),
substrLength = decPos == -1 ? numS.length : 1 + decPos + digits,
trimmedResult = numS.substr(0, substrLength),
finalResult = isNaN(trimmedResult) ? 0 : trimmedResult;
return parseFloat(finalResult);
}
For those who need speed but also want to avoid floating-point errors, try something like BigDecimal.js. You can find other javascript BigDecimal libraries in this SO question: "Is there a good Javascript BigDecimal library?" and here's a good blog post about math libraries for Javascript
upd:
So, after all it turned out, rounding bugs will always haunt you, no matter how hard you try to compensate them. Hence the problem should be attacked by representing numbers exactly in decimal notation.
Number.prototype.toFixedDown = function(digits) {
var re = new RegExp("(\\d+\\.\\d{" + digits + "})(\\d)"),
m = this.toString().match(re);
return m ? parseFloat(m[1]) : this.valueOf();
};
[ 5.467.toFixedDown(2),
985.943.toFixedDown(2),
17.56.toFixedDown(2),
(0).toFixedDown(1),
1.11.toFixedDown(1) + 22];
// [5.46, 985.94, 17.56, 0, 23.1]
Old error-prone solution based on compilation of others':
Number.prototype.toFixedDown = function(digits) {
var n = this - Math.pow(10, -digits)/2;
n += n / Math.pow(2, 53); // added 1360765523: 17.56.toFixedDown(2) === "17.56"
return n.toFixed(digits);
}
var a = 5.467;
var truncated = Math.floor(a * 100) / 100; // = 5.46
You can fix the rounding by subtracting 0.5 for toFixed, e.g.
(f - 0.005).toFixed(2)
Nice one-line solution:
function truncate (num, places) {
return Math.trunc(num * Math.pow(10, places)) / Math.pow(10, places);
}
Then call it with:
truncate(3.5636232, 2); // returns 3.56
truncate(5.4332312, 3); // returns 5.433
truncate(25.463214, 4); // returns 25.4632
Consider taking advantage of the double tilde: ~~.
Take in the number. Multiply by significant digits after the decimal so that you can truncate to zero places with ~~. Divide that multiplier back out. Profit.
function truncator(numToTruncate, intDecimalPlaces) {
var numPower = Math.pow(10, intDecimalPlaces); // "numPowerConverter" might be better
return ~~(numToTruncate * numPower)/numPower;
}
I'm trying to resist wrapping the ~~ call in parens; order of operations should make that work correctly, I believe.
alert(truncator(5.1231231, 1)); // is 5.1
alert(truncator(-5.73, 1)); // is -5.7
alert(truncator(-5.73, 0)); // is -5
JSFiddle link.
EDIT: Looking back over, I've unintentionally also handled cases to round off left of the decimal as well.
alert(truncator(4343.123, -2)); // gives 4300.
The logic's a little wacky looking for that usage, and may benefit from a quick refactor. But it still works. Better lucky than good.
I thought I'd throw in an answer using | since it is simple and works well.
truncate = function(number, places) {
var shift = Math.pow(10, places);
return ((number * shift) | 0) / shift;
};
Truncate using bitwise operators:
~~0.5 === 0
~~(-0.5) === 0
~~14.32794823 === 14
~~(-439.93) === -439
#Dogbert's answer can be improved with Math.trunc, which truncates instead of rounding.
There is a difference between rounding and truncating. Truncating is
clearly the behaviour this question is seeking. If I call
truncate(-3.14) and receive -4 back, I would definitely call that
undesirable. – #NickKnowlson
var a = 5.467;
var truncated = Math.trunc(a * 100) / 100; // = 5.46
var a = -5.467;
var truncated = Math.trunc(a * 100) / 100; // = -5.46
I wrote an answer using a shorter method. Here is what I came up with
function truncate(value, precision) {
var step = Math.pow(10, precision || 0);
var temp = Math.trunc(step * value);
return temp / step;
}
The method can be used like so
truncate(132456.25456789, 5)); // Output: 132456.25456
truncate(132456.25456789, 3)); // Output: 132456.254
truncate(132456.25456789, 1)); // Output: 132456.2
truncate(132456.25456789)); // Output: 132456
Or, if you want a shorter syntax, here you go
function truncate(v, p) {
var s = Math.pow(10, p || 0);
return Math.trunc(s * v) / s;
}
I think this function could be a simple solution:
function trunc(decimal,n=2){
let x = decimal + ''; // string
return x.lastIndexOf('.')>=0?parseFloat(x.substr(0,x.lastIndexOf('.')+(n+1))):decimal; // You can use indexOf() instead of lastIndexOf()
}
console.log(trunc(-241.31234,2));
console.log(trunc(241.312,5));
console.log(trunc(-241.233));
console.log(trunc(241.2,0));
console.log(trunc(241));
Number.prototype.trim = function(decimals) {
var s = this.toString();
var d = s.split(".");
d[1] = d[1].substring(0, decimals);
return parseFloat(d.join("."));
}
console.log((5.676).trim(2)); //logs 5.67
I'm a bit confused as to why there are so many different answers to such a fundamentally simple question; there are only two approaches which I saw which seemed to be worth looking at. I did a quick benchmark to see the speed difference using https://jsbench.me/.
This is the solution which is currently (9/26/2020) flagged as the answer:
function truncate(n, digits) {
var re = new RegExp("(\\d+\\.\\d{" + digits + "})(\\d)"),
m = n.toString().match(re);
return m ? parseFloat(m[1]) : n.valueOf();
};
[ truncate(5.467,2),
truncate(985.943,2),
truncate(17.56,2),
truncate(0, 1),
truncate(1.11, 1) + 22];
However, this is doing string and regex stuff, which is usually not very efficient, and there is a Math.trunc function which does exactly what the OP wants just with no decimals. Therefore, you can easily use that plus a little extra arithmetic to get the same thing.
Here is another solution I found on this thread, which is the one I would use:
function truncate(n, digits) {
var step = Math.pow(10, digits || 0);
var temp = Math.trunc(step * n);
return temp / step;
}
[ truncate(5.467,2),
truncate(985.943,2),
truncate(17.56,2),
truncate(0, 1),
truncate(1.11, 1) + 22];
The first method is "99.92% slower" than the second, so the second is definitely the one I would recommend using.
Okay, back to finding other ways to avoid work...
I found a problem: considering the next situation: 2.1 or 1.2 or -6.4
What if you want always 3 decimals or two or wharever, so, you have to complete the leading zeros to the right
// 3 decimals numbers
0.5 => 0.500
// 6 decimals
0.1 => 0.10000
// 4 decimales
-2.1 => -2.1000
// truncate to 3 decimals
3.11568 => 3.115
This is the fixed function of Nick Knowlson
function truncateDecimals (num, digits)
{
var numS = num.toString();
var decPos = numS.indexOf('.');
var substrLength = decPos == -1 ? numS.length : 1 + decPos + digits;
var trimmedResult = numS.substr(0, substrLength);
var finalResult = isNaN(trimmedResult) ? 0 : trimmedResult;
// adds leading zeros to the right
if (decPos != -1){
var s = trimmedResult+"";
decPos = s.indexOf('.');
var decLength = s.length - decPos;
while (decLength <= digits){
s = s + "0";
decPos = s.indexOf('.');
decLength = s.length - decPos;
substrLength = decPos == -1 ? s.length : 1 + decPos + digits;
};
finalResult = s;
}
return finalResult;
};
https://jsfiddle.net/huttn155/7/
function toFixed(number, digits) {
var reg_ex = new RegExp("(\\d+\\.\\d{" + digits + "})(\\d)")
var array = number.toString().match(reg_ex);
return array ? parseFloat(array[1]) : number.valueOf()
}
var test = 10.123456789
var __fixed = toFixed(test, 6)
console.log(__fixed)
// => 10.123456
The answer by #kirilloid seems to be the correct answer, however, the main code needs to be updated. His solution doesn't take care of negative numbers (which someone did mention in the comment section but has not been updated in the main code).
Updating that to a complete final tested solution:
Number.prototype.toFixedDown = function(digits) {
var re = new RegExp("([-]*\\d+\\.\\d{" + digits + "})(\\d)"),
m = this.toString().match(re);
return m ? parseFloat(m[1]) : this.valueOf();
};
Sample Usage:
var x = 3.1415629;
Logger.log(x.toFixedDown(2)); //or use whatever you use to log
Fiddle: JS Number Round down
PS: Not enough repo to comment on that solution.
Here my take on the subject:
convert.truncate = function(value, decimals) {
decimals = (decimals === undefined ? 0 : decimals);
return parseFloat((value-(0.5/Math.pow(10, decimals))).toFixed(decimals),10);
};
It's just a slightly more elaborate version of
(f - 0.005).toFixed(2)
Here is simple but working function to truncate number upto 2 decimal places.
function truncateNumber(num) {
var num1 = "";
var num2 = "";
var num1 = num.split('.')[0];
num2 = num.split('.')[1];
var decimalNum = num2.substring(0, 2);
var strNum = num1 +"."+ decimalNum;
var finalNum = parseFloat(strNum);
return finalNum;
}
The resulting type remains a number...
/* Return the truncation of n wrt base */
var trunc = function(n, base) {
n = (n / base) | 0;
return base * n;
};
var t = trunc(5.467, 0.01);
Lodash has a few Math utility methods that can round, floor, and ceil a number to a given decimal precision. This leaves off trailing zeroes.
They take an interesting approach, using the exponent of a number. Apparently this avoids rounding issues.
(Note: func is Math.round or ceil or floor in the code below)
// Shift with exponential notation to avoid floating-point issues.
var pair = (toString(number) + 'e').split('e'),
value = func(pair[0] + 'e' + (+pair[1] + precision));
pair = (toString(value) + 'e').split('e');
return +(pair[0] + 'e' + (+pair[1] - precision));
Link to the source code
const TO_FIXED_MAX = 100;
function truncate(number, decimalsPrecison) {
// make it a string with precision 1e-100
number = number.toFixed(TO_FIXED_MAX);
// chop off uneccessary digits
const dotIndex = number.indexOf('.');
number = number.substring(0, dotIndex + decimalsPrecison + 1);
// back to a number data type (app specific)
return Number.parseFloat(number);
}
// example
truncate(0.00000001999, 8);
0.00000001
works with:
negative numbers
very small numbers (Number.EPSILON precision)
The one that is mark as the solution is the better solution I been found until today, but has a serious problem with 0 (for example, 0.toFixedDown(2) gives -0.01). So I suggest to use this:
Number.prototype.toFixedDown = function(digits) {
if(this == 0) {
return 0;
}
var n = this - Math.pow(10, -digits)/2;
n += n / Math.pow(2, 53); // added 1360765523: 17.56.toFixedDown(2) === "17.56"
return n.toFixed(digits);
}
Here is what I use:
var t = 1;
for (var i = 0; i < decimalPrecision; i++)
t = t * 10;
var f = parseFloat(value);
return (Math.floor(f * t)) / t;
You can work with strings.
It Checks if '.' exists, and then removes part of string.
truncate (7.88, 1) --> 7.8
truncate (7.889, 2) --> 7.89
truncate (-7.88, 1 ) --> -7.88
function truncate(number, decimals) {
const tmp = number + '';
if (tmp.indexOf('.') > -1) {
return +tmp.substr(0 , tmp.indexOf('.') + decimals+1 );
} else {
return +number
}
}
function trunc(num, dec) {
const pow = 10 ** dec
return Math.trunc(num * pow) / pow
}
// ex.
trunc(4.9634, 1) // 4.9
trunc(4.9634, 2) // 4.96
trunc(-4.9634, 1) // -4.9
You can use toFixed(2) to convert your float to a string with 2 decimal points. Then you can wrap that in floatParse() to convert that string back to a float to make it usable for calculations or db storage.
const truncatedNumber = floatParse(num.toFixed(2))
I am not sure of the potential drawbacks of this answer like increased processing time but I tested edge cases from other comments like .29 which returns .29 (not .28 like other solutions). It also handles negative numbers.
just to point out a simple solution that worked for me
convert it to string and then regex it...
var number = 123.45678;
var number_s = '' + number;
var number_truncated_s = number_s.match(/\d*\.\d{4}/)[0]
var number_truncated = parseFloat(number_truncated_s)
It can be abbreviated to
var number_truncated = parseFloat(('' + 123.4568908).match(/\d*\.\d{4}/)[0])
Here is an ES6 code which does what you want
const truncateTo = (unRouned, nrOfDecimals = 2) => {
const parts = String(unRouned).split(".");
if (parts.length !== 2) {
// without any decimal part
return unRouned;
}
const newDecimals = parts[1].slice(0, nrOfDecimals),
newString = `${parts[0]}.${newDecimals}`;
return Number(newString);
};
// your examples
console.log(truncateTo(5.467)); // ---> 5.46
console.log(truncateTo(985.943)); // ---> 985.94
// other examples
console.log(truncateTo(5)); // ---> 5
console.log(truncateTo(-5)); // ---> -5
console.log(truncateTo(-985.943)); // ---> -985.94
Suppose you want to truncate number x till n digits.
Math.trunc(x * pow(10,n))/pow(10,n);
Number.prototype.truncate = function(places) {
var shift = Math.pow(10, places);
return Math.trunc(this * shift) / shift;
};

Categories

Resources