Have I missed a standard API call that removes trailing insignificant zeros from a number?
var x = 1.234000; // to become 1.234
var y = 1.234001; // stays 1.234001
Number.toFixed() and Number.toPrecision() are not quite what I'm looking for.
Have I missed a standard API call that removes trailing insignificant zeros from a number?
var x = 1.234000; // to become 1.234
var y = 1.234001; // stays 1.234001
Number.toFixed() and Number.toPrecision() are not quite what I'm looking for.
How about just multiplying by one like this?
var x = 1.234000*1; // becomes 1.234
var y = 1.234001*1; // stays as 1.234001
Pure regex answer
n.replace(/(\.[0-9]*[1-9])0+$|\.0*$/,'$1');
I wonder why no one gave one!
You can try this one to minify floating numbers
var n = 0.0000;
n = parseFloat(n.toString());
//output n = 0;
// n = 3.14000; --> n = 3.14;
If you use toFixed(n) where n > 0, a more simple and stable (no more float operations) solution can be:
(+n).toFixed(2).replace(/(\.0+|0+)$/, '')
// 0 => 0
// 0.1234 => 0.12
// 0.1001 => 0.1
// 1 => 1
// 1.1234 => 1.12
// 1.1001 => 1.1
// 100 => 100
// 100.1234 => 100.12
// 100.1001 => 100.1
PS: if you use toFixed(0), then no replace is needed.
If we have some s string representation of a number, which we can get for example using the .toFixed(digits) method of Number (or by any other means), then for removal of insignificant trailing zeros from the s string we can use:
s.replace(/(\.0*|(?<=(\..*))0*)$/, '')
/**********************************
* Results for various values of s:
**********************************
*
* "0" => 0
* "0.000" => 0
*
* "10" => 10
* "100" => 100
*
* "0.100" => 0.1
* "0.010" => 0.01
*
* "1.101" => 1.101
* "1.100" => 1.1
* "1.100010" => 1.10001
*
* "100.11" => 100.11
* "100.10" => 100.1
*/
Regular expression used above in the replace() is explained below:
| operator inside the regular expression, which stands for "OR", so, the replace() method will remove from s two possible kinds of substring, matched either by the (\.0*)$ part OR by the ((?<=(\..*))0*)$ part.(\.0*)$ part of regex matches a dot symbol followed by all the zeros and nothing else till to the end of the s. This might be for example 0.0 (.0 is matched & removed), 1.0 (.0 is matched & removed), 0.000 (.000 is matched & removed) or any similar string with all the zeros after the dot, so, all the trailing zeros and the dot itself will be removed if this part of regex will match.((?<=(\..*))0*)$ part matches only the trailing zeros (which are located after a dot symbol followed by any number of any symbol before start of the consecutive trailing zeros). This might be for example 0.100 (trailing 00 is matched & removed), 0.010 (last 0 is matched & removed, note that 0.01 part do NOT get matched at all thanks to the "Positive Lookbehind Assertion", i.e. (?<=(\..*)), which is in front of 0* in this part of regex), 1.100010 (last 0 is matched & removed), etc.100 or 100.11, etc. So, if an input does not have any trailing zeros then it stays unchanged.Some more examples using .toFixed(digits)(Literal value "1000.1010" is used in the examples below, but we can assume variables instead):
let digits = 0; // Get `digits` from somewhere, for example: user input, some sort of config, etc.
(+"1000.1010").toFixed(digits).replace(/(\.0*|(?<=(\..*))0*)$/, '');
// Result: '1000'
(+"1000.1010").toFixed(digits = 1).replace(/(\.0*|(?<=(\..*))0*)$/, '');
// Result: '1000.1'
(+"1000.1010").toFixed(digits = 2).replace(/(\.0*|(?<=(\..*))0*)$/, '');
// Result: '1000.1'
(+"1000.1010").toFixed(digits = 3).replace(/(\.0*|(?<=(\..*))0*)$/, '');
// Result: '1000.101'
(+"1000.1010").toFixed(digits = 4).replace(/(\.0*|(?<=(\..*))0*)$/, '');
// Result: '1000.101'
(+"1000.1010").toFixed(digits = 5).replace(/(\.0*|(?<=(\..*))0*)$/, '');
// Result: '1000.101'
(+"1000.1010").toFixed(digits = 10).replace(/(\.0*|(?<=(\..*))0*)$/, '');
// Result: '1000.101'
To play around with the above regular expression used in replace() we can visit: https://regex101.com/r/owj9fz/1
I needed to remove any trailing zeros but keep at least 2 decimals, including any zeros.
The numbers I'm working with are 6 decimal number strings, generated by .toFixed(6).
Expected Result:
var numstra = 12345.000010 // should return 12345.00001
var numstrb = 12345.100000 // should return 12345.10
var numstrc = 12345.000000 // should return 12345.00
var numstrd = 12345.123000 // should return 12345.123
Solution:
var numstr = 12345.100000
while (numstr[numstr.length-1] === "0") {
numstr = numstr.slice(0, -1)
if (numstr[numstr.length-1] !== "0") {break;}
if (numstr[numstr.length-3] === ".") {break;}
}
console.log(numstr) // 12345.10
Logic:
Run loop function if string last character is a zero.
Remove the last character and update the string variable.
If updated string last character is not a zero, end loop.
If updated string third to last character is a floating point, end loop.
If you cannot use Floats for any reason (like money-floats involved) and are already starting from a string representing a correct number, you could find this solution handy. It converts a string representing a number to a string representing number w/out trailing zeroes.
function removeTrailingZeroes( strAmount ) {
// remove all trailing zeroes in the decimal part
var strDecSepCd = '.'; // decimal separator
var iDSPosition = strAmount.indexOf( strDecSepCd ); // decimal separator positions
if ( iDSPosition !== -1 ) {
var strDecPart = strAmount.substr( iDSPosition ); // including the decimal separator
var i = strDecPart.length - 1;
for ( ; i >= 0 ; i-- ) {
if ( strDecPart.charAt(i) !== '0') {
break;
}
}
if ( i=== 0 ) {
return strAmount.substring(0, iDSPosition);
} else {
// return INTPART and DS + DECPART including the rightmost significant number
return strAmount.substring(0, iDSPosition) + strDecPart.substring(0,i + 1);
}
}
return strAmount;
}
This is how I do it:
parseFloat(number.toString());
This is a good workaround for the TypeScript bug too. The bug that changes number to string in certain situations.
I wrote this regular expression to remove insignificant: zeros, decimals, and spaces from the beginning and end of strings containing numbers:
const rxInsignificant = /^[\s0]+|(?<=\..*)[\s0.]+$|\.0+$|\.$/gm;
let ary = [
"001.230",
"2.",
"3.00",
"1000",
" 0000000000000010000.10000000000000000000000 "];
ary.forEach((str)=>
{
console.log(`"${str}" becomes "${str.replace(rxInsignificant,'')}"`);
});
Unfortunately, Safari still doesn't support the 2018 specification that gave us look-behinds in regular expressions. There has been an open bug report for this issue since 07-28-2017.
The good news is that look-behinds do work in Firefox and in all Chromium derivatives. Hopefully, Safari will receive more requests for this compliance and implement this standard soon.
In the meantime, I've written this function to accomplish the same task without a look-behind:
function createRemoveInsignificantFunction()
{
const rxLeadingZeros = /^[\s0]+/;
const rxEndingZeros = /[\s0]+$/;
function removeInsignificant(str)
{
str = str.replace(rxLeadingZeros,'');
let ary = str.split('.');
if (ary.length > 1)
{
ary[1] = ary[1].replace(rxEndingZeros,'');
if (ary[1].length === 0)
{
return ary[0];
}
else
{
return ary[0] + '.' + ary[1];
}
}
return str;
}
return removeInsignificant;
}
let removeInsignificant = createRemoveInsignificantFunction();
let ary = [
"001.230",
"2.",
"3.00",
"1000",
" 0000000000000010000.10000000000000000000000 "];
ary.forEach((str)=>
{
console.log(`"${str}" becomes "${removeInsignificant(str)}"`);
});
When I have more time, I'd like to figure out how to accomplish this with one regular expression that does not have a look-behind in it. You're welcome to beat me to it in the comments below.
If you'd also like to deal with numeric errors, you could use Intl.NumberFormat or Number.toLocaleString()
new Intl.NumberFormat().format(0.0100) // "0.01"
new Intl.NumberFormat().format(0.010000000000001) // "0.01"
new Intl.NumberFormat().format(0.009999999999999) // "0.01"
console.log((0.0100).toLocaleString()) // "0.01"
console.log((0.010000000000001).toLocaleString()) // "0.01"
console.log((0.009999999999999).toLocaleString()) // "0.01"
So you want
var x = 1.234000; // to become 1.234
var y = 1.234001; // stays 1.234001
No strings attached, just try Number().
var x = 1.234000, // to become 1.234
y = 1.234001, // stays 1.234001
x_ = Number(x),
y_ = Number(y);
console.log(x_,y_);
After reading all of the answers - and comments - I ended up with this:
function isFloat(n) {
let number = (Number(n) === n && n % 1 !== 0) ? eval(parseFloat(n)) : n;
return number;
}
I know using eval can be harmful somehow but this helped me a lot.
So:
isFloat(1.234000); // = 1.234;
isFloat(1.234001); // = 1.234001
isFloat(1.2340010000); // = 1.234001
If you want to limit the decimal places, use toFixed() as others pointed out.
let number = (Number(n) === n && n % 1 !== 0) ? eval(parseFloat(n).toFixed(3)) : n;
That's it.
My solution is as follow:
export const floatToStr = (f, ndigit = 2) => {
const str = f.toFixed(ndigit)
return ndigit
? str
.replace(/0*$/g, '')
.replace(/\.$/, '')
: str
}
Using parseFloat() did the trick for me. I'm scratching my head here as to why those complicated solutions.
I think the following function may be close to what you want. I wrote it for an application of mine. It will always output in standard notation with no trailing zeros. A few things you may not want but can edit out if you like. It will always return at least one decimal(e.x. 5=>"5.0"). It also is limited to 10 decimals. Use it as a guide.
const toDecimalStr(value)=>{
let str=value.toFixed(10).replace(/([0]+)$/,"");
try {
if (str.endsWith(".")) str+='0';
} catch (e) {
str+='0';
}
return str;
}
the try catch is because not everything supports endsWith and I was being lazy.