Format a number as 2.5K if a thousand or more, otherwise 900
Asked Answered
S

37

327

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?

Sandpiper answered 27/2, 2012 at 7:52 Comment(4)
Do you also need M and G?Jemy
I will need M yes...Can you help?Sandpiper
see #17633962Denudation
See https://mcmap.net/q/98529/-format-a-number-as-2-5k-if-a-thousand-or-more-otherwise-900 for a locale friendly ES2020 solutionBlaise
B
288

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
Basque answered 27/2, 2012 at 7:56 Comment(10)
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.Buntline
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.8kMoue
Note that one kilobyte is 1024 bytes in some cases: en.wikipedia.org/wiki/KilobyteSkylark
Any idea how we can make 1000 display as 1.0k instead of 1k?Evangel
Doesn't completely answer the user's question. "I will need M yes...Can you help?" - Carl WeisFlatways
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 ?Fragrance
Math.round(Math.abs(num)/100)/10 instead of (Math.abs(num)/1000).toFixed(1) so typescript is happyPotentiometer
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' : numBryanbryana
Why Math.sign(num)*Math.abs(num) ? Isn't it just num?Electroencephalogram
Here is simplified version const kFormatter = (num) => Math.abs(num) >= 1000 ? +(num/1000).toFixed(1) + 'k' : num;Electroencephalogram
J
433

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 regexp = /\.0+$|(?<=\.[0-9]*[1-9])0+$/;
  const item = lookup.findLast(item => num >= item.value);
  return item ? (num / item.value).toFixed(digits).replace(regexp, "").concat(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(test => {
  console.log("nFormatter(%f, %i) = %s", test.num, test.digits, nFormatter(test.num, test.digits));
});

The lookup contains SI prefix sorted ascending. The regexp matches trailing zeros (and the dot, if possible) in the number.

Note:

Array.findLast requires ES2023. If you get an error, change lookup.findLast(...) to lookup.slice().reverse().find(...)

Jemy answered 27/2, 2012 at 9:3 Comment(15)
@SalmanA - Great help, it fails if one pass arg as string, if cleansed with parseFloat works well. Thank you!Lubberly
Small fix for numbers less < 1000, add {value: 1E0, symbol: ""} to var si =Donatelli
@GiovanniAzua just replace if (num >= si[i].value) with if (Math.abs(num) >= si[i].value)Jemy
what does .replace(rx, "$1") do ?Mapel
@Mapel the regex is used to trim trailing zeros e.g. 1.0 becomes 1 and 1.10 becomes 1.1Jemy
To account for negative values use Math.abs(num) >= si[i].value in the if statement inside the loopAudette
also, it might be great to treat the special case at the beginning. if(num === 0) return 0;Colour
'[0-9]' can be simplified to '\d'Fugazy
Great solution, but this doesn't account for negative numbers. Trying to figure out how.Enfilade
@rukshan see comments above that mention Math.absJemy
UPDATE : I added a simple if (num<0) and then added a "-" sign infront of the returned value if it is, to account for negative numbers. Had to use another variable though.Enfilade
I think the abbreviation for billion is B - abbreviations.yourdictionary.com/…Baun
@john the original version of answer used SI prefixes (en.m.wikipedia.org/wiki/Metric_prefix). Billion is Giga. Of course you can change it.Jemy
if I give { num: 999.9, digits: 0 } it will return 1000 not 1kFireboard
accepted answer should be the one using JS native formatterDecurion
B
288

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
Basque answered 27/2, 2012 at 7:56 Comment(10)
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.Buntline
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.8kMoue
Note that one kilobyte is 1024 bytes in some cases: en.wikipedia.org/wiki/KilobyteSkylark
Any idea how we can make 1000 display as 1.0k instead of 1k?Evangel
Doesn't completely answer the user's question. "I will need M yes...Can you help?" - Carl WeisFlatways
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 ?Fragrance
Math.round(Math.abs(num)/100)/10 instead of (Math.abs(num)/1000).toFixed(1) so typescript is happyPotentiometer
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' : numBryanbryana
Why Math.sign(num)*Math.abs(num) ? Isn't it just num?Electroencephalogram
Here is simplified version const kFormatter = (num) => Math.abs(num) >= 1000 ? +(num/1000).toFixed(1) + 'k' : num;Electroencephalogram
L
267

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

Live answered 2/4, 2020 at 9:30 Comment(7)
That package has been deprecated, so please use this link: npmjs.com/package/@formatjs/intl-numberformatRoydd
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.Motorboat
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.)Acacia
There are a couple of issues with compact and its very flexible.Wilkins
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. €Wilkins
Also for Germany and some language's any number in thousand's will not have compact. But it will be displayed as suchWilkins
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"Very
I
126

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?

Immiscible answered 21/11, 2016 at 16:2 Comment(6)
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.Granule
Just use Math.abs to add support to negative numbers, like that: var tier = Math.log10(Math.abs(number)) / 3 | 0;.Unregenerate
Thanks, I made the change to enable negative numbers.Immiscible
Does this work just like the accepted answer without any issues?Dysteleology
Thanks, that's actually the most understandable answer, in terms of what's happening.Dunning
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.Narra
W
95

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

Whosoever answered 21/2, 2013 at 4:59 Comment(3)
Anyway to do this without rounding the number? 1,590,000 will return 1.6M.Beginner
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.Obstreperous
@Whosoever you're the code I'm trying to implement in the counter script but not getting this is my codepen link 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.Haste
F
54

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);
}
Flatways answered 4/5, 2019 at 23:13 Comment(1)
@Jan - Updated my post with an example, but felt it was simple enough to compute the negative form using '-' + formatCash(-1 * number)Flatways
K
29
/**
 * 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.

Keary answered 19/2, 2015 at 13:50 Comment(1)
You can change the if to Math.abs(num) >= decimal.Manager
M
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/

Money answered 1/2, 2017 at 16:19 Comment(5)
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 :/Anticlinorium
@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.Mudguard
If you don't want rounding you can do this after the scale step: const floored = Math.floor(scaled * 10) / 10;Bingen
doesn't work properly with negative numbersTaffeta
@Mudguard sorry i haven't seen this for a year... i added your change. wrx!Money
G
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"
Gilder answered 5/4, 2018 at 11:14 Comment(0)
M
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);
Morea answered 21/5, 2021 at 9:7 Comment(4)
Thanks, This is helpful Because this is not a round return figure like others.Amphioxus
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 😞Accelerator
I think that's not with this function. I tested it with 100000 calls and nothing happened. Please share your code.Morea
For the number "1000" this returns "1000". To return "1K" replace the "> 1000" with ">= 1000" in the while lineJoerg
B
14

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.

Baseborn answered 1/4, 2020 at 5:10 Comment(1)
not working at all on node.js afaictClod
J
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"
Jedjedd answered 3/11, 2015 at 10:32 Comment(0)
S
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) }`));
Secant answered 5/3, 2020 at 16:30 Comment(0)
R
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 
Rainey answered 1/5, 2020 at 9:39 Comment(0)
A
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"
Accidie answered 6/1, 2015 at 8:29 Comment(0)
G
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)}`);
  });
});
Glucoprotein answered 16/12, 2020 at 13:17 Comment(2)
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.Wimble
@Wimble 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.Kathlyn
C
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/

Cedric answered 15/6, 2015 at 23:40 Comment(1)
numeraljs is not maintained anymore. The most active fork seems to be numbro. But neither of them support the SI/metric notationJedjedd
L
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]) );
    }
Lubet answered 29/8, 2019 at 22:56 Comment(0)
J
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"

Jahdai answered 10/1, 2022 at 12:35 Comment(1)
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, 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.Medium
N
2

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;
}
Natter answered 6/11, 2019 at 16:43 Comment(0)
G
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');
Gymnastic answered 17/11, 2020 at 19:26 Comment(0)
R
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
}
Rompish answered 9/3, 2017 at 5:57 Comment(0)
S
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
Shockley answered 4/9, 2018 at 1:35 Comment(2)
(11000).prefix() equals to 10.74K not very accurate should say 11.00KGallinacean
@Gallinacean Just change the 1024 to 1000Shockley
E
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 }
Epilogue answered 28/3, 2019 at 9:58 Comment(0)
S
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);
Selvage answered 11/4, 2019 at 12:9 Comment(0)
H
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;
}
Holoblastic answered 19/7, 2019 at 6:4 Comment(0)
D
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))
Durman answered 28/10, 2019 at 20:10 Comment(0)
G
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)
Gerrald answered 14/9, 2020 at 15:4 Comment(0)
P
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;
    }
Preinstruct answered 15/3, 2018 at 11:37 Comment(1)
pls add some explanation of your solutionReflex
B
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;
    }
Boorman answered 12/6, 2019 at 10:5 Comment(0)
S
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 === '%' ? '%' : '');
}
Styliform answered 4/7, 2019 at 20:48 Comment(0)
F
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)}`);
}
Felodese answered 24/7, 2019 at 3:58 Comment(0)
D
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;
  }
Deutsch answered 7/10, 2020 at 6:14 Comment(0)
C
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.

Carabiniere answered 26/3, 2021 at 11:23 Comment(0)
D
0

The JavaScript Internationalization API (Intl) provides a way to format numbers, dates, and strings according to the language and locale conventions. If you're looking to format numbers in a way that represents millions, billions, etc., in a shortened form, you can use the Intl.NumberFormat object with appropriate options.

For example, to format a number to show it in a shortened form for billions, you might specify the notation as "compact" and the compactDisplay as "short" to use abbreviations like "B" for billion. Here's how you could do it:

// Number to format (e.g., 1,250,000,000 for 1.25 billion)
const number = 1250000000;

// Create an Intl.NumberFormat instance for English (US) locale with compact notation
const formatter = new Intl.NumberFormat('en-US', {
  notation: 'compact',
  compactDisplay: 'short' // Other option is 'long'
});

// Format the number
const formattedNumber = formatter.format(number);

document.getElementById('number').innerHTML = formattedNumber;
1250000000 is <span id="number"></span>
Dryly answered 8/3 at 15:17 Comment(0)
M
-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
Morelli answered 27/2, 2012 at 7:52 Comment(0)
E
-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;
  }
  
Ernaldus answered 24/7, 2020 at 3:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.