313

I need to show a currency value in the format of 1K of equal to one thousand, or 1.1K, 1.2K, 1.9K etc, if its not an even thousands, otherwise if under a thousand, display normal 500, 100, 250 etc, using JavaScript to format the number?

Penny Liu
  • 15,447
  • 5
  • 79
  • 98
Carl Weis
  • 6,794
  • 15
  • 63
  • 86

36 Answers36

417

A more generalized version:

function nFormatter(num, digits) {
  const lookup = [
    { value: 1, symbol: "" },
    { value: 1e3, symbol: "k" },
    { value: 1e6, symbol: "M" },
    { value: 1e9, symbol: "G" },
    { value: 1e12, symbol: "T" },
    { value: 1e15, symbol: "P" },
    { value: 1e18, symbol: "E" }
  ];
  const rx = /\.0+$|(\.[0-9]*[1-9])0+$/;
  var item = lookup.slice().reverse().find(function(item) {
    return num >= item.value;
  });
  return item ? (num / item.value).toFixed(digits).replace(rx, "$1") + item.symbol : "0";
}

/*
 * Tests
 */
const tests = [
  { num: 0, digits: 1 },
  { num: 12, digits: 1 },
  { num: 1234, digits: 1 },
  { num: 100000000, digits: 1 },
  { num: 299792458, digits: 1 },
  { num: 759878, digits: 1 },
  { num: 759878, digits: 0 },
  { num: 123, digits: 1 },
  { num: 123.456, digits: 1 },
  { num: 123.456, digits: 2 },
  { num: 123.456, digits: 4 }
];
tests.forEach(function(test) {
  console.log("nFormatter(" + test.num + ", " + test.digits + ") = " + nFormatter(test.num, test.digits));
});
Salman A
  • 262,204
  • 82
  • 430
  • 521
286

Sounds like this should work for you:

function kFormatter(num) {
    return Math.abs(num) > 999 ? Math.sign(num)*((Math.abs(num)/1000).toFixed(1)) + 'k' : Math.sign(num)*Math.abs(num)
}
    
console.log(kFormatter(1200)); // 1.2k
console.log(kFormatter(-1200)); // -1.2k
console.log(kFormatter(900)); // 900
console.log(kFormatter(-900)); // -900
Derk Jan Speelman
  • 11,291
  • 4
  • 29
  • 45
Jake Feasel
  • 16,785
  • 5
  • 53
  • 66
  • 7
    Minor fix suggested... Should be lowercase k for thousands. Upper is for Kilos. Tried to edit, but requires at least 6 characters changed before it will take. – Adam Youngers Dec 19 '14 at 18:47
  • How do I inset a php variable inside here and use it? i.e. if my number variable is `$mynumber_output` where do I insert this to use it? For example, say `$mynumber_output` = 12846, I would like 12846 converted to `12.8k` –  Feb 08 '17 at 23:13
  • Note that one kilobyte is 1024 bytes in some cases: https://en.wikipedia.org/wiki/Kilobyte – Olle Härstedt May 01 '17 at 00:01
  • Any idea how we can make 1000 display as 1.0k instead of 1k? – Brent Apr 18 '19 at 03:23
  • 6
    Doesn't completely answer the user's question. "I will need M yes...Can you help?" - Carl Weis – tim-montague May 04 '19 at 22:54
  • Why is it that when a typical developers writes javascript code they think it is suddenly OK to perform the same calculation more than once (twice, three times...) ? why is Math.abs(num) called twice ? – Cesar Feb 04 '20 at 19:20
  • 11
    `Math.round(Math.abs(num)/100)/10` instead of `(Math.abs(num)/1000).toFixed(1)` so typescript is happy – Pierre de LESPINAY Jun 18 '20 at 09:47
  • I'm afraid that I'm missing the point, but I think this example has unneeded function calls. Why not just return this way? `return Math.abs(num) > 999 ? (num/1000).toFixed(1) + 'k' : num` – André Sousa Oct 20 '20 at 18:58
236

ES2020 adds support for this in Intl.NumberFormat Using notation as follows:

let formatter = Intl.NumberFormat('en', { notation: 'compact' });
// example 1
let million = formatter.format(1e6);
// example 2
let billion = formatter.format(1e9);
// print
console.log(million == '1M', billion == '1B');

Note as shown above, that the second example produces 1B instead of 1G. NumberFormat specs:

Note that at the moment not all browsers support ES2020, so you may need this Polyfill: https://formatjs.io/docs/polyfills/intl-numberformat

Ori Price
  • 3,593
  • 2
  • 22
  • 37
  • 1
    That package has been deprecated, so please use this link: https://www.npmjs.com/package/@formatjs/intl-numberformat – Ammad Khalid May 30 '20 at 07:42
  • 7
    Note: Chrome supports the `notation` and `compactDisplay` but FireFox 77 and Safari 13.1 still do not support it so you'll likely need the polyfill. – Josh Unger Jun 04 '20 at 03:06
  • 1
    Wow, Firefox *just* added support for this in v. 78, it seems. Of course, 2+ years from now, this comment's going to look stupid. :P (It's funny to me though because the code runs for me but it doesn't convert properly, so I'll need to do an update.) – Andrew Jul 07 '20 at 18:51
  • There are a couple of issues with compact and its very flexible. – AnandShiva Oct 26 '21 at 08:49
  • Eg. For german compact, when you want M for million, it does not give M, but rather a german specific alternative. ```const number = 12453456.789; console.log(new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR', notation:'compact' }).format(number)); ``` // 12 Mio. € – AnandShiva Oct 26 '21 at 08:51
  • Also for Germany and some language's any number in thousand's will not have compact. But it will be displayed as such – AnandShiva Oct 26 '21 at 08:52
  • 3
    Note the above example formats `12345` as `12K` and not `12.3K`. You can add `maximumSignificantDigits` or `maximumFractionDigits`, depending on the behaviour you want. eg `Intl.NumberFormat("en", { notation: "compact", maximumSignificantDigits: 3 }).format(12345) === "12.3K"` or `Intl.NumberFormat("en", { notation: "compact", maximumFractionDigits: 1 }).format(12345) === "12.3K"` – Rik Jan 15 '23 at 20:28
125

Here's a simple solution that avoids all the if statements (with the power of Math).

var SI_SYMBOL = ["", "k", "M", "G", "T", "P", "E"];

function abbreviateNumber(number){

    // what tier? (determines SI symbol)
    var tier = Math.log10(Math.abs(number)) / 3 | 0;

    // if zero, we don't need a suffix
    if(tier == 0) return number;

    // get suffix and determine scale
    var suffix = SI_SYMBOL[tier];
    var scale = Math.pow(10, tier * 3);

    // scale the number
    var scaled = number / scale;

    // format number and add suffix
    return scaled.toFixed(1) + suffix;
}

Bonus Meme

What does SI stand for?

Waylon Flinn
  • 19,969
  • 15
  • 70
  • 72
  • I really like your solution. To be able to shorten negative values as well, I multiply the number by -1 before and after determining the tier, since Math.log10(negativeValue) would return NaN. – xhadon Jun 14 '17 at 10:26
  • 3
    Just use `Math.abs` to add support to negative numbers, like that: `var tier = Math.log10(Math.abs(number)) / 3 | 0;`. – Caio Tarifa Jul 13 '20 at 05:19
  • Thanks, I made the change to enable negative numbers. – Waylon Flinn Jan 11 '21 at 22:41
  • Does this work just like the accepted answer without any issues? – ThisDude Apr 06 '21 at 22:08
  • 1
    Thanks, that's actually the most understandable answer, in terms of what's happening. – Fabian Jan 15 '22 at 20:12
  • Yea, this one makes a lot more sense and is much easier to read, especially with the comments. It also works with negative numbers too, which is a plus. – train Mar 25 '22 at 21:09
96

Further improving Salman's Answer because it returns nFormatter(33000) as 33.0K

function nFormatter(num) {
     if (num >= 1000000000) {
        return (num / 1000000000).toFixed(1).replace(/\.0$/, '') + 'G';
     }
     if (num >= 1000000) {
        return (num / 1000000).toFixed(1).replace(/\.0$/, '') + 'M';
     }
     if (num >= 1000) {
        return (num / 1000).toFixed(1).replace(/\.0$/, '') + 'K';
     }
     return num;
}

now nFormatter(33000) = 33K

Yash
  • 2,153
  • 2
  • 16
  • 11
  • 3
    Anyway to do this without rounding the number? 1,590,000 will return 1.6M. – Brett Hardin Sep 30 '14 at 17:48
  • 4
    Sometimes its hard to know when to post a new answer of edit an existing one, something I use to decide is if I steal the code from another users answer, I usually edit their answer so that they can get the recognition instead of me stealing their code. – M H Feb 19 '16 at 17:09
  • @Yash you're the code I'm trying to implement in the counter script but not getting this is my codepen link https://codepen.io/Merajkhan/pen/MMoxGE?editors=1010 Can you help me out how to implement this logic I want K, L, M units have to come. – Mehraj Khan Jun 25 '19 at 07:34
53

A straight-forward approach has the best readability, and uses the least memory. No need to over-engineer with the use of regex, map objects, Math objects, for-loops, etc.

Formatting Cash value with K

const formatCash = n => {
  if (n < 1e3) return n;
  if (n >= 1e3) return +(n / 1e3).toFixed(1) + "K";
};

console.log(formatCash(2500));

Formatting Cash value with K M B T

const formatCash = n => {
  if (n < 1e3) return n;
  if (n >= 1e3 && n < 1e6) return +(n / 1e3).toFixed(1) + "K";
  if (n >= 1e6 && n < 1e9) return +(n / 1e6).toFixed(1) + "M";
  if (n >= 1e9 && n < 1e12) return +(n / 1e9).toFixed(1) + "B";
  if (n >= 1e12) return +(n / 1e12).toFixed(1) + "T";
};

console.log(formatCash(1235000));

Using negative numbers

let format;
const number = -1235000;

if (number < 0) {
  format = '-' + formatCash(-1 * number);
} else {
  format = formatCash(number);
}
tim-montague
  • 16,217
  • 5
  • 62
  • 51
  • 1
    @Jan - Updated my post with an example, but felt it was simple enough to compute the negative form using `'-' + formatCash(-1 * number)` – tim-montague Apr 03 '20 at 10:14
30
/**
 * Shorten number to thousands, millions, billions, etc.
 * http://en.wikipedia.org/wiki/Metric_prefix
 *
 * @param {number} num Number to shorten.
 * @param {number} [digits=0] The number of digits to appear after the decimal point.
 * @returns {string|number}
 *
 * @example
 * // returns '12.5k'
 * shortenLargeNumber(12543, 1)
 *
 * @example
 * // returns '-13k'
 * shortenLargeNumber(-12567)
 *
 * @example
 * // returns '51M'
 * shortenLargeNumber(51000000)
 *
 * @example
 * // returns 651
 * shortenLargeNumber(651)
 *
 * @example
 * // returns 0.12345
 * shortenLargeNumber(0.12345)
 */
function shortenLargeNumber(num, digits) {
    var units = ['k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'],
        decimal;

    for(var i=units.length-1; i>=0; i--) {
        decimal = Math.pow(1000, i+1);

        if(num <= -decimal || num >= decimal) {
            return +(num / decimal).toFixed(digits) + units[i];
        }
    }

    return num;
}

Thx @Cos for comment, I removed Math.round10 dependency.

Martin Sznapka
  • 829
  • 11
  • 6
23

Give Credit to Waylon Flinn if you like this

This was improved from his more elegant approach to handle negative numbers and ".0" case.

The fewer loops and "if" cases you have, the better IMO.

function abbreviateNumber(number) {
    const SI_POSTFIXES = ["", "k", "M", "G", "T", "P", "E"];
    const sign = number < 0 ? '-1' : '';
    const absNumber = Math.abs(number);
    const tier = Math.log10(absNumber) / 3 | 0;
    // if zero, we don't need a prefix
    if(tier == 0) return `${absNumber}`;
    // get postfix and determine scale
    const postfix = SI_POSTFIXES[tier];
    const scale = Math.pow(10, tier * 3);
    // scale the number
    const scaled = absNumber / scale;
    const floored = Math.floor(scaled * 10) / 10;
    // format number and add postfix as suffix
    let str = floored.toFixed(1);
    // remove '.0' case
    str = (/\.0$/.test(str)) ? str.substr(0, str.length - 2) : str;
    return `${sign}${str}${postfix}`;
}

jsFiddle with test cases -> https://jsfiddle.net/qhbrz04o/9/

King Friday
  • 25,132
  • 12
  • 90
  • 84
  • 1
    There's still an annoying bug: `abbreviateNumber(999999) == '1000k'` instead of `'1M'`. This is because `toFixed()` also rounds the numbers. Not sure how to fix it, though :/ – Vitor Baptista Sep 07 '17 at 11:24
  • @VitorBaptista If `toFixed()` rounds the number anyway, you might as well round the number before sending it to `abbreviateNumber()`, so it returns `1M` instead of `1000k`. Not a solution, but a workaround. – forsureitsme Mar 22 '18 at 19:47
  • 2
    If you don't want rounding you can do this after the scale step: `const floored = Math.floor(scaled * 10) / 10;` – tybro0103 Apr 13 '19 at 02:24
  • 1
    doesn't work properly with negative numbers – doğukan Mar 01 '21 at 22:02
  • 1
    @forsureitsme sorry i haven't seen this for a year... i added your change. wrx! – King Friday Mar 02 '21 at 16:30
16

this is is quite elegant.

function formatToUnits(number, precision) {
  const abbrev = ['', 'k', 'm', 'b', 't'];
  const unrangifiedOrder = Math.floor(Math.log10(Math.abs(number)) / 3)
  const order = Math.max(0, Math.min(unrangifiedOrder, abbrev.length -1 ))
  const suffix = abbrev[order];

  return (number / Math.pow(10, order * 3)).toFixed(precision) + suffix;
}

formatToUnits(12345, 2)
==> "12.35k"
formatToUnits(0, 3)
==> "0.000"
Novellizator
  • 13,633
  • 9
  • 43
  • 65
16

I think it can be one solution.

var unitlist = ["","K","M","G"];
function formatnumber(number){
   let sign = Math.sign(number);
   let unit = 0;
   
   while(Math.abs(number) >= 1000)
   {
     unit = unit + 1; 
     number = Math.floor(Math.abs(number) / 100)/10;
   }
   console.log(sign*Math.abs(number) + unitlist[unit]);
}
formatnumber(999);
formatnumber(1234);
formatnumber(12345);
formatnumber(123456);
formatnumber(1234567);
formatnumber(12345678);
formatnumber(1000);
formatnumber(-999);
formatnumber(-1234);
formatnumber(-12345);
formatnumber(-123456);
formatnumber(-1234567);
formatnumber(-12345678);
BTSM
  • 1,585
  • 8
  • 12
  • 26
  • Thanks, This is helpful Because this is not a round return figure like others. – Sandeep Sherpur Jul 20 '22 at 07:55
  • 1
    This function use a lot of resources because it's iterating over the same number again and again. My web app was freezing in Chrome and Safari and was because I was using this function several times – Victor Nov 19 '22 at 13:52
  • I think that's not with this function. I tested it with 100000 calls and nothing happened. Please share your code. – BTSM Nov 21 '22 at 01:27
  • For the number "1000" this returns "1000". To return "1K" replace the "> 1000" with ">= 1000" in the while line – NathanPB Jun 08 '23 at 19:53
13

The simplest and easiest way of doing this is

new Intl.NumberFormat('en-IN', { 
    notation: "compact",
    compactDisplay: "short",
    style: 'currency',
    currency: 'INR'
}).format(1000).replace("T", "K")

This works for any number. Including L Cr etc.

NOTE: Not working in safari.

Narasimha Reddy - Geeker
  • 3,510
  • 2
  • 18
  • 23
11

You can use the d3-format package modeled after Python Advanced String Formatting PEP3101 :

var f = require('d3-format')
console.log(f.format('.2s')(2500)) // displays "2.5k"
Vincent de Lagabbe
  • 4,964
  • 3
  • 31
  • 38
11

Short and generic method

You can make the COUNT_FORMATS config object as long or short as you want, depending on the range of values you testing.

// Configuration    
const COUNT_FORMATS =
[
  { // 0 - 999
    letter: '',
    limit: 1e3
  },
  { // 1,000 - 999,999
    letter: 'K',
    limit: 1e6
  },
  { // 1,000,000 - 999,999,999
    letter: 'M',
    limit: 1e9
  },
  { // 1,000,000,000 - 999,999,999,999
    letter: 'B',
    limit: 1e12
  },
  { // 1,000,000,000,000 - 999,999,999,999,999
    letter: 'T',
    limit: 1e15
  }
];
    
// Format Method:
function formatCount(value)
{
  const format = COUNT_FORMATS.find(format => (value < format.limit));

  value = (1000 * value / format.limit);
  value = Math.round(value * 10) / 10; // keep one decimal number, only if needed

  return (value + format.letter);
}

// Test:
const test = [274, 1683, 56512, 523491, 9523489, 5729532709, 9421032489032];
test.forEach(value => console.log(`${ value } >>> ${ formatCount(value) }`));
Gil Epshtain
  • 8,670
  • 7
  • 63
  • 89
9

By eliminating the loop in @martin-sznapka solution, you will reduce the execution time by 40%.

function formatNum(num,digits) {
    let units = ['k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'];
    let floor = Math.floor(Math.abs(num).toString().length / 3);
    let value=+(num / Math.pow(1000, floor))
    return value.toFixed(value > 1?digits:2) + units[floor - 1];

}

Speed test (200000 random samples) for different solution from this thread

Execution time: formatNum          418  ms
Execution time: kFormatter         438  ms it just use "k" no "M".."T" 
Execution time: beautify           593  ms doesnt support - negatives
Execution time: shortenLargeNumber 682  ms    
Execution time: Intl.NumberFormat  13197ms 
0xFK
  • 2,433
  • 32
  • 24
6

Further improving @Yash's answer with negative number support:

function nFormatter(num) {
    isNegative = false
    if (num < 0) {
        isNegative = true
    }
    num = Math.abs(num)
    if (num >= 1000000000) {
        formattedNumber = (num / 1000000000).toFixed(1).replace(/\.0$/, '') + 'G';
    } else if (num >= 1000000) {
        formattedNumber =  (num / 1000000).toFixed(1).replace(/\.0$/, '') + 'M';
    } else  if (num >= 1000) {
        formattedNumber =  (num / 1000).toFixed(1).replace(/\.0$/, '') + 'K';
    } else {
        formattedNumber = num;
    }   
    if(isNegative) { formattedNumber = '-' + formattedNumber }
    return formattedNumber;
}

nFormatter(-120000)
"-120K"
nFormatter(120000)
"120K"
Strawberry
  • 66,024
  • 56
  • 149
  • 197
4

2020 edition of Waylon Flinn's solution.

const SI_SYMBOLS = ["", "k", "M", "G", "T", "P", "E"];

const abbreviateNumber = (number, minDigits, maxDigits) => {
    if (number === 0) return number;

    // determines SI symbol
    const tier = Math.floor(Math.log10(Math.abs(number)) / 3);

    // get suffix and determine scale
    const suffix = SI_SYMBOLS[tier];
    const scale = 10 ** (tier * 3);

    // scale the number
    const scaled = number / scale;

    // format number and add suffix
    return scaled.toLocaleString(undefined, {
        minimumFractionDigits: minDigits,
        maximumFractionDigits: maxDigits,
    }) + suffix;
};

Tests and examples:

const abbreviateNumberFactory = (symbols) => (
  (number, minDigits, maxDigits) => {
    if (number === 0) return number;

    // determines SI symbol
    const tier = Math.floor(Math.log10(Math.abs(number)) / 3);

    // get suffix and determine scale
    const suffix = symbols[tier];
    const scale = 10 ** (tier * 3);

    // scale the number
    const scaled = number / scale;

    // format number and add suffix
    return scaled.toLocaleString(undefined, {
      minimumFractionDigits: minDigits,
      maximumFractionDigits: maxDigits,
    }) + suffix;
  }
);

const SI_SYMBOLS = ["", "k", "M", "G", "T", "P", "E"];
const SHORT_SYMBOLS = ["", "K", "M", "B", "T", "Q"];
const LONG_SYMBOLS = ["", " thousand", " million", " billion", " trillion", " quadrillion"];

const abbreviateNumberSI = abbreviateNumberFactory(SI_SYMBOLS);
const abbreviateNumberShort = abbreviateNumberFactory(SHORT_SYMBOLS);
const abbreviateNumberLong = abbreviateNumberFactory(LONG_SYMBOLS);

const tests = [1e5, -9e7, [1009999.999, 2],
  [245345235.34513, 1, 1],
  [-72773144123, 3]
];

const functions = {
  abbreviateNumberSI,
  abbreviateNumberShort,
  abbreviateNumberLong,
};

tests.forEach((test) => {
  const testValue = Array.isArray(test) ? test : [test];
  Object.entries(functions).forEach(([key, func]) => {
    console.log(`${key}(${testValue.join(', ')}) = ${func(...testValue)}`);
  });
});
Georgiy Bukharov
  • 356
  • 3
  • 10
  • 1
    Welcome to SO. Your question was flagged for 'Late Answer' review as the question is nearly 9 years old and has 32 other answers. Whilst your answer may provide some value, very late answers will often be downvoted. – GoodJuJu Dec 16 '20 at 13:43
  • 2
    @GoodJuJu I don't see a reason why would someone "downvote" late answers. There's a lot of users who still answers late, even a user who has 78k reputation. Tell that to that guy. – Wesley Brian Lachenal Jan 15 '21 at 11:25
3

This post is quite old but I somehow reached to this post searching for something. SO to add my input Numeral js is the one stop solution now a days. It gives a large number of methods to help formatting the numbers

http://numeraljs.com/

Vatsal
  • 2,068
  • 4
  • 21
  • 24
  • 1
    numeraljs is not maintained anymore. The most active fork seems to be [numbro](https://github.com/foretagsplatsen/numbro). But neither of them support the SI/metric notation – Vincent de Lagabbe Nov 03 '15 at 10:36
3

Not satisfied any of the posted solutions, so here's my version:

  1. Supports positive and negative numbers
  2. Supports negative exponents
  3. Rounds up to next exponent if possible
  4. Performs bounds checking (doesn't error out for very large/small numbers)
  5. Strips off trailing zeros/spaces
  6. Supports a precision parameter

    function abbreviateNumber(number,digits=2) {
      var expK = Math.floor(Math.log10(Math.abs(number)) / 3);
      var scaled = number / Math.pow(1000, expK);
    
      if(Math.abs(scaled.toFixed(digits))>=1000) { // Check for rounding to next exponent
        scaled /= 1000;
        expK += 1;
      }
    
      var SI_SYMBOLS = "apμm kMGTPE";
      var BASE0_OFFSET = SI_SYMBOLS.indexOf(' ');
    
      if (expK + BASE0_OFFSET>=SI_SYMBOLS.length) { // Bound check
        expK = SI_SYMBOLS.length-1 - BASE0_OFFSET;
        scaled = number / Math.pow(1000, expK);
      }
      else if (expK + BASE0_OFFSET < 0) return 0;  // Too small
    
      return scaled.toFixed(digits).replace(/(\.|(\..*?))0+$/,'$2') + SI_SYMBOLS[expK+BASE0_OFFSET].trim();
    }
    
    //////////////////
    
    const tests = [
      [0.0000000000001,2],
      [0.00000000001,2],
      [0.000000001,2],
      [0.000001,2],
      [0.001,2],
      [0.0016,2],
      [-0.0016,2],
      [0.01,2],
      [1,2],
      [999.99,2],
      [999.99,1],
      [-999.99,1],
      [999999,2],
      [999999999999,2],
      [999999999999999999,2],
      [99999999999999999999,2],
    ];
    
    for (var i = 0; i < tests.length; i++) {
      console.log(abbreviateNumber(tests[i][0], tests[i][1]) );
    }
ttk
  • 407
  • 3
  • 4
3
function   transform(value,args) {
    const suffixes = ['K', 'M', 'B', 'T', 'P', 'E'];

    if (!value) {
      return null;
    }

    if (Number.isNaN(value)) {
      return null;
    }

    if (value < 1000) {
      return value;
    }

    const exp = Math.floor(Math.log(value) / Math.log(1000));

    const returnValue = (value / Math.pow(1000, exp)).toFixed(args) + suffixes[exp - 1];

    return returnValue;
  }

transform(9999,2)

// "10.00K"

Afuye Olawale
  • 141
  • 1
  • 8
  • While this code snippet may solve the problem, it doesn't explain why or how it answers the question. Please [include an explanation for your code](//meta.stackexchange.com/q/114762/269535), as that really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. – Luca Kiebel Jan 12 '22 at 17:19
2

Here is an option using for:

function numberFormat(d) {
   for (var e = 0; d >= 1000; e++) {
      d /= 1000;
   }
   return d.toFixed(3) + ['', ' k', ' M', ' G'][e];
}

let s = numberFormat(9012345678);
console.log(s == '9.012 G');
Zombo
  • 1
  • 62
  • 391
  • 407
1

Adding on the top answer, this will give 1k for 1000 instead of 1.0k

function kFormatter(num) {
    return num > 999 ? num % 1000 === 0 ? (num/1000).toFixed(0) + 'k' : (num/1000).toFixed(1) + 'k' : num
}
rajatbarman
  • 149
  • 1
  • 6
1
  • Support negative number
  • Checking for !isFinite
  • Change ' K M G T P E Z Y' to ' K M' if you want the max unit is M
  • Option for base ( 1K = 1000 / 1K = 1024 )

Number.prototype.prefix = function (precision, base) {

  var units = ' K M G T P E Z Y'.split(' ');

  if (typeof precision === 'undefined') {
    precision = 2;
  }

  if (typeof base === 'undefined') {
    base = 1000;
  }

  if (this == 0 || !isFinite(this)) {
    return this.toFixed(precision) + units[0];
  }

  var power = Math.floor(Math.log(Math.abs(this)) / Math.log(base));
  // Make sure not larger than max prefix
  power = Math.min(power, units.length - 1);

  return (this / Math.pow(base, power)).toFixed(precision) + units[power];
};

console.log('0 = ' + (0).prefix()) // 0.00
console.log('10000 = ' + (10000).prefix()) // 10.00K
console.log('1234000 = ' + (1234000).prefix(1)) // 1.2M
console.log('-10000 = ' + (-10240).prefix(1, 1024)) // -10.0K
console.log('-Infinity = ' + (-Infinity).prefix()) // -Infinity
console.log('NaN = ' + (NaN).prefix()) // NaN
Steely Wing
  • 16,239
  • 8
  • 58
  • 54
1

A modified version of Waylon Flinn's answer with support for negative exponents:

function metric(number) {

  const SI_SYMBOL = [
    ["", "k", "M", "G", "T", "P", "E"], // +
    ["", "m", "μ", "n", "p", "f", "a"] // -
  ];

  const tier = Math.floor(Math.log10(Math.abs(number)) / 3) | 0;

  const n = tier < 0 ? 1 : 0;

  const t = Math.abs(tier);

  const scale = Math.pow(10, tier * 3);

  return {
    number: number,
    symbol: SI_SYMBOL[n][t],
    scale: scale,
    scaled: number / scale
  }
}

function metric_suffix(number, precision) {
  const m = metric(number);
  return (typeof precision === 'number' ? m.scaled.toFixed(precision) : m.scaled) + m.symbol;
}

for (var i = 1e-6, s = 1; i < 1e7; i *= 10, s *= -1) {
  // toggles sign in each iteration
  console.log(metric_suffix(s * (i + i / 5), 1));
}

console.log(metric(0));

Expected output:

   1.2μ
 -12.0μ
 120.0μ
  -1.2m
  12.0m
-120.0m
   1.2
 -12.0
 120.0
  -1.2k
  12.0k
-120.0k
   1.2M
{ number: 0, symbol: '', scale: 1, scaled: 0 }
1

This function could transform huge numbers (both positive & negative) into a reader friendly format without losing its precision:

function abbrNum(n) {
    if (!n || (n && typeof n !== 'number')) {
      return '';
    }

    const ranges = [
      { divider: 1e12 , suffix: 't' },
      { divider: 1e9 , suffix: 'b' },
      { divider: 1e6 , suffix: 'm' },
      { divider: 1e3 , suffix: 'k' }
    ];
    const range = ranges.find(r => Math.abs(n) >= r.divider);
    if (range) {
      return (n / range.divider).toString() + range.suffix;
    }
    return n.toString();
}

/* test cases */
let testAry = [99, 1200, -150000, 9000000];
let resultAry = testAry.map(abbrNum);
console.log("result array: " + resultAry);
Hamzeen Hameem
  • 2,360
  • 1
  • 27
  • 28
1

Improving @tfmontague's answer further to format decimal places. 33.0k to 33k

largeNumberFormatter(value: number): any {
   let result: any = value;

   if (value >= 1e3 && value < 1e6) { result = (value / 1e3).toFixed(1).replace(/\.0$/, '') + 'K'; }
   if (value >= 1e6 && value < 1e9) { result = (value / 1e6).toFixed(1).replace(/\.0$/, '') + 'M'; }
   if (value >= 1e9) { result = (value / 1e9).toFixed(1).replace(/\.0$/, '') + 'T'; }

   return result;
}
Abdul Rahman
  • 1,833
  • 1
  • 21
  • 21
1

I came up with a very code golfed one, and it is very short!

var beautify=n=>((Math.log10(n)/3|0)==0)?n:Number((n/Math.pow(10,(Math.log10(n)/3|0)*3)).toFixed(1))+["","K","M","B","T",][Math.log10(n)/3|0];

console.log(beautify(1000))
console.log(beautify(10000000))
Kavelin
  • 397
  • 1
  • 11
1

Further improving Salman's Answer because of the cases like nFormatter(999999,1) that returns 1000K.

function formatNumberWithMetricPrefix(num, digits = 1) {
  const si = [
    {value: 1e18, symbol: 'E'},
    {value: 1e15, symbol: 'P'},
    {value: 1e12, symbol: 'T'},
    {value: 1e9, symbol: 'G'},
    {value: 1e6, symbol: 'M'},
    {value: 1e3, symbol: 'k'},
    {value: 0, symbol: ''},
  ];
  const rx = /\.0+$|(\.[0-9]*[1-9])0+$/;
  function divideNum(divider) {
    return (num / (divider || 1)).toFixed(digits);
  }

  let i = si.findIndex(({value}) => num >= value);
  if (+divideNum(si[i].value) >= 1e3 && si[i - 1]) {
    i -= 1;
  }
  const {value, symbol} = si[i];
  return divideNum(value).replace(rx, '$1') + symbol;
}
qwertypomy
  • 41
  • 4
1

Supports up to Number.MAX_SAFE_INTEGER and down to Number.MIN_SAFE_INTEGER

function abbreviateThousands(value) {
  const num = Number(value)
  const absNum = Math.abs(num)
  const sign = Math.sign(num)
  const numLength = Math.round(absNum).toString().length
  const symbol = ['K', 'M', 'B', 'T', 'Q']
  const symbolIndex = Math.floor((numLength - 1) / 3) - 1
  const abbrv = symbol[symbolIndex] || symbol[symbol.length - 1]
  let divisor = 0
  if (numLength > 15) divisor = 1e15
  else if (numLength > 12) divisor = 1e12
  else if (numLength > 9) divisor = 1e9
  else if (numLength > 6) divisor = 1e6
  else if (numLength > 3) divisor = 1e3
  else return num
  return `${((sign * absNum) / divisor).toFixed(divisor && 1)}${abbrv}`
}

console.log(abbreviateThousands(234523452345)) // 234.5b (billion)
console.log(abbreviateThousands(Number.MIN_SAFE_INTEGER)) // -9.0q (quadrillion)
dugong
  • 3,690
  • 4
  • 11
  • 27
0
/*including negative values*/    
function nFormatter(num) {
      let neg = false;
       if(num < 0){
         num = num * -1;
         neg = true;
       }
       if (num >= 1000000000) {
         if(neg){
           return -1 * (num / 1000000000).toFixed(1).replace(/\.0$/, '') + 'G';  
         }
         return (num / 1000000000).toFixed(1).replace(/\.0$/, '') + 'G';
       }
       if (num >= 1000000) {
         if(neg){
           return -1 * (num / 1000000).toFixed(1).replace(/\.0$/, '') + 'M';  
         }
         return (num / 1000000).toFixed(1).replace(/\.0$/, '') + 'M';
       }
       if (num >= 1000) {
         if(neg){
           return -1 * (num / 1000).toFixed(1).replace(/\.0$/, '') + 'K';  
         }
         return (num / 1000).toFixed(1).replace(/\.0$/, '') + 'K';
       }
       return num;
    }
0

I am using this function. It works for both php and javascript.

    /**
     * @param $n
     * @return string
     * Use to convert large positive numbers in to short form like 1K+, 100K+, 199K+, 1M+, 10M+, 1B+ etc
     */
 function num_format($n) {
        $n_format = null;
        $suffix = null;
        if ($n > 0 && $n < 1000) {
           $n_format = Math.floor($n);   
            $suffix = '';
        }
        else if ($n == 1000) {
            $n_format = Math.floor($n / 1000);   //For PHP only use floor function insted of Math.floor()
            $suffix = 'K';
        }
        else if ($n > 1000 && $n < 1000000) {
            $n_format = Math.floor($n / 1000);
            $suffix = 'K+';
        } else if ($n == 1000000) {
            $n_format = Math.floor($n / 1000000);
            $suffix = 'M';
        } else if ($n > 1000000 && $n < 1000000000) {
            $n_format = Math.floor($n / 1000000);
            $suffix = 'M+';
        } else if ($n == 1000000000) {
            $n_format = Math.floor($n / 1000000000);
            $suffix = 'B';
        } else if ($n > 1000000000 && $n < 1000000000000) {
            $n_format = Math.floor($n / 1000000000);
            $suffix = 'B+';
        } else if ($n == 1000000000000) {
            $n_format = Math.floor($n / 1000000000000);
            $suffix = 'T';
        } else if ($n >= 1000000000000) {
            $n_format = Math.floor($n / 1000000000000);
            $suffix = 'T+';
        }


       /***** For PHP  ******/
       //  return !empty($n_format . $suffix) ? $n_format . $suffix : 0;

       /***** For Javascript ******/
        return ($n_format + $suffix).length > 0 ? $n_format + $suffix : 0;
    }
shah
  • 1,163
  • 2
  • 19
  • 40
0

I decided to expand a lot on @Novellizator's answer here to meet my needs. I wanted a flexible function to handle most of my formatting needs without external libraries.

Features

  • Option to use order suffixes (k, M, etc.)
    • Option to specify a custom list of order suffixes to use
    • Option to constrain the min and max order
  • Control over the number of decimal places
  • Automatic order-separating commas
  • Optional percent or dollar formatting
  • Control over what to return in the case of non-numeric input
  • Works on negative and infinite numbers

Examples

let x = 1234567.8;
formatNumber(x);  // '1,234,568'
formatNumber(x, {useOrderSuffix: true});  // '1M'
formatNumber(x, {useOrderSuffix: true, decimals: 3, maxOrder: 1});  // '1,234.568k'
formatNumber(x, {decimals: 2, style: '$'});  // '$1,234,567.80'

x = 10.615;
formatNumber(x, {style: '%'});  // '1,062%'
formatNumber(x, {useOrderSuffix: true, decimals: 1, style: '%'});  // '1.1k%'
formatNumber(x, {useOrderSuffix: true, decimals: 5, style: '%', minOrder: 2});  // '0.00106M%'

formatNumber(-Infinity);  // '-∞'
formatNumber(NaN);  // ''
formatNumber(NaN, {valueIfNaN: NaN});  // NaN

Function

/*
 * Return the given number as a formatted string.  The default format is a plain
 * integer with thousands-separator commas.  The optional parameters facilitate
 * other formats:
 *   - decimals = the number of decimals places to round to and show
 *   - valueIfNaN = the value to show for non-numeric input
 *   - style
 *     - '%': multiplies by 100 and appends a percent symbol
 *     - '$': prepends a dollar sign
 *   - useOrderSuffix = whether to use suffixes like k for 1,000, etc.
 *   - orderSuffixes = the list of suffixes to use
 *   - minOrder and maxOrder allow the order to be constrained.  Examples:
 *     - minOrder = 1 means the k suffix should be used for numbers < 1,000
 *     - maxOrder = 1 means the k suffix should be used for numbers >= 1,000,000
 */
function formatNumber(number, {
    decimals = 0,
    valueIfNaN = '',
    style = '',
    useOrderSuffix = false,
    orderSuffixes = ['', 'k', 'M', 'B', 'T'],
    minOrder = 0,
    maxOrder = Infinity
  } = {}) {

  let x = parseFloat(number);

  if (isNaN(x))
    return valueIfNaN;

  if (style === '%')
    x *= 100.0;

  let order;
  if (!isFinite(x) || !useOrderSuffix)
    order = 0;
  else if (minOrder === maxOrder)
    order = minOrder;
  else {
    const unboundedOrder = Math.floor(Math.log10(Math.abs(x)) / 3);
    order = Math.max(
      0,
      minOrder,
      Math.min(unboundedOrder, maxOrder, orderSuffixes.length - 1)
    );
  }

  const orderSuffix = orderSuffixes[order];
  if (order !== 0)
    x /= Math.pow(10, order * 3);

  return (style === '$' ? '$' : '') +
    x.toLocaleString(
      'en-US',
      {
        style: 'decimal',
        minimumFractionDigits: decimals,
        maximumFractionDigits: decimals
      }
    ) +
    orderSuffix +
    (style === '%' ? '%' : '');
}
MarredCheese
  • 17,541
  • 8
  • 92
  • 91
0

Wow there are so many answers on here. I thought I would give you how I solved it as it seemed to be the easiest to read, handles negative numbers, and goes out far in the kilo number range for JavaScript. It also would be easy to change to what you want or extended even farther.

const symbols = [
  { value: 1, symbol: '' },
  { value: 1e3, symbol: 'k' },
  { value: 1e6, symbol: 'M' },
  { value: 1e9, symbol: 'G' },
  { value: 1e12, symbol: 'T' },
  { value: 1e15, symbol: 'P' },
  { value: 1e18, symbol: 'E' }
];

function numberFormatter(num, digits) {
  const numToCheck = Math.abs(num);
  for (let i = symbols.length - 1; i >= 0; i--) {
    if (numToCheck >= symbols[i].value) {
      const newNumber = (num / symbols[i].value).toFixed(digits);
      return `${newNumber}${symbols[i].symbol}`;
    }
  }
  return '0';
}

const tests = [
  { num: 1234, digits: 1 },
  { num: 100000000, digits: 1 },
  { num: 299792458, digits: 1 },
  { num: 759878, digits: 1 },
  { num: -759878, digits: 0 },
  { num: 123, digits: 1 },
  { num: 123.456, digits: 1 },
  { num: -123.456, digits: 2 },
  { num: 123.456, digits: 4 }
];
for (let i = 0; i < tests.length; i++) {
  console.log(`numberFormatter(${tests[i].num}, ${tests[i].digits})=${numberFormatter(tests[i].num, tests[i].digits)}`);
}
JT Turner
  • 502
  • 2
  • 14
0

Here is my version of Waylon Flinn's answer. This removes the .0 and fixes an undefined when the tier is not exactly an integer.

const SI_SYMBOL = ['', 'k', 'M', 'G', 'T', 'P', 'E'];

abbreviateNumber(num) {
    const tier = Math.floor(Math.log10(num) / 3) || 0;
    let result = '' + num;
    // if zero, we don't need a suffix
    if (tier > 0) {
      // get suffix and determine scale
      const suffix = SI_SYMBOL[tier];
      const scale = Math.pow(10, tier * 3);
      // scale the number
      const scaled = num / scale;
      // format number and add suffix
      result = scaled.toFixed(1).replace('.0', '') + suffix;
    }
    return result;
  }
Raul Ruiz
  • 49
  • 6
0

Well, you can use the simplest way around.

$('#attrib-id').val(Number(response.column/1000000).toLocaleString()); // Million

You can use for other properties by dividing the value by the number you want like if you want to display "K" in front of a number, you should go for Number(response.column/1000), and the rest of the things accordingly.

Saddam Khan
  • 159
  • 1
  • 6
-1

A shorter alternative :

function nFormatter(num) {
    const format = [
      { value: 1e18, symbol: 'E' },
      { value: 1e15, symbol: 'P' },
      { value: 1e12, symbol: 'T' },
      { value: 1e9, symbol: 'G' },
      { value: 1e6, symbol: 'M' },
      { value: 1e3, symbol: 'k' },
      { value: 1, symbol: '' },
    ];
    const formatIndex = format.findIndex((data) => num >= data.value);
    console.log(formatIndex)
    return (num / format[formatIndex === -1? 6: formatIndex].value).toFixed(2) + format[formatIndex === -1?6: formatIndex].symbol;
  }
  
wkwkwk
  • 310
  • 5
  • 13
-1
function AmountConveter(amount) {
  return Math.abs(amount) > 999
    ? Math.sign(amount) * (Math.abs(amount) / 1000).toFixed(1) + "k"
    : Math.sign(amount) * Math.abs(amount);
}

console.log(AmountConveter(1200)); // 1.2k
console.log(AmountConveter(-1200)); // -1.2k
console.log(AmountConveter(900)); // 900
console.log(AmountConveter(-900)); // -900