user3707836 user3707836 - 3 months ago 50
Java Question

Determine million, billion, trillion, quadrillion in Java

From this Standard dictionary numbers, I need a fastest way to convert some number below :

1000000 = 1 Million

1435234 = 1.43 Million

350000000 = 350 Million

1000000000 = 1 Billion

1765000000 = 1.76 Billion

1000000000000 = 1 Trillion

1345342345000 = 1.34 Trillion

1000000000000000 = 1 Quadrillion

100000000000000000 = 100 Quadrillion

and further.

I have tried like this below:

public String truncateNumber(float floatNumber) {
long million = 1000000L;
long billion = 1000000000L;
long trillion = 1000000000000L;
long number = Math.round(floatNumber);
if ((number >= million) && (number < billion)) {
float fraction = calculateFraction(number, million);
return Float.toString(fraction) + "M";
} else if ((number >= billion) && (number < trillion)) {
float fraction = calculateFraction(number, billion);
return Float.toString(fraction) + "B";
}
return Long.toString(number);
}

public float calculateFraction(long number, long divisor) {
long truncate = (number * 10L + (divisor / 2L)) / divisor;
float fraction = (float) truncate * 0.10F;
return fraction;
}


but I think my solution is not quite true. So, what is a fastest way to do that in Java? Many Thanks.

Answer

The first problem is that float does not have enough precision to represent these numbers. In fact, even double does not have enough precision for values in the Nonillion range - although this may not be so important here, because you obviously want to drop most of the information of this number anyhow.

Nevertheless, I have implemented it here using BigInteger. Converting this to use double should be straightforward, if you don't care about the precision issues.

The basic idea here is to create a NavigableMap from powers of 1000 to the respective number name. This map can be quickly looked up using floorEntry to find the best matching power (and thus, the number name).

import java.math.BigInteger;
import java.util.Map.Entry;
import java.util.NavigableMap;
import java.util.TreeMap;

public class NumberNames
{
    public static void main(String[] args)
    {
        test("100", "Nearly nothing");
        test("1000", "1 Thousand");
        test("1230", "1.23 Thousand");
        test("1000000", "1 Million");
        test("1435234", "1.43 Million");
        test("350000000", "350 Million");
        test("1000000000", "1 Billion");
        test("1765000000", "1.76 Billion");
        test("1000000000000", "1 Trillion");
        test("1345342345000", "1.34 Trillion");
        test("1000000000000000", "1 Quadrillion");
        test("100000000000000000", "100 Quadrillion");
        test("1230000000000000000000000000000000000000000000000000000000000000", "1.23 Vigintillion");
    }

    private static void test(String numberString, String string)
    {
        BigInteger number = new BigInteger(numberString);
        System.out.println(number+" is "+createString(number)+" should be "+string);
    }



    private static final String NAMES[] = new String[]{
        "Thousand",
        "Million",
        "Billion",
        "Trillion",
        "Quadrillion",
        "Quintillion",
        "Sextillion",
        "Septillion",
        "Octillion",
        "Nonillion",
        "Decillion",
        "Undecillion",
        "Duodecillion",
        "Tredecillion",
        "Quattuordecillion",
        "Quindecillion",
        "Sexdecillion",
        "Septendecillion",
        "Octodecillion",
        "Novemdecillion",
        "Vigintillion",
    };
    private static final BigInteger THOUSAND = BigInteger.valueOf(1000);
    private static final NavigableMap<BigInteger, String> MAP;
    static
    {
        MAP = new TreeMap<BigInteger, String>();
        for (int i=0; i<NAMES.length; i++)
        {
            MAP.put(THOUSAND.pow(i+1), NAMES[i]);
        }
    }

    public static String createString(BigInteger number)
    {
        Entry<BigInteger, String> entry = MAP.floorEntry(number);
        if (entry == null)
        {
            return "Nearly nothing";
        }
        BigInteger key = entry.getKey();
        BigInteger d = key.divide(THOUSAND);
        BigInteger m = number.divide(d);
        float f = m.floatValue() / 1000.0f;
        float rounded = ((int)(f * 100.0))/100.0f;
        if (rounded % 1 == 0)
        {
            return ((int)rounded) + " "+entry.getValue();
        }
        return rounded+" "+entry.getValue();
    }
}