Based on this question: Is there a way to round numbers into a friendly format?
THE CHALLENGE - UPDATED! (removed hundreds abbreviation from spec)
The shortest code by character count that will abbreviate an integer (no decimals).
Code should include the full program.
Relevant range is from 0 - 9,223,372,036,854,775,807
(the upper limit for signed 64 bit integer).
The number of decimal places for abbreviation will be positive. You will not need to calculate the following: 920535 abbreviated -1 place
(which would be something like 0.920535M
).
Numbers in the tens and hundreds place (0-999
) should never be abbreviated (the abbreviation for the number 57
to 1+
decimal places is 5.7dk
- it is unneccessary and not friendly).
Remember to round half away from zero (23.5 gets rounded to 24). Banker's rounding is verboten.
Here are the relevant number abbreviations:
h = hundred (10
2
)
k = thousand (10
3
)
M = million (10
6
)
G = billion (10
9
)
T = trillion (10
12
)
P = quadrillion (10
15
)
E = quintillion (10
18
)
SAMPLE INPUTS/OUTPUTS (inputs can be passed as separate arguments):
First argument will be the integer to abbreviate. The second is the number of decimal places.
12 1 => 12 // tens and hundreds places are never rounded
1500 2 => 1.5k
1500 0 => 2k // look, ma! I round UP at .5
0 2 => 0
1234 0 => 1k
34567 2 => 34.57k
918395 1 => 918.4k
2134124 2 => 2.13M
47475782130 2 => 47.48G
9223372036854775807 3 => 9.223E
// ect...
Original answer from related question (JavaScript, does not follow spec):
function abbrNum(number, decPlaces) {
// 2 decimal places => 100, 3 => 1000, etc
decPlaces = Math.pow(10,decPlaces);
// Enumerate number abbreviations
var abbrev = [ "k", "m", "b", "t" ];
// Go through the array backwards, so we do the largest first
for (var i=abbrev.length-1; i>=0; i--) {
// Convert array index to "1000", "1000000", etc
var size = Math.pow(10,(i+1)*3);
// If the number is bigger or equal do the abbreviation
if(size <= number) {
// Here, we multiply by decPlaces, round, and then divide by decPlaces.
// This gives us nice rounding to a particular decimal place.
number = Math.round(number*decPlaces/size)/decPlaces;
// Add the letter for the abbreviation
number += abbrev[i];
// We are done... stop
break;
}
}
return number;
}
((j.&(1&{)":({.%&1e3{:));{&' kMGTPE'@{.)(([:<.1e3^.{.),{:,{.)
Output:
((j.&(1&{)":({.%&1e3{:));{&' kMGTPE'@{.)(([:<.1e3^.{.),{:,{.) 1500 0
┌─┬─┐
│2│k│
└─┴─┘
((j.&(1&{)":({.%&1e3{:));{&' kMGTPE'@{.)(([:<.1e3^.{.),{:,{.) 987654321987654321 4
┌────────┬─┐
│987.6543│P│
└────────┴─┘
(The reason the output is "boxed" like that is because J doesn't support a list consisting of varying types)
Explanation (from right to left):
(([:<.1000^.{.),{:,{.)
We make a new 3-element list, using ,
to join ([:<.1000^.{.)
(the floored <.
base 1000 log ^.
of the first param {.
. We join it with the second param {:
and then the first param {.
.
So after the first bit, we've transformed say 12345 2
into 1 2 12345
((j.&(1&{)":({.%&1000{:));{&' kMGTPE'@{.)
uses ;
to join the two halves of the expression together in a box to produce the final output.
The first half is ((j.&(1&{)":({.%&1000{:))
which divides (%
) the last input number ({:
) by 1000, the first number of times. Then it sets the precision ":
using the second number in the input list (1&{
).
The second half {&' kMGTPE'@{.
- this uses the first number to select ({
) the appropriate character from the 0-indexed list of abbreviations.