# Convert long number into abbreviated string in JavaScript, with a special shortness requirement

In JavaScript, how would one write a function that converts a given [edit: positive integer] number (below 100 billion) into a 3-letter abbreviation -- where 0-9 and a-z/A-Z are counting as a letter, but the dot (as it's so tiny in many proportional fonts) would not, and would be ignored in terms of the letter limit?

This question is related to this helpful thread, but it's not the same; for instance, where that function would turn e.g. "123456 -> 1.23k" ("123.5k" being 5 letters) I am looking for something that does "123456 -> 0.1m" ("0[.]1m" being 3 letters). For instance, this would be the output of hoped function (left original, right ideal return value):

``````0                      "0"
12                    "12"
123                  "123"
1234                "1.2k"
12345                "12k"
123456              "0.1m"
1234567             "1.2m"
12345678             "12m"
123456789           "0.1b"
1234567899          "1.2b"
12345678999          "12b"
``````

Thanks!

Update: Thanks! An answer is in and works per the requirements when the following amendments are made:

``````function abbreviateNumber(value) {
var newValue = value;
if (value >= 1000) {
var suffixes = ["", "k", "m", "b","t"];
var suffixNum = Math.floor( (""+value).length/3 );
var shortValue = '';
for (var precision = 2; precision >= 1; precision--) {
shortValue = parseFloat( (suffixNum != 0 ? (value / Math.pow(1000,suffixNum) ) : value).toPrecision(precision));
var dotLessShortValue = (shortValue + '').replace(/[^a-zA-Z 0-9]+/g,'');
if (dotLessShortValue.length <= 2) { break; }
}
if (shortValue % 1 != 0)  shortValue = shortValue.toFixed(1);
newValue = shortValue+suffixes[suffixNum];
}
return newValue;
}
``````

I believe ninjagecko's solution doesn't quite conform with the standard you wanted. The following function does:

``````function intToString (value) {
var suffixes = ["", "k", "m", "b","t"];
var suffixNum = Math.floor((""+value).length/3);
var shortValue = parseFloat((suffixNum != 0 ? (value / Math.pow(1000,suffixNum)) : value).toPrecision(2));
if (shortValue % 1 != 0) {
shortValue = shortValue.toFixed(1);
}
return shortValue+suffixes[suffixNum];
}
``````

For values greater than 99 trillion no letter will be added, which can be easily fixed by appending to the 'suffixes' array.

Edit by Philipp follows: With the following changes it fits with all requirements perfectly!

``````function abbreviateNumber(value) {
var newValue = value;
if (value >= 1000) {
var suffixes = ["", "k", "m", "b","t"];
var suffixNum = Math.floor( (""+value).length/3 );
var shortValue = '';
for (var precision = 2; precision >= 1; precision--) {
shortValue = parseFloat( (suffixNum != 0 ? (value / Math.pow(1000,suffixNum) ) : value).toPrecision(precision));
var dotLessShortValue = (shortValue + '').replace(/[^a-zA-Z 0-9]+/g,'');
if (dotLessShortValue.length <= 2) { break; }
}
if (shortValue % 1 != 0)  shortValue = shortValue.toFixed(1);
newValue = shortValue+suffixes[suffixNum];
}
return newValue;
}
``````

This handles very large values as well and is a bit more succinct and efficient.

``````abbreviate_number = function(num, fixed) {
if (num === null) { return null; } // terminate early
if (num === 0) { return '0'; } // terminate early
fixed = (!fixed || fixed < 0) ? 0 : fixed; // number of decimal places to show
var b = (num).toPrecision(2).split("e"), // get power
k = b.length === 1 ? 0 : Math.floor(Math.min(b[1].slice(1), 14) / 3), // floor at decimals, ceiling at trillions
c = k < 1 ? num.toFixed(0 + fixed) : (num / Math.pow(10, k * 3) ).toFixed(1 + fixed), // divide by power
d = c < 0 ? c : Math.abs(c), // enforce -0 is 0
e = d + ['', 'K', 'M', 'B', 'T'][k]; // append power
return e;
}
``````

Results:

``````for(var a='', i=0; i < 14; i++){
a += i;
console.log(a, abbreviate_number(parseInt(a),0));
console.log(-a, abbreviate_number(parseInt(-a),0));
}

0 0
-0 0
01 1
-1 -1
012 12
-12 -12
0123 123
-123 -123
01234 1.2K
-1234 -1.2K
012345 12.3K
-12345 -12.3K
0123456 123.5K
-123456 -123.5K
01234567 1.2M
-1234567 -1.2M
012345678 12.3M
-12345678 -12.3M
0123456789 123.5M
-123456789 -123.5M
012345678910 12.3B
-12345678910 -12.3B
01234567891011 1.2T
-1234567891011 -1.2T
0123456789101112 123.5T
-123456789101112 -123.5T
012345678910111213 12345.7T
-12345678910111212 -12345.7T
``````

A lot of answers on this thread get rather complicated, using `Math` objects, map objects, for-loops, etc. But those approaches don't actually improve the design very much - they introduce more lines of code, more complexity, and more memory overhead. After evaluating several approaches, I think the manual approach is the easiest to understand, and provides the highest performance.

``````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));``````

I think you cant try this numeraljs/

If you want convert 1000 to 1k

``````console.log(numeral(1000).format('0a'));
``````

and if you want convert 123400 to 123.4k try this

``````console.log(numeral(123400).format('0.0a'));
``````

Here's what I think is a fairly elegant solution. It does not attempt to deal with negative numbers:

``````const COUNT_ABBRS = [ '', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y' ];

function formatCount(count, withAbbr = false, decimals = 2) {
const i     = 0 === count ? count : Math.floor(Math.log(count) / Math.log(1000));
let result  = parseFloat((count / Math.pow(1000, i)).toFixed(decimals));
if(withAbbr) {
result += `\${COUNT_ABBRS[i]}`;
}
return result;
}
``````

Examples:

``````   formatCount(1000, true);
=> '1k'
formatCount(100, true);
=> '100'
formatCount(10000, true);
=> '10k'
formatCount(10241, true);
=> '10.24k'
formatCount(10241, true, 0);
=> '10k'
formatCount(10241, true, 1)
=> '10.2k'
formatCount(1024111, true, 1)
=> '1M'
formatCount(1024111, true, 2)
=> '1.02M'
``````

Based on my answer at https://stackoverflow.com/a/10600491/711085 , your answer is actually slightly shorter to implement, by using `.substring(0,3)`:

``````function format(n) {
with (Math) {
var base = floor(log(abs(n))/log(1000));
var suffix = 'kmb'[base-1];
return suffix ? String(n/pow(1000,base)).substring(0,3)+suffix : ''+n;
}
}
``````

(As usual, don't use Math unless you know exactly what you're doing; assigning `var pow=...` and the like would cause insane bugs. See link for a safer way to do this.)

``````> tests = [-1001, -1, 0, 1, 2.5, 999, 1234,
1234.5, 1000001, Math.pow(10,9), Math.pow(10,12)]
> tests.forEach(function(x){ console.log(x,format(x)) })

-1001 "-1.k"
-1 "-1"
0 "0"
1 "1"
2.5 "2.5"
999 "999"
1234 "1.2k"
1234.5 "1.2k"
1000001 "1.0m"
1000000000 "1b"
1000000000000 "1000000000000"
``````

You will need to catch the case where the result is >=1 trillion, if your requirement for 3 chars is strict, else you risk creating corrupt data, which would be very bad.

After some playing around, this approach seems to meet the required criteria. Takes some inspiration from @chuckator's answer.

``````function abbreviateNumber(value) {

if (value <= 1000) {
return value.toString();
}

const numDigits = (""+value).length;
const suffixIndex = Math.floor(numDigits / 3);

const normalisedValue = value / Math.pow(1000, suffixIndex);

let precision = 2;
if (normalisedValue < 1) {
precision = 1;
}

const suffixes = ["", "k", "m", "b","t"];
return normalisedValue.toPrecision(precision) + suffixes[suffixIndex];
}
``````

Intl is the Javascript standard 'package' for implemented internationalized behaviours. Intl.NumberFormatter is specifically the localized number formatter. So this code actually respects your locally configured thousands and decimal separators.

``````intlFormat(num) {
return new Intl.NumberFormat().format(Math.round(num*10)/10);
}

abbreviateNumber(value) {
let num = Math.floor(value);
if(num >= 1000000000)
return this.intlFormat(num/1000000000)+'B';
if(num >= 1000000)
return this.intlFormat(num/1000000)+'M';
if(num >= 1000)
return this.intlFormat(num/1000)+'k';
return this.intlFormat(num);
}
``````

abbreviateNumber(999999999999) // Gives 999B

Code

``````const SI_PREFIXES = [
{ 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 abbreviateNumber = (number) => {
if (number === 0) return number

const tier = SI_PREFIXES.filter((n) => number >= n.value).pop()
const numberFixed = (number / tier.value).toFixed(1)

return `\${numberFixed}\${tier.symbol}`
}

abbreviateNumber(2000) // "2.0k"
abbreviateNumber(2500) // "2.5k"
abbreviateNumber(255555555) // "255.6M"
``````

Test:

``````import abbreviateNumber from './abbreviate-number'

test('abbreviateNumber', () => {
expect(abbreviateNumber(0)).toBe('0')
expect(abbreviateNumber(100)).toBe('100')
expect(abbreviateNumber(999)).toBe('999')

expect(abbreviateNumber(1000)).toBe('1.0k')
expect(abbreviateNumber(100000)).toBe('100.0k')
expect(abbreviateNumber(1000000)).toBe('1.0M')
expect(abbreviateNumber(1e6)).toBe('1.0M')
expect(abbreviateNumber(1e10)).toBe('10.0G')
expect(abbreviateNumber(1e13)).toBe('10.0T')
expect(abbreviateNumber(1e16)).toBe('10.0P')
expect(abbreviateNumber(1e19)).toBe('10.0E')

expect(abbreviateNumber(1500)).toBe('1.5k')
expect(abbreviateNumber(1555)).toBe('1.6k')

expect(abbreviateNumber(undefined)).toBe('0')
expect(abbreviateNumber(null)).toBe(null)
expect(abbreviateNumber('100')).toBe('100')
expect(abbreviateNumber('1000')).toBe('1.0k')
})
``````

I'm using this function to get these values.

``````function Converter(number, fraction) {
let ranges = [
{ divider: 1, suffix: '' },
{ divider: 1e3, suffix: 'K' },
{ divider: 1e6, suffix: 'M' },
{ divider: 1e9, suffix: 'G' },
{ divider: 1e12, suffix: 'T' },
{ divider: 1e15, suffix: 'P' },
{ divider: 1e18, suffix: 'E' },
]
//find index based on number of zeros
let index = (Math.abs(number).toString().length / 3).toFixed(0)
return (number / ranges[index].divider).toFixed(fraction) + ranges[index].suffix
}
``````

Each 3 digits has different suffix, that's what i'm trying to find firstly.

So, remove negative symbol if exists, then find how many 3 digits in this number.

after that find appropriate suffix based on previous calculation added to divided number.

``````Converter(1500, 1)
``````

Will return:

``````1.5K
``````

Here's another take on it. I wanted 123456 to be 123.4K instead of 0.1M

``````function convert(value) {
var length = (value + '').length,
index = Math.ceil((length - 3) / 3),
suffix = ['K', 'M', 'B', 'T'];

if (length < 4) return value;
return (value / Math.pow(1000, index)).toFixed(1) + suffix[index - 1];
}
``````

I found better solution on SO here with fiddle running examples as @chucktator solution returns NaN in many cases. It worked perfectly fine for me.

``````            function converse_number (labelValue) {

// Nine Zeroes for Billions
return Math.abs(Number(labelValue)) >= 1.0e+9

? Math.abs(Number(labelValue)) / 1.0e+9 + "B"
// Six Zeroes for Millions
: Math.abs(Number(labelValue)) >= 1.0e+6

? Math.abs(Number(labelValue)) / 1.0e+6 + "M"
// Three Zeroes for Thousands
: Math.abs(Number(labelValue)) >= 1.0e+3

? Math.abs(Number(labelValue)) / 1.0e+3 + "K"

: Math.abs(Number(labelValue));

}
``````

@nimesaram

Your solution will not be desirable for the following case:

``````Input 50000
Output 50.0k
``````

Following solution will work fine.

``````const convertNumberToShortString = (
number: number,
fraction: number
) => {
let newValue: string = number.toString();
if (number >= 1000) {
const ranges = [
{ divider: 1, suffix: '' },
{ divider: 1e3, suffix: 'k' },
{ divider: 1e6, suffix: 'm' },
{ divider: 1e9, suffix: 'b' },
{ divider: 1e12, suffix: 't' },
{ divider: 1e15, suffix: 'p' },
{ divider: 1e18, suffix: 'e' }
];
//find index based on number of zeros
const index = Math.floor(Math.abs(number).toString().length / 3);
let numString = (number / ranges[index].divider).toFixed(fraction);
numString =
parseInt(numString.substring(numString.indexOf('.') + 1)) === 0
? Math.floor(number / ranges[index].divider).toString()
: numString;
newValue = numString + ranges[index].suffix;
}
return newValue;
};

// Input 50000
// Output 50k
// Input 4500
// Output 4.5k
``````

The modern, easy, built-in, highly customizable, and 'no-code' way: Intl.FormatNumber 's format function (compatibility graph)

``````var numbers = [98721, 9812730,37462,29,093484620123, 9732,0283737718234712]
for(let num of numbers){
console.log(new Intl.NumberFormat( 'en-US', { maximumFractionDigits: 1,notation: "compact" , compactDisplay: "short" }).format(num));
}
98.7K
9.8M
37.5K
29
93.5B
9.7K
283.7T
``````

Notes:

• If you're using typescript add a `//@ts-ignore` before `notation` (source)
• And a list of all the keys in the `options` parameter: https://docs.w3cub.com/javascript/global_objects/numberformat/
• When using `style: 'currency'`, you must remove maximumFractionDigits, as it will figure this out for you.

## Use as a Number Prototype

For easy and direct you. Simply make a prototype of it. Here is an example.

``````Number.prototype.abbr = function (decimal = 2): string {
const notations = ['', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'],
i = Math.floor(Math.log(this) / Math.log(1000));
return `\${parseFloat((this / Math.pow(1000, i)).toFixed(decimal))}\${notations[i]}`;
};
``````