[javascript] Remove insignificant trailing zeros from a number?

Have I missed a standard API call that removes trailing insignificant zeros from a number?

Ex.

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.

This question is related to javascript regex math numbers

The answer is


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!


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.


Here's a possible solution:

var x = 1.234000 // to become 1.234;
var y = 1.234001; // stays 1.234001

eval(x) --> 1.234
eval(y) --> 1.234001

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:

  • In the first place please pay the attention to the | 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.
  • The (\.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.
  • The ((?<=(\..*))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.
  • If neither of the two parts of expression will match, nothing gets removed. This might be for example 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


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

None of these solutions worked for me for very small numbers. http://numeraljs.com/ solved this for me.

parseFloat(0.00000001.toFixed(8));
// 1e-8

numeral(0.00000001).format('0[.][00000000]');
// "0.00000001"

I first used a combination of matti-lyra and gary's answers:

r=(+n).toFixed(4).replace(/\.0+$/,'')

Results:

  • 1234870.98762341: "1234870.9876"
  • 1230009100: "1230009100"
  • 0.0012234: "0.0012"
  • 0.1200234: "0.12"
  • 0.000001231: "0"
  • 0.10001: "0.1000"
  • "asdf": "NaN" (so no runtime error)

The somewhat problematic case is 0.10001. I ended up using this longer version:

    r = (+n).toFixed(4);
    if (r.match(/\./)) {
      r = r.replace(/\.?0+$/, '');
    }
  • 1234870.98762341: "1234870.9876"
  • 1230009100: "1230009100"
  • 0.0012234: "0.0012"
  • 0.1200234: "0.12"
  • 0.000001231: "0"
  • 0.10001: "0.1"
  • "asdf": "NaN" (so no runtime error)

Update: And this is Gary's newer version (see comments):

r=(+n).toFixed(4).replace(/([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)/,'$1')

This gives the same results as above.


The toFixed method will do the appropriate rounding if necessary. It will also add trailing zeroes, which is not always ideal.

(4.55555).toFixed(2);
//-> "4.56"

(4).toFixed(2);
//-> "4.00"

If you cast the return value to a number, those trailing zeroes will be dropped. This is a simpler approach than doing your own rounding or truncation math.

+(4.55555).toFixed(2);
//-> 4.56

+(4).toFixed(2);
//-> 4

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.


I had the basically the same requirement, and found that there is no built-in mechanism for this functionality.

In addition to trimming the trailing zeros, I also had the need to round off and format the output for the user's current locale (i.e. 123,456.789).

All of my work on this has been included as prettyFloat.js (MIT Licensed) on GitHub: https://github.com/dperish/prettyFloat.js


Usage Examples:

prettyFloat(1.111001, 3) // "1.111"
prettyFloat(1.111001, 4) // "1.111"
prettyFloat(1.1111001, 5) // "1.1111"
prettyFloat(1234.5678, 2) // "1234.57"
prettyFloat(1234.5678, 2, true) // "1,234.57" (en-us)


Updated - August, 2018


All modern browsers now support the ECMAScript Internationalization API, which provides language sensitive string comparison, number formatting, and date and time formatting.

let formatters = {
    default: new Intl.NumberFormat(),
    currency: new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', minimumFractionDigits: 0, maximumFractionDigits: 0 }),
    whole: new Intl.NumberFormat('en-US', { style: 'decimal', minimumFractionDigits: 0, maximumFractionDigits: 0 }),
    oneDecimal: new Intl.NumberFormat('en-US', { style: 'decimal', minimumFractionDigits: 1, maximumFractionDigits: 1 }),
    twoDecimal: new Intl.NumberFormat('en-US', { style: 'decimal', minimumFractionDigits: 2, maximumFractionDigits: 2 })
};

formatters.twoDecimal.format(1234.5678);  // result: "1,234.57"
formatters.currency.format(28761232.291); // result: "$28,761,232"

For older browsers, you can use this polyfill: https://cdn.polyfill.io/v2/polyfill.min.js?features=Intl.~locale.en


I needed to solve this problem too when Django was displaying Decimal type values in a text field. E.g. when '1' was the value. It would show '1.00000000'. If '1.23' was the value, it would show '1.23000000' (In the case of a 'decimal_places' setting of 8)

Using parseFloat was not an option for me since it is possible it does not return the exact same value. toFixed was not an option since I did not want to round anything, so I created a function:

function removeTrailingZeros(value) {
    value = value.toString();

    # if not containing a dot, we do not need to do anything
    if (value.indexOf('.') === -1) {
        return value;
    }

    # as long as the last character is a 0 or a dot, remove it
    while((value.slice(-1) === '0' || value.slice(-1) === '.') && value.indexOf('.') !== -1) {
        value = value.substr(0, value.length - 1);
    }
    return value;
}

I had a similar instance where I wanted to use .toFixed() where necessary, but I didn't want the padding when it wasn't. So I ended up using parseFloat in conjunction with toFixed.

toFixed without padding

parseFloat(n.toFixed(4));

Another option that does almost the same thing
This answer may help your decision

Number(n.toFixed(4));

toFixed will round/pad the number to a specific length, but also convert it to a string. Converting that back to a numeric type will not only make the number safer to use arithmetically, but also automatically drop any trailing 0's. For example:

var n = "1.234000";
    n = parseFloat(n);
 // n is 1.234 and in number form

Because even if you define a number with trailing zeros they're dropped.

var n = 1.23000;
 // n == 1.23;

Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to regex

Why my regexp for hyphenated words doesn't work? grep's at sign caught as whitespace Preg_match backtrack error regex match any single character (one character only) re.sub erroring with "Expected string or bytes-like object" Only numbers. Input number in React Visual Studio Code Search and Replace with Regular Expressions Strip / trim all strings of a dataframe return string with first match Regex How to capture multiple repeated groups?

Examples related to math

How to do perspective fixing? How to pad a string with leading zeros in Python 3 How can I use "e" (Euler's number) and power operation in python 2.7 numpy max vs amax vs maximum Efficiently getting all divisors of a given number Using atan2 to find angle between two vectors How to calculate percentage when old value is ZERO Finding square root without using sqrt function? Exponentiation in Python - should I prefer ** operator instead of math.pow and math.sqrt? How do I get the total number of unique pairs of a set in the database?

Examples related to numbers

how to display a javascript var in html body How to label scatterplot points by name? Allow 2 decimal places in <input type="number"> Why does the html input with type "number" allow the letter 'e' to be entered in the field? Explanation on Integer.MAX_VALUE and Integer.MIN_VALUE to find min and max value in an array Input type "number" won't resize C++ - how to find the length of an integer How to Generate a random number of fixed length using JavaScript? How do you check in python whether a string contains only numbers? Turn a single number into single digits Python