Convert from one base to another in Java - java

Right now, I'm trying to find a way to convert a number from one base to another in Java, given a number, the base that the number is in, and the base to convert to.
public static void BaseConversion(String number, int base1, int base2){
//convert the number from one base to another
}
I found a solution for JavaScript, and I'm wondering if it would be possible to do something similar in Java:
function convertFromBaseToBase(str, fromBase, toBase){
var num = parseInt(str, fromBase); //convert from one base to another
return num.toString(toBase);
}

You could do
return Integer.toString(Integer.parseInt(number, base1), base2);
So with your function signature, in Java:
public String convertFromBaseToBase(String str, int fromBase, int toBase) {
return Integer.toString(Integer.parseInt(str, fromBase), toBase);
}

public class BaseToBaseConv {
static String baseToBase(String num, int base1, int base2) {
int no = convFrmBaseToDeci(num, base1);
return convFrmDecToBase(no, base2);
}
static String convFrmDecToBase(int num, int base) {
String res = "";
int rem;
// Convert input number is given base by repeatedly
// dividing it by base and taking remainder
while (num > 0) {
rem = num % base;
if (base == 16) {
if (rem == 10)
res += 'A';
else if (rem == 11)
res += 'B';
else if (rem == 12)
res += 'C';
else if (rem == 13)
res += 'D';
else if (rem == 14)
res += 'E';
else if (rem == 15)
res += 'F';
else
res += rem;
} else
res += rem;
num /= base;
}
// Reverse the result
return new StringBuffer(res).reverse().toString();
}
static int convFrmBaseToDeci(String num, int base) {
if (base < 2 || (base > 10 && base != 16))
return -1;
int val = 0;
int power = 1;
for (int i = num.length() - 1; i >= 0; i--) {
int digit = digitToVal(num.charAt(i));
if (digit < 0 || digit >= base)
return -1;
// Decimal equivalent is str[len-1]*1 +
// str[len-1]*base + str[len-1]*(base^2) + ...
val += digit * power;
power = power * base;
}
return val;
}
static int digitToVal(char c) {
if (c >= '0' && c <= '9')
return (int) c - '0';
else
return (int) c - 'A' + 10;
}
public static void main(String [] args) {
System.out.println(baseToBase("12345", 10, 2));
System.out.println(baseToBase("11000000111001", 2, 10));
System.out.println(baseToBase("ABC11", 16, 2));
System.out.println(baseToBase("10101011110000010001", 2, 16));
System.out.println(baseToBase("12322", 8, 16));
}
}

The two-argument versions of Integer.parseInt or Long.parseLong will do this if you can be sure the number in question is within the range of int or long respectively. If you can't guarantee this, use java.math.BigInteger:
BigInteger bi = new BigInteger(number, base1);
return bi.toString(base2);
This can handle arbitrarily-large integers, for example
System.out.println(
new BigInteger("12345678901234567890123456789", 10).toString(16));
// prints 27e41b3246bec9b16e398115 - too big to represent as a long

I believe this will work:
long x = 10;
int baseToConvertTo = 9;
System.out.println(Long.toString(x, baseToConvertTo));
Output: 11

As others have displayed,Integer.parseInt() can do this for you. However, if you're trying to build a converter yourself, the following will work to simply convert a numeric value to the desired radix. Note, for radix above base 10 you have to consider the alpha chars ... I.E. 11-A, 12-B, etc...
public class NumberUtil {
/**
* This example is convoluted as in reality it just uses 'toString' to convert the number...
* However, it displays the logic needed to make the conversion...
*
* To convert a number to a new radix, recursively return the remainder of the number
* divided by the radix for each operation until zero. Then return the concatenated value in reverse.
*
* Example convert 9658 to base 2
*
* 9658 / 2 = 4829 R 0
* 4829 / 2 = 2414 R 1
* 2414 / 2 = 1207 R 0
* 1207 / 2 = 603 R 1
* 603 / 2 = 301 R 1
* 301 / 2 = 150 R 1
* 150 / 2 = 75 R 0
* 75 / 2 = 37 R 1
* 37 / 2 = 18 R 1
* 18 / 2 = 9 R 0
* 9 / 2 = 4 R 1
* 4 / 2 = 2 R 0
* 2 / 2 = 1 R 0
* 1 / 2 = 0 R 1
*
* Answer :: 10010110111010
*
* #param number :: Integer number to convert.
* #param radix :: Radix to convert to.
* #return :: BigInteger of the number converted to the desired radix.
*/
static BigInteger convertBase( int number, int radix ) {
List<Integer> remainder = new ArrayList<>();
int count = 0;
String result = "";
while( number != 0 ) {
remainder.add( count, number % radix != 0 ? number % radix : 0 );
number /= radix;
try {
result += remainder.get( count );
} catch( NumberFormatException e ) {
e.printStackTrace();
}
}
return new BigInteger( new StringBuffer( result ).reverse().toString() );
}
public static void main( String[] args ) {
System.out.println( convertBase( 9658, 2 ) );
}
}

The test:
class Test1 {
public static void main(String[] args) {
String s1 = "10";
int n1 = Integer.parseInt(s1, 8);
System.out.println(s1 + " is " + n1 + " in base10");
String s2 = Integer.toString(n1, 2);
System.out.println(n1 + " is " + s2 + " in base2");
}
}
Gives:
C:\Temp>java Test1
10 is 8 in base10
8 is 1000 in base2
using Integer.parseInt and Integer.toString.

BaseEncoder:
BaseEncoder was written for this question.
Notes:
Support for base 2 to base 3263
Not optimized for speed
Base 64 is non-standard
Output:
baseConversion("10011100", 2, 16) = "9C"
baseConversion("9c", 16, 2) = "10011100"
baseConversion("609643", 10, 64) = "2Krh"
baseConversion("33773377",10, 100) = "bÈbÈ"
baseConversion("18018018",10,1000) = "NNN"
Use:
sout("(\"10011100\", 2, 16)=" + baseConversion("10011100", 2, 16));
sout("(\"9c\", 16, 2)=" + baseConversion("9c", 16, 2));
sout("(\"609643\", 10, 64)=" + baseConversion("609643", 10, 64));
sout("(\"33773377\",10, 100)=" + baseConversion("33773377", 10, 100));
sout("(\"18018018\",10,1000)=" + baseConversion("18018018", 10, 1000));
Source:
/*
* Licensced for commercial or non-commercial use, modification and
* redistribution provided the source code retain this license header and
* attribution. Written to answer to Stack Overflow question 15735079. See
* https://stackoverflow.com/questions/15735079/
* to see the original questions and ( if this code has been modified ) to see
* the original source code. This license does not supercede any licencing
* requirements set forth by StackOverflow. In the event of a disagreement
* between this license and the terms of use set forth by StackOverflow, the
* terms of use and/or license set forth by StackOverflow shall be considered
* the governing terms and license.
*/
package org.myteam.util;
import java.math.BigInteger;
/**
* conversion routines to support
* <pre>
* BaseEncoder.baseConversion("94d6b", 16, 2));
* </pre> allowing conversions between numbering systems of base 2 to base 3263
* inclusive, with the following caveats:<ul>
* <li> WARNING: BASE64 numbers created or parsed with this encoder are not
* compatible with a standard base 64 encoder, and </li>
* <li> WARNING: this class does not currently support unicode, or if it does
* that's only by accident and it most likely does not support characters that
* require more than one codepoint.</li>
* </ul>
* . to convert between two non-standard numbering systems, use two BaseEncoder
* objects e.g.
* <pre>
*
* String numberBase64 = "1X3dt+4N";
* String numberBase16 = new BaseEncoder(16).fromBase10(new BaseEncoder(
* "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/")
* .toBase10(numberBase64));
*
* </pre>
*
* #see https://stackoverflow.com/questions/15735079/
*/
public class BaseEncoder {
public static void main(String[] args) {
sout("(\"10011100\", 2, 16)=" + baseConversion("10011100", 2, 16));
sout("(\"9c\", 16, 2)=" + baseConversion("9c", 16, 2));
sout("(\"609643\", 10, 64)=" + baseConversion("609643", 10, 64));
sout("(\"33773377\",10, 100)=" + baseConversion("33773377", 10, 100));
sout("(\"18018018\",10,1000)=" + baseConversion("18018018", 10, 1000));
// test();
}
private static void sout(String output) {
System.out.println("\tbaseConversion"
+ output.replace("=", " = \"") + "\"");
}
/**
* this is the method that satisfies the criteria set forth by the original
* question at https://stackoverflow.com/questions/15735079/ .
*
* #param fromNumber
* #param fromBase
* #param toBase
* #return
*/
public static String baseConversion(
String fromNumber, int fromBase, int toBase) {
final BigInteger numberBase10 = fromBase == 10
? new BigInteger(fromNumber)
: parseBigInteger(fromNumber, fromBase);
// System.out.println("org.myteam.util.baseConversion():"
// + " numberBase10 = " + numberBase10);
return toBase == 10 ? numberBase10.toString()
: toString(numberBase10, toBase);
}
/**
* Simple test to validate conversion functions. Should be converted to
* support whatever unit tests or automated test suite your organization
* employs. No return value.
*
* #throws IllegalStateException if any test fails, and aborts all tests.
*/
public static void test() throws IllegalStateException {
final int level1 = 100;
final int level2 = 525;
final int level3 = 1000;
final int maxlvl = 3263;
for (int radix = 2; radix < maxlvl;) {
test(radix);
radix += (radix < level1) ? 1
: (radix < level2) ? 17
: (radix < level3) ? 43
: 139;
}
test(3263);
System.out.println("taurus.BaseEncoder.test(): all tests passed.");
}
private static void test(int radix) throws IllegalStateException {
final BigInteger level1 = BigInteger.valueOf(radix);
final BigInteger level2 = level1.multiply(level1);
final BigInteger level3 = level2.multiply(level1);
final BigInteger maxlvl = level3.multiply(level1);
final BigInteger increment1 = BigInteger.ONE;
final BigInteger increment2 = level1.add(BigInteger.ONE);
final BigInteger increment3 = level2
.add(BigInteger.ONE).add(BigInteger.ONE).add(BigInteger.ONE);
final BigInteger increment4 = level3.add(BigInteger.valueOf(17));
final int exitLvl = 5;
int prevLvl = 1;
BigInteger iTest = BigInteger.ZERO;
while (true) {
Throwable err = null;
String radixEncoded = "(conversion to base " + radix + " failed)";
String backToBase10 = "(conversion back to base 10 failed)";
try {
radixEncoded = baseConversion("" + iTest, 10, radix);
backToBase10 = baseConversion(radixEncoded, radix, 10);
} catch (Throwable ex) {
err = ex;
}
if (err != null || !backToBase10.equals("" + iTest)) {
System.out.println("FAIL: "
+ iTest + " base " + radix + " = " + radixEncoded);
System.out.println("FAIL: "
+ radixEncoded + " base 10 = " + backToBase10
+ " (should be " + iTest + ")");
throw new IllegalStateException("Test failed. base 10 '" + iTest
+ "' conversion to/from base" + radix + ".", err);
}
int lvl = (prevLvl == 1 && iTest.compareTo(level1) >= 0) ? 2
: (prevLvl == 2 && iTest.compareTo(level2) >= 0) ? 3
: (prevLvl == 3 && iTest.compareTo(level3) >= 0) ? 4
: (prevLvl == 4 && iTest.compareTo(maxlvl) >= 0) ? exitLvl
: prevLvl;
final BigInteger increment
= (lvl == 1) ? increment1
: (lvl == 2) ? increment2
: (lvl == 3) ? increment3
: (lvl == 4) ? increment4
: BigInteger.ZERO;
iTest = iTest.add(increment);
if (prevLvl != lvl) {
if (lvl == exitLvl && (radix % 56 == 0 || radix > 2700)) {
System.out.println("test():" + " radix " + radix
+ " level " + prevLvl + " test passed.");
}
}
if (lvl == exitLvl) {
break;
}
prevLvl = lvl;
}
}
/**
* <pre>
* String tenAsOctal = toString(BigInteger.TEN, 8); // returns "12"
* </pre>.
*
* #param numberBase10
* #param radix
* #return
*/
public static String toString(BigInteger numberBase10, int radix) {
return new BaseEncoder(radix).fromBase10(numberBase10);
}
/**
* <pre>
* String tenAsOctal = toString(BigInteger.TEN, "01234567"); // returns "12"
* </pre>.
*
* #param numberBase10
* #param digits
* #return
*/
public static String toString(BigInteger numberBase10, String digits) {
return new BaseEncoder(digits).fromBase10(numberBase10);
}
/**
* <pre>
* String tenAsOctal = "12"; // ("1" x 8^1) + ("2" x 8^0) = 10
* String tenAsDecimal = parseBigInteger(tenAsOctal, 8);
* System.out.println(tenAsDecimal); // "10"
* </pre>.
*
* #param numberEncoded
* #param radix
* #return
*/
public static BigInteger parseBigInteger(String numberEncoded, int radix) {
return new BaseEncoder(radix).toBase10(numberEncoded);
}
/**
* <pre>
* String tenAsOctal = "12"; // ("1" x 8^1) + ("2" x 8^0) = 10
* String tenAsDecimal = parseBigInteger(tenAsOctal, "01234567");
* System.out.println(tenAsDecimal); // "10"
* </pre>.
*
* #param numberEncoded
* #param digits
* #return
*/
public static BigInteger parseBigInteger(
String numberEncoded, String digits) {
return new BaseEncoder(digits).toBase10(numberEncoded);
}
/**
* <pre>
* String tenAsOctal = "12"; // ("1" x 8^1) + ("2" x 8^0) = 10
* int tenAsDecimal = parseInt(tenAsOctal, 8);
* System.out.println(tenAsDecimal); // 10
* </pre>.
*
* #param numberEncoded
* #param radix
* #return
*/
public static int parseInt(String numberEncoded, int radix) {
return new BaseEncoder(radix).toBase10(numberEncoded).intValueExact();
}
/**
* <pre>
* String tenAsOctal = "12"; // ("1" x 8^1) + ("2" x 8^0) = 10
* int tenAsDecimal = parseInt(tenAsOctal, "01234567");
* System.out.println(tenAsDecimal); // 10
* </pre>.
*
* #param numberEncoded
* #param digits
* #return
*/
public static int parseInt(String numberEncoded, String digits) {
return new BaseEncoder(digits).toBase10(numberEncoded).intValueExact();
}
/**
* <pre>
* String tenAsOctal = "12"; // ("1" x 8^1) + ("2" x 8^0) = 10
* long tenAsDecimal = parseLong(tenAsOctal, 8);
* System.out.prlongln(tenAsDecimal); // 10
* </pre>.
*
* #param numberEncoded
* #param radix
* #return
*/
public static long parseLong(String numberEncoded, int radix) {
return new BaseEncoder(radix).toBase10(numberEncoded).longValueExact();
}
/**
* <pre>
* String tenAsOctal = "12"; // ("1" x 8^1) + ("2" x 8^0) = 10
* long tenAsDecimal = parseLong(tenAsOctal, "01234567");
* System.out.prlongln(tenAsDecimal); // 10
* </pre>.
*
* #param numberEncoded
* #param digits
* #return
*/
public static long parseLong(String numberEncoded, String digits) {
return new BaseEncoder(digits).toBase10(numberEncoded).longValueExact();
}
/**
* each character in this string represents one digit in the base-X
* numbering system supported by this instance, where X = the length of the
* string. e.g.
* <pre>
* base 2 (binary) digits = "01"
* base 8 (octal) digits = "01234567"
* base 10 (decimal) digits = "0123456789"
* base 16 (hexdecimal) digits = "0123456789ABCDEF"
* </pre> digits follow this pattern until base 64. a somewhat arbitrary
* character system is utilized to support base 65 to base 3263.
*/
private final String digits;
/**
* specify a numbering system between base 2 and base 64 inclusive
* <pre>
* String fiveAsBinary = new BaseEncoder(2).fromBase10(5);
* System.out.println(fiveAsBinary); // "101"
* </pre> to use a numbering system with more than 64 digits, or to use your
* own custom digits, use
* <pre>
* new BaseEncoder(String)
* </pre>.
*
* #param radix
*/
public BaseEncoder(int radix) {
String digitsTemp = getDefaultDigitsForBase(radix);
digits = digitsTemp;
}
/**
* specify digits to use for your numbering system for example base 16 could
* be represented as
* <pre>
* new BaseEncoder("0123456789ABCDEF")
* </pre> <br>
* and base 64 could be represented as
* <pre>
* new BaseEncoder("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
* + "abcdefgjijklmnopqrstuvwxyz+/")
* </pre>.
*
* #param digits
*/
public BaseEncoder(String digits) {
if (digits.length() < 2) {
final String errorMessage = "Supported bases include 2 and above."
+ " " + "Please provide at least two characters"
+ " " + "e.g. new BaseEncoder(\"01\") // binary or base 2";
throw new IllegalArgumentException(errorMessage);
}
this.digits = digits;
}
/**
* convert a number from a non-standard numbering format to base 10
* (BigInteger).
*
* #param numberEncoded
* #return
*/
public BigInteger toBase10(final String numberEncoded) {
final int radix = digits.length();
final BigInteger magnitude = BigInteger.valueOf(radix);
final char[] chars = numberEncoded.toCharArray();
BigInteger numberBase10 = BigInteger.ZERO;
for (int i = 0; i < chars.length; i++) {
numberBase10 = numberBase10.multiply(magnitude);
final char digitEncoded = chars[i];
final int indexOf = digits.indexOf(digitEncoded);
final int digitValue;
if (indexOf == -1) {
digitValue = digits.toLowerCase().indexOf(
Character.toLowerCase(digitEncoded));
} else {
digitValue = indexOf;
}
if (digitValue == -1) {
final String errorMessage = "Digit '" + digitEncoded + "'"
+ " " + "from base " + radix + " number"
+ " " + "'" + numberEncoded + "' not found in"
+ " " + "base " + radix + " digits '" + digits + "'.";
throw new IllegalArgumentException(errorMessage);
}
numberBase10 = numberBase10.add(BigInteger.valueOf(digitValue));
}
return numberBase10;
}
/**
* convert a number from a non-standard numbering format to base 10
* (BigInteger).
*
* #param numberBase10
* #return
*/
public String fromBase10(long numberBase10) {
return fromBase10(BigInteger.valueOf(numberBase10));
}
/**
* convert a number from a non-standard numbering format to base 10
* (BigInteger).
*
* #param numberBase10
* #return
*/
public String fromBase10(BigInteger numberBase10) {
final StringBuilder encodedNumber = new StringBuilder("");
final int radix = digits.length();
final BigInteger magnitude = BigInteger.valueOf(radix);
while (numberBase10.compareTo(BigInteger.ZERO) > 0) {
final BigInteger[] divideAndRemainder = numberBase10
.divideAndRemainder(magnitude);
final BigInteger quotient = divideAndRemainder[0];
final BigInteger remainder = divideAndRemainder[1];
encodedNumber.insert(0, digits.charAt(remainder.intValueExact()));
numberBase10 = quotient;
}
return encodedNumber.toString();
}
public static String getDefaultDigitsForBase(int radix) throws IllegalArgumentException {
if (radix < 2) {
final String errorMessage = "Supported bases include 2 and above."
+ " " + "Not really sure how to represent"
+ " " + "base " + radix + " numbers.";
throw new IllegalArgumentException(errorMessage);
} else if (radix <= 64) {
return ("0123456789ABCDEFGHIJKLMNOPQRSTUV" // base 32 ends at V
+ "WXYZabcdefghijklmnopqrstuvwxyz+/").substring(0, radix);
}
int charCount = 0;
final StringBuilder s = new StringBuilder();
for (int i = Character.MIN_VALUE; i < Character.MAX_VALUE; i++) {
switch (Character.getType(i)) {
case Character.CONNECTOR_PUNCTUATION:
case Character.CURRENCY_SYMBOL:
case Character.FINAL_QUOTE_PUNCTUATION:
case Character.INITIAL_QUOTE_PUNCTUATION:
case Character.LETTER_NUMBER:
case Character.LINE_SEPARATOR:
case Character.LOWERCASE_LETTER:
case Character.MATH_SYMBOL:
case Character.UPPERCASE_LETTER:
s.append((char) i);
if (++charCount >= radix) {
return s.toString();
}
break;
}
}
throw new IllegalArgumentException("Radix '" + radix + "' exceeds maximum '" + charCount + "'");
}
}

Since you mentioned int in your js codes, there are two methods in Integer class you may want to take a look:
static int parseInt(String s, int radix)
Parses the string argument as a signed integer in the radix specified by the second argument.
and
static String toString(int i, int radix)
Returns a string representation of the first argument in the radix specified by the second argument.

use this code
import java.util.Scanner; // import scanner class
public class BaseConverting {
public static void main(String[] args) {
Scanner input = new Scanner(System.in); //creating object from Scanner class
String ans;
System.out.println("Enter the decimal value need to convert !");
int decimal_value = input.nextInt(); //getting decimal value from user
System.out.println("Select base \n Binary - b ;\n Octal- o ;\n HexaDecimal -h ;");
String choice = input.next(); //getting user needs Base type
switch (choice) {
case "b":
ans = Integer.toString(decimal_value, 2);
System.out.println("Binary value of " + decimal_value + " = " + ans);
break;
case "o":
ans = Integer.toString(decimal_value, 8);
System.out.println("Octal value of " + decimal_value + " = " + ans);
break;
case "h":
ans = Integer.toString(decimal_value, 16);
System.out.println("Hexa Decimal value of " + decimal_value + " = " + ans);
break;
}
}
}

How about this ?
public static void main(String[] args) {
System.out.println(toDecimalBase("11111111", 2));
System.out.println(toDecimalBase("Ff", 16));
System.out.println(toDecimalBase("377", 8));
System.out.println(toDecimalBase("255", 10));
}
private static int toDecimalBase(String number, int base) {
int lenght = number.length();
int result = 0;
for (int i = 0; i < lenght; i++) {
// get char in a reverse order from the array
int character = number.charAt(lenght - i - 1);
// convert range [A-F] to range of [0-6]
if (character >= 'A' && character <= 'F') {
character = character - 'A' + 10;
}
else if (character >= 'a' && character <= 'f') {
character = character - 'a' + 10;
}
// Unicode to int
else {
character = Character.getNumericValue(character);
}
result += (Math.pow(base, i)) * character;
}
return result;
}

Related

Step by step long division in Java?

I'm trying to write a function that outputs a step by step long division problem given a dividend and a divisor. It's supposed to look like this:
25 r 2
5 | 125
-10
27
-25
2
I can write the bit with the vertical line easily enough, but I can't figure out how to format the top part with the remainder or the subtraction loop. Any help greatly appreciated
Here's my solution to this problem, you might want to implement some error checking to see if the dividend is larger than the divisor. The spacing might not always work, but I tried with a few numbers and it seemed fine:
int divisor = 5;
int dividend = 127;
int answer = dividend / divisor;
// Set a space constant for formatting
int spaces = (int) Math.log10(dividend) + (int) Math.log10(divisor) + 4;
// Print the initial bracket
for(int i = 0; i < spaces - (int) Math.log10(answer); i ++) {
System.out.print(" ");
}
System.out.println(Integer.toString(answer) + " r " + Integer.toString(dividend % divisor));
System.out.println(Integer.toString(divisor) + " | " + Integer.toString(dividend));
// Do a while loop to do the subtraction
int remainder = dividend;
while(remainder != dividend % divisor) {
// Find how much of the start of the remainder can be subtracted by making it into a string
String test = Integer.toString(remainder);
int sub = Integer.valueOf(test.substring(0, 1));
test = test.substring(1);
int exp = (int) Math.log10(remainder);
while(sub < divisor) {
sub = sub * 10 + Integer.valueOf(test.substring(0, 1));
test = test.substring(1);
exp--;
}
int multiple = sub - (sub % divisor);
//Print the subtraction and remainder lines
for(int i = 0; i < spaces - 1 - exp - (int) Math.log10(multiple); i++) {
System.out.print(" ");
}
System.out.println("-" + Integer.valueOf(multiple));
remainder -= multiple * Math.pow(10, exp);
for(int i = 0; i < spaces - (int) Math.log10(remainder); i++) {
System.out.print(" ");
}
System.out.println(Integer.valueOf(remainder));
}
The tricky part was working out how much of the remainder needed to be isolated (for example with 127 and 5, 1 cannot be divided by 5, so I needed to use 12) which I achieved by making the remainder into a String to interpret it one character at a time (this can be done mathematically but it hurt my head when it didn't work on my first try so I gave up).
Sample output for dividend = 12, divisor = 5:
25 r 2
5 | 127
-10
27
-25
2
Populate an object and then call to print format.
LongDivision.java
public class LongDivision {
/**
* The Number.
*/
String number;
/**
* The Divider.
*/
String divider;
/**
* The Result.
*/
String result;
/**
* The Lines.
*/
List<String> lines;
/**
* Instantiates a new Long divider.
*
* #param number the number
* #param divider the divider
* #param result the result
* #param lines the lines
*/
public LongDivision(String number, String divider, String result, List<String> lines) {
this.number = number;
this.divider = divider;
this.result = result;
this.lines = lines;
}
/**
* Gets number.
*
* #return the number
*/
public String getNumber() {
return number;
}
/**
* Sets number.
*
* #param number the number
*/
public void setNumber(String number) {
this.number = number;
}
/**
* Gets divider.
*
* #return the divider
*/
public String getDivider() {
return divider;
}
/**
* Sets divider.
*
* #param divider the divider
*/
public void setDivider(String divider) {
this.divider = divider;
}
/**
* Gets result.
*
* #return the result
*/
public String getResult() {
return result;
}
/**
* Sets result.
*
* #param result the result
*/
public void setResult(String result) {
this.result = result;
}
/**
* Gets lines.
*
* #return the lines
*/
public List<String> getLines() {
return lines;
}
/**
* Sets lines.
*
* #param lines the lines
*/
public void setLines(List<String> lines) {
this.lines = lines;
}
#Override
public String toString() {
return String.format(
"LongDivider (number=%s, divider=%s, result=%s, lines=%s)", this.number, this.divider, this.result, this.lines);
}
/**
* print format.
*
* #return the string
*/
public String printFormat() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(result+"\n");
stringBuilder.append(repeat("__", 2));
stringBuilder.append("\n");
stringBuilder.append(number + "| " + divider);
stringBuilder.append("\n");
lines.stream().forEach(s -> stringBuilder.append(s+"\n"));
return stringBuilder.toString();
}
public static String repeat(String s, int n) {
if(s == null) {
return null;
}
final StringBuilder sb = new StringBuilder(s.length() * n);
for(int i = 0; i < n; i++) {
sb.append(s);
}
return sb.toString();
}
}
Main class
public class LongDividerSolution {
/**
* The entry point of application.
*
* #param args the input arguments
*/
public static void main(String[] args) {
String number = "945";
String divider = "4";
String result = "236 (1)";
String lineSeparator = "_";
int max = Math.max(number.length(), result.length());
// TODO Implement the calculation itself.
List<String> strings = new ArrayList<>();
strings.add("8");
strings.add(LongDivision.repeat(lineSeparator, max));
strings.add("14");
strings.add(" 12");
strings.add(LongDivision.repeat(lineSeparator,max));
strings.add(" 25");
strings.add(" 24");
strings.add(LongDivision.repeat(lineSeparator,max));
strings.add("( 1 )");
LongDivision longDivision = new LongDivision(number, divider, result,strings);
System.out.println(longDivision.printFormat());
}
}
Output:
236 (1)
___
945| 4
8
_____
14
12
_____
25
24
_____
( 1 )

IMEI validation java convert string to long losing leading 0

I am trying to validate IMEI numbers using the code below, the user will enter their number on a page and this then runs isValidIMEI using a string that is converted to a long.
Now this does work for almost all IMEI's that I have come across but for a few iPhone 5's they have a leading 0, so 0133xxxxxxxxxx0 for example. When this is casted to a long the leading 0 is lost so it becomes 14 digits and fails, if I turn off the length checker this still won't work as it will be doubling the wrong digits.
Any idea how I can convert to some kind of number format but keep that leading 0?
/**
* Sum digits
*
* #param n
* #return
*/
private static int sumDig(int n)
{
int a = 0;
while (n > 0)
{
a = a + n % 10;
n = n / 10;
}
return a;
}
/**
* Is valid imei
*
* #param n
* #return
*/
public boolean isValidIMEI(long n)
{
// Converting the number into String
// for finding length
String s = Long.toString(n);
int len = s.length();
Log.v("IMEIValidation", s);
if (len != 15) {
Log.v("IMEIValidation", "Length issue");
return false;
}
int sum = 0;
for (int i = len; i >= 1; i--)
{
int d = (int)(n % 10);
// Doubling every alternate digit
if (i % 2 == 0)
d = 2 * d;
// Finding sum of the digits
sum += sumDig(d);
n = n / 10;
}
Log.v("IMEIValidation", String.valueOf(sum));
Log.v("IMEIValidation", String.valueOf(sum % 10));
return (sum % 10 == 0);
}

Converting to base 10 in java?

I have a homework assignment where I have to covert any base to base 10. I have some given numbers, which are the "basen". I have to convert those bases to base 10. The only part that I am stuck in is this part of the code:
answer = ; // Not sure what I have to put in here
I have seen some other posts about converting to base ten, but I am just not sure how to how to incorporate them into my code.
public class BaseN {
public static final int BASEN_ERRNO = -1;
public static int digit = 0;
public static void main(String[] argv) {
basen(512, 6);
basen(314, 8);
basen(49, 5);
basen(10101, 2);
}
public static void basen(int n, int b) {
int ans = basen(n, b, 1, 0);
if (ans == BASEN_ERRNO)
System.out.println(n + " is not a valid base-" + b + " number");
else
System.out.println(n + " base-" + b + " = " + ans + " base-10");
}
public static int basen(int number, int base, int placevalue, int answer) {
if (number == 0) return answer;
digit = number % 10;
if (digit >= base) return BASEN_ERRNO;
answer = 1;// not sure what to put here
number = 0;
placevalue = 0;
return basen(number, base, placevalue, answer);
}
}
You could look at a k length number of base n like this:
x(0)*n^(k-1) + x(1)*n^(k-2) + ... + x(k-1)*n^1 + x(k)*n^0
Where x(0), x(1), ..., x(k) is the digit at position k from the left.
So, if you are trying to convert, say, 101 base 2 to base 10 you would do the following :
1 * 2^2 + 0 * 2^1 + 1 * 2^0 = 4 + 0 + 1 = 5 base 10
say you want to convert the number 352 from base 6:
3 * 6^2 + 5 * 6^1 + 2 * 6^0 = 108 + 30 + 2 = 145 base 10
What you're looking for code wise is something like this :
int[] digits = {3, 5, 2};
int base = 6;
int answer = 0;
for(int i = digits.length - 1; i >= 0; i--)
{
answer += digits[i] * Math.pow(base,digits.length-i-1);
}
return answer;
which will return 145.
Hopefully even though my implementation is iterative you should be able to apply it to your recursive implementation as well.
You can implement the following algorithm. Lets say you are given String number which represents the number you want to convert to decimal form and int base which represents the base of given number. You can implement function int convertToNumber(char c); which accepts one character representing one digit from your number and will map characters to numbers like this:
0 -> 0,
1 -> 1,
... ,
A-> 10,
B -> 11,
... ,
F -> 15,
...
Then you just iterate through your given string and multiply this functions output with base to the power of iteration. For example, convert number A32(hexadecimal):
A32 = convertToNumber(A) * b ^ 2 + convertToNumber(3) * b ^ 1 + convertToNumber(2) * b ^ 0 = 10 * 16 ^ 2 + 3 * 16 ^ 1 + 2 * 16 ^ 0 = 10 * 16 * 16 + 3 * 16 + 2 = 2610 (decimal).
public class BaseConvert {
public static int convertDigitToNumber(char c) throws Exception {
if(c >= '0' && c <= '9') return c - '0';
if(c >= 'A' && c <= 'Z') return c - 55;
if(c >= 'a' && c <= 'z') return c - 97;
throw new Exception("Invalid digit!");
}
public static int convertToBase(String number, int base) throws Exception {
int result = 0;
for(int i = 0; i < number.length(); i++){
result += convertDigitToNumber(number.charAt(i)) * (int)Math.pow(base, number.length() - i - 1);
}
return result;
}
public static void main(String[] args) {
try{
System.out.println(convertToBase("732", 8));
System.out.println(convertToBase("A32", 16));
System.out.println(convertToBase("1010", 2));
}catch (Exception e) {
System.out.print(e);
}
}
}

Why won't this quadratic equation return negative numbers?

This quadratic equation will not return negative numbers in the string that I've determined it to return.
Here's the equation:
public class QuadraticEquation {
String final0;
public String calculate(int a, int b, int c) {
double done1 = ((-1 * b) + Math.sqrt((b * b) - (4 * a * c))) / (2 * a);
double done2 = ((-1 * b) - Math.sqrt((b * b) - (4 * a * c))) / (2 * a);
final0 = "x = " + (done1) + " or x = " + (done2);
return final0;
}
}
imagine an equation with a, b, and c values like -3, 13, and -4. The returning value of this would be -0.3(repeating) and -4. But this equation only returns positives, so in this case it would return 0.3(repeating) and 4. Why is this, and what can I do to fix it?
Note: I do believe that this is a Java error and not a math error. If it is a math error, let me know in the comments and I will promptly put it in the proper forums. Thanks.
public static void main(String[] args) {
String final0 = calculate(-3, 13, -4);
System.out.println(final0);
}
public static String calculate(int a, int b, int c) {
String final0 ;
int i = -1 * b; // -1 * 13 = -13
System.out.println(i);
int j = 4 * a * c; // 4 * -3 * -4 = 4 * 12 = 48
System.out.println(j);
double sqrt = Math.sqrt((b * b) - j); // sqrt ((13 * 13) - 48) = sqrt(169 - 48) = sqrt(121) = 11
System.out.println(sqrt);
double d = i + sqrt; // -13 + 11 = -2
System.out.println(d);
int k = 2 * a; // 2* -3 = -6
System.out.println(k);
double done1 = d / k; // -2 / -6 = 1/3 = 0.3333333333
System.out.println(done1);
double done2 = (i - sqrt) / k;
final0 = "x = " + (done1) + " or x = " + (done2);
return final0;
}
If you decompose your method to more local variables, you will see that math in java works correctly.
I would have thought
-3*x^2 + 13 *x + -4 = -3 * (x - 0.33333) * (x - 4) = 0
so two positive answers is correct.
Try instead
1 * x^2 + 0 * x -1 = (x - 1) * (x + 1) = 0
i.e. x = -1 or +1
Here is how I would write it.
public static String calculate(int a, int b, int c) {
double sqrt = Math.sqrt((b * b) - (4 * a * c));
double done1 = (-b + sqrt) / (2 * a);
double done2 = (-b - sqrt) / (2 * a);
return "x = " + (done1) + " or x = " + (done2);
}
The code is working correctly with your input. If you changed b to be -13 for example, you would get
x = -4.0 or x = -0.3333333333333333
Math.sqrt will always return a positive number ignoring complex numbers. But that is somewhat besides the point.

How to go about formatting 1200 to 1.2k in java

I'd like to format following numbers into the numbers next to them with java:
1000 to 1k
5821 to 5.8k
10500 to 10k
101800 to 101k
2000000 to 2m
7800000 to 7.8m
92150000 to 92m
123200000 to 123m
The number on the right will be long or integer the number on the left will be string.
How should I approach this. I already did little algorithm for this but I thought there might be already something invented out there that does nicer job at it and doesn't require additional testing if I start dealing with billions and trillions :)
Additional Requirements:
The format should have maximum of 4 characters
The above means 1.1k is OK 11.2k is not. Same for 7.8m is OK 19.1m is not. Only one digit before decimal point is allowed to have decimal point. Two digits before decimal point means not digits after decimal point.
No rounding is necessary. (Numbers being displayed with k and m appended are more of analog gauge indicating approximation not precise article of logic. Hence rounding is irrelevant mainly due to nature of variable than can increase or decrees several digits even while you are looking at the cached result.)
Here is a solution that works for any long value and that I find quite readable (the core logic is done in the bottom three lines of the format method).
It leverages TreeMap to find the appropriate suffix. It is surprisingly more efficient than a previous solution I wrote that was using arrays and was more difficult to read.
private static final NavigableMap<Long, String> suffixes = new TreeMap<> ();
static {
suffixes.put(1_000L, "k");
suffixes.put(1_000_000L, "M");
suffixes.put(1_000_000_000L, "G");
suffixes.put(1_000_000_000_000L, "T");
suffixes.put(1_000_000_000_000_000L, "P");
suffixes.put(1_000_000_000_000_000_000L, "E");
}
public static String format(long value) {
//Long.MIN_VALUE == -Long.MIN_VALUE so we need an adjustment here
if (value == Long.MIN_VALUE) return format(Long.MIN_VALUE + 1);
if (value < 0) return "-" + format(-value);
if (value < 1000) return Long.toString(value); //deal with easy case
Entry<Long, String> e = suffixes.floorEntry(value);
Long divideBy = e.getKey();
String suffix = e.getValue();
long truncated = value / (divideBy / 10); //the number part of the output times 10
boolean hasDecimal = truncated < 100 && (truncated / 10d) != (truncated / 10);
return hasDecimal ? (truncated / 10d) + suffix : (truncated / 10) + suffix;
}
Test code
public static void main(String args[]) {
long[] numbers = {0, 5, 999, 1_000, -5_821, 10_500, -101_800, 2_000_000, -7_800_000, 92_150_000, 123_200_000, 9_999_999, 999_999_999_999_999_999L, 1_230_000_000_000_000L, Long.MIN_VALUE, Long.MAX_VALUE};
String[] expected = {"0", "5", "999", "1k", "-5.8k", "10k", "-101k", "2M", "-7.8M", "92M", "123M", "9.9M", "999P", "1.2P", "-9.2E", "9.2E"};
for (int i = 0; i < numbers.length; i++) {
long n = numbers[i];
String formatted = format(n);
System.out.println(n + " => " + formatted);
if (!formatted.equals(expected[i])) throw new AssertionError("Expected: " + expected[i] + " but found: " + formatted);
}
}
I know, this looks more like a C program, but it's super lightweight!
public static void main(String args[]) {
long[] numbers = new long[]{1000, 5821, 10500, 101800, 2000000, 7800000, 92150000, 123200000, 9999999};
for(long n : numbers) {
System.out.println(n + " => " + coolFormat(n, 0));
}
}
private static char[] c = new char[]{'k', 'm', 'b', 't'};
/**
* Recursive implementation, invokes itself for each factor of a thousand, increasing the class on each invokation.
* #param n the number to format
* #param iteration in fact this is the class from the array c
* #return a String representing the number n formatted in a cool looking way.
*/
private static String coolFormat(double n, int iteration) {
double d = ((long) n / 100) / 10.0;
boolean isRound = (d * 10) %10 == 0;//true if the decimal part is equal to 0 (then it's trimmed anyway)
return (d < 1000? //this determines the class, i.e. 'k', 'm' etc
((d > 99.9 || isRound || (!isRound && d > 9.99)? //this decides whether to trim the decimals
(int) d * 10 / 10 : d + "" // (int) d * 10 / 10 drops the decimal
) + "" + c[iteration])
: coolFormat(d, iteration+1));
}
It outputs:
1000 => 1k
5821 => 5.8k
10500 => 10k
101800 => 101k
2000000 => 2m
7800000 => 7.8m
92150000 => 92m
123200000 => 123m
9999999 => 9.9m
Here a solution that makes use of DecimalFormat's engineering notation:
public static void main(String args[]) {
long[] numbers = new long[]{7, 12, 856, 1000, 5821, 10500, 101800, 2000000, 7800000, 92150000, 123200000, 9999999};
for(long number : numbers) {
System.out.println(number + " = " + format(number));
}
}
private static String[] suffix = new String[]{"","k", "m", "b", "t"};
private static int MAX_LENGTH = 4;
private static String format(double number) {
String r = new DecimalFormat("##0E0").format(number);
r = r.replaceAll("E[0-9]", suffix[Character.getNumericValue(r.charAt(r.length() - 1)) / 3]);
while(r.length() > MAX_LENGTH || r.matches("[0-9]+\\.[a-z]")){
r = r.substring(0, r.length()-2) + r.substring(r.length() - 1);
}
return r;
}
Output:
7 = 7
12 = 12
856 = 856
1000 = 1k
5821 = 5.8k
10500 = 10k
101800 = 102k
2000000 = 2m
7800000 = 7.8m
92150000 = 92m
123200000 = 123m
9999999 = 10m
Need some improvement, but: StrictMath to the rescue!
You can put the suffix in a String or array and fetch'em based on power, or something like that.
The division can also be managed around the power, i think almost everything is about the power value.
Hope it helps!
public static String formatValue(double value) {
int power;
String suffix = " kmbt";
String formattedNumber = "";
NumberFormat formatter = new DecimalFormat("#,###.#");
power = (int)StrictMath.log10(value);
value = value/(Math.pow(10,(power/3)*3));
formattedNumber=formatter.format(value);
formattedNumber = formattedNumber + suffix.charAt(power/3);
return formattedNumber.length()>4 ? formattedNumber.replaceAll("\\.[0-9]+", "") : formattedNumber;
}
outputs:
999
1.2k
98k
911k
1.1m
11b
712b
34t
With Java-12 +, you can use NumberFormat.getCompactNumberInstance to format the numbers. You can create a NumberFormat first as
NumberFormat fmt = NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT);
and then use it to format:
fmt.format(1000)
$5 ==> "1K"
fmt.format(10000000)
$9 ==> "10M"
fmt.format(1000000000)
$11 ==> "1B"
Problems with Current Answers
Many of the current solutions are using these prefixes k=103, m=106, b=109, t=1012. However, according to various sources, the correct prefixes are k=103, M=106, G=109, T=1012
Lack of support for negative numbers (or at least a lack of tests demonstrating that negative numbers are supported)
Lack of support for the inverse operation, e.g. converting 1.1k to 1100 (though this is outside the scope of the original question)
Java Solution
This solution (an extension of this answer) addresses the above issues.
import org.apache.commons.lang.math.NumberUtils;
import java.text.DecimalFormat;
import java.text.FieldPosition;
import java.text.Format;
import java.text.ParsePosition;
import java.util.regex.Pattern;
/**
* Converts a number to a string in metric prefix format.
* For example, 7800000 will be formatted as '7.8M'. Numbers under 1000 will be unchanged. Refer to the tests for further examples.
*/
class RoundedMetricPrefixFormat extends Format {
private static final String[] METRIC_PREFIXES = new String[]{"", "k", "M", "G", "T"};
/**
* The maximum number of characters in the output, excluding the negative sign
*/
private static final Integer MAX_LENGTH = 4;
private static final Pattern TRAILING_DECIMAL_POINT = Pattern.compile("[0-9]+\\.[kMGT]");
private static final Pattern METRIC_PREFIXED_NUMBER = Pattern.compile("\\-?[0-9]+(\\.[0-9])?[kMGT]");
#Override
public StringBuffer format(Object obj, StringBuffer output, FieldPosition pos) {
Double number = Double.valueOf(obj.toString());
// if the number is negative, convert it to a positive number and add the minus sign to the output at the end
boolean isNegative = number < 0;
number = Math.abs(number);
String result = new DecimalFormat("##0E0").format(number);
Integer index = Character.getNumericValue(result.charAt(result.length() - 1)) / 3;
result = result.replaceAll("E[0-9]", METRIC_PREFIXES[index]);
while (result.length() > MAX_LENGTH || TRAILING_DECIMAL_POINT.matcher(result).matches()) {
int length = result.length();
result = result.substring(0, length - 2) + result.substring(length - 1);
}
return output.append(isNegative ? "-" + result : result);
}
/**
* Convert a String produced by <tt>format()</tt> back to a number. This will generally not restore
* the original number because <tt>format()</tt> is a lossy operation, e.g.
*
* <pre>
* {#code
* def formatter = new RoundedMetricPrefixFormat()
* Long number = 5821L
* String formattedNumber = formatter.format(number)
* assert formattedNumber == '5.8k'
*
* Long parsedNumber = formatter.parseObject(formattedNumber)
* assert parsedNumber == 5800
* assert parsedNumber != number
* }
* </pre>
*
* #param source a number that may have a metric prefix
* #param pos if parsing succeeds, this should be updated to the index after the last parsed character
* #return a Number if the the string is a number without a metric prefix, or a Long if it has a metric prefix
*/
#Override
public Object parseObject(String source, ParsePosition pos) {
if (NumberUtils.isNumber(source)) {
// if the value is a number (without a prefix) don't return it as a Long or we'll lose any decimals
pos.setIndex(source.length());
return toNumber(source);
} else if (METRIC_PREFIXED_NUMBER.matcher(source).matches()) {
boolean isNegative = source.charAt(0) == '-';
int length = source.length();
String number = isNegative ? source.substring(1, length - 1) : source.substring(0, length - 1);
String metricPrefix = Character.toString(source.charAt(length - 1));
Number absoluteNumber = toNumber(number);
int index = 0;
for (; index < METRIC_PREFIXES.length; index++) {
if (METRIC_PREFIXES[index].equals(metricPrefix)) {
break;
}
}
Integer exponent = 3 * index;
Double factor = Math.pow(10, exponent);
factor *= isNegative ? -1 : 1;
pos.setIndex(source.length());
Float result = absoluteNumber.floatValue() * factor.longValue();
return result.longValue();
}
return null;
}
private static Number toNumber(String number) {
return NumberUtils.createNumber(number);
}
}
Groovy Solution
The solution was originally written in Groovy as shown below.
import org.apache.commons.lang.math.NumberUtils
import java.text.DecimalFormat
import java.text.FieldPosition
import java.text.Format
import java.text.ParsePosition
import java.util.regex.Pattern
/**
* Converts a number to a string in metric prefix format.
* For example, 7800000 will be formatted as '7.8M'. Numbers under 1000 will be unchanged. Refer to the tests for further examples.
*/
class RoundedMetricPrefixFormat extends Format {
private static final METRIC_PREFIXES = ["", "k", "M", "G", "T"]
/**
* The maximum number of characters in the output, excluding the negative sign
*/
private static final Integer MAX_LENGTH = 4
private static final Pattern TRAILING_DECIMAL_POINT = ~/[0-9]+\.[kMGT]/
private static final Pattern METRIC_PREFIXED_NUMBER = ~/\-?[0-9]+(\.[0-9])?[kMGT]/
#Override
StringBuffer format(Object obj, StringBuffer output, FieldPosition pos) {
Double number = obj as Double
// if the number is negative, convert it to a positive number and add the minus sign to the output at the end
boolean isNegative = number < 0
number = Math.abs(number)
String result = new DecimalFormat("##0E0").format(number)
Integer index = Character.getNumericValue(result.charAt(result.size() - 1)) / 3
result = result.replaceAll("E[0-9]", METRIC_PREFIXES[index])
while (result.size() > MAX_LENGTH || TRAILING_DECIMAL_POINT.matcher(result).matches()) {
int length = result.size()
result = result.substring(0, length - 2) + result.substring(length - 1)
}
output << (isNegative ? "-$result" : result)
}
/**
* Convert a String produced by <tt>format()</tt> back to a number. This will generally not restore
* the original number because <tt>format()</tt> is a lossy operation, e.g.
*
* <pre>
* {#code
* def formatter = new RoundedMetricPrefixFormat()
* Long number = 5821L
* String formattedNumber = formatter.format(number)
* assert formattedNumber == '5.8k'
*
* Long parsedNumber = formatter.parseObject(formattedNumber)
* assert parsedNumber == 5800
* assert parsedNumber != number
* }
* </pre>
*
* #param source a number that may have a metric prefix
* #param pos if parsing succeeds, this should be updated to the index after the last parsed character
* #return a Number if the the string is a number without a metric prefix, or a Long if it has a metric prefix
*/
#Override
Object parseObject(String source, ParsePosition pos) {
if (source.isNumber()) {
// if the value is a number (without a prefix) don't return it as a Long or we'll lose any decimals
pos.index = source.size()
toNumber(source)
} else if (METRIC_PREFIXED_NUMBER.matcher(source).matches()) {
boolean isNegative = source[0] == '-'
String number = isNegative ? source[1..-2] : source[0..-2]
String metricPrefix = source[-1]
Number absoluteNumber = toNumber(number)
Integer exponent = 3 * METRIC_PREFIXES.indexOf(metricPrefix)
Long factor = 10 ** exponent
factor *= isNegative ? -1 : 1
pos.index = source.size()
(absoluteNumber * factor) as Long
}
}
private static Number toNumber(String number) {
NumberUtils.createNumber(number)
}
}
Tests (Groovy)
The tests are written in Groovy but can be used to verify either either the Java or Groovy class (because they both have the same name and API).
import java.text.Format
import java.text.ParseException
class RoundedMetricPrefixFormatTests extends GroovyTestCase {
private Format roundedMetricPrefixFormat = new RoundedMetricPrefixFormat()
void testNumberFormatting() {
[
7L : '7',
12L : '12',
856L : '856',
1000L : '1k',
(-1000L) : '-1k',
5821L : '5.8k',
10500L : '10k',
101800L : '102k',
2000000L : '2M',
7800000L : '7.8M',
(-7800000L): '-7.8M',
92150000L : '92M',
123200000L : '123M',
9999999L : '10M',
(-9999999L): '-10M'
].each { Long rawValue, String expectedRoundValue ->
assertEquals expectedRoundValue, roundedMetricPrefixFormat.format(rawValue)
}
}
void testStringParsingSuccess() {
[
'7' : 7,
'8.2' : 8.2F,
'856' : 856,
'-856' : -856,
'1k' : 1000,
'5.8k' : 5800,
'-5.8k': -5800,
'10k' : 10000,
'102k' : 102000,
'2M' : 2000000,
'7.8M' : 7800000L,
'92M' : 92000000L,
'-92M' : -92000000L,
'123M' : 123000000L,
'10M' : 10000000L
].each { String metricPrefixNumber, Number expectedValue ->
def parsedNumber = roundedMetricPrefixFormat.parseObject(metricPrefixNumber)
assertEquals expectedValue, parsedNumber
}
}
void testStringParsingFail() {
shouldFail(ParseException) {
roundedMetricPrefixFormat.parseObject('notNumber')
}
}
}
My function for convert big number to small number (with 2 digits). You can change the number of digits by change #.## in DecimalFormat
public String formatValue(float value) {
String arr[] = {"", "K", "M", "B", "T", "P", "E"};
int index = 0;
while ((value / 1000) >= 1) {
value = value / 1000;
index++;
}
DecimalFormat decimalFormat = new DecimalFormat("#.##");
return String.format("%s %s", decimalFormat.format(value), arr[index]);
}
Testing
System.out.println(formatValue(100)); // 100
System.out.println(formatValue(1000)); // 1 K
System.out.println(formatValue(10345)); // 10.35 K
System.out.println(formatValue(10012)); // 10.01 K
System.out.println(formatValue(123456)); // 123.46 K
System.out.println(formatValue(4384324)); // 4.38 M
System.out.println(formatValue(10000000)); // 10 M
System.out.println(formatValue(Long.MAX_VALUE)); // 9.22 E
Hope it help
The ICU lib has a rule based formatter for numbers, which can be used for number spellout etc. I think using ICU would give you a readable and maintanable solution.
[Usage]
The right class is RuleBasedNumberFormat. The format itself can be stored as separate file (or as String constant, IIRC).
Example from http://userguide.icu-project.org/formatparse/numbers
double num = 2718.28;
NumberFormat formatter =
new RuleBasedNumberFormat(RuleBasedNumberFormat.SPELLOUT);
String result = formatter.format(num);
System.out.println(result);
The same page shows Roman numerals, so I guess your case should be possible, too.
Here's a short implementation without recursion and just a very small loop. Doesn't work with negative numbers but supports all positive longs up to Long.MAX_VALUE:
private static final char[] SUFFIXES = {'k', 'm', 'g', 't', 'p', 'e' };
public static String format(long number) {
if(number < 1000) {
// No need to format this
return String.valueOf(number);
}
// Convert to a string
final String string = String.valueOf(number);
// The suffix we're using, 1-based
final int magnitude = (string.length() - 1) / 3;
// The number of digits we must show before the prefix
final int digits = (string.length() - 1) % 3 + 1;
// Build the string
char[] value = new char[4];
for(int i = 0; i < digits; i++) {
value[i] = string.charAt(i);
}
int valueLength = digits;
// Can and should we add a decimal point and an additional number?
if(digits == 1 && string.charAt(1) != '0') {
value[valueLength++] = '.';
value[valueLength++] = string.charAt(1);
}
value[valueLength++] = SUFFIXES[magnitude - 1];
return new String(value, 0, valueLength);
}
Outputs:
1k
5.8k
10k
101k
2m
7.8m
92m
123m
9.2e (this is Long.MAX_VALUE)
I also did some really simple benchmarking (formatting 10 million random longs) and it's considerably faster than Elijah's implementation and slightly faster than assylias' implementation.
Mine: 1137.028 ms
Elijah's: 2664.396 ms
assylias': 1373.473 ms
Important: Answers casting to double will fail for numbers like 99999999999999999L and return 100P instead of 99P because double uses the IEEE standard:
If a decimal string with at most 15 significant digits is converted to IEEE 754 double precision representation and then converted back to a string with the same number of significant digits, then the final string should match the original. [long has up to 19 significant digits.]
System.out.println((long)(double)99999999999999992L); // 100000000000000000
System.out.println((long)(double)99999999999999991L); // 99999999999999984
// it is even worse for the logarithm:
System.out.println(Math.log10(99999999999999600L)); // 17.0
System.out.println(Math.log10(99999999999999500L)); // 16.999999999999996
This solution cuts off unwanted digits and works for all long values. Simple but performant implementation (comparison below). -120k can't be expressed with 4 characters, even -0.1M is too long, that's why for negative numbers 5 characters have to be okay:
private static final char[] magnitudes = {'k', 'M', 'G', 'T', 'P', 'E'}; // enough for long
public static final String convert(long number) {
String ret;
if (number >= 0) {
ret = "";
} else if (number <= -9200000000000000000L) {
return "-9.2E";
} else {
ret = "-";
number = -number;
}
if (number < 1000)
return ret + number;
for (int i = 0; ; i++) {
if (number < 10000 && number % 1000 >= 100)
return ret + (number / 1000) + '.' + ((number % 1000) / 100) + magnitudes[i];
number /= 1000;
if (number < 1000)
return ret + number + magnitudes[i];
}
}
The test in the else if at the beginning is necessairy because the min is -(2^63) and the max is (2^63)-1 and therefore the assignment number = -number would fail if number == Long.MIN_VALUE. If we have to do a check, then we can as well include as many numbers as possible instead of just checking for number == Long.MIN_VALUE.
The comparison of this implementation with the one who got the most upvotes (said to be the fastest currently) showed that it is more than 5 times faster (it depends on the test settings, but with more numbers the gain gets bigger and this implementation has to do more checks because it handles all cases, so if the other one would be fixed the difference would become even bigger). It is that fast because there are no floating point operations, no logarithm, no power, no recursion, no regex, no sophisticated formatters and minimization of the amount of objects created.
Here is the test program:
public class Test {
public static void main(String[] args) {
long[] numbers = new long[20000000];
for (int i = 0; i < numbers.length; i++)
numbers[i] = Math.random() < 0.5 ? (long) (Math.random() * Long.MAX_VALUE) : (long) (Math.random() * Long.MIN_VALUE);
System.out.println(convert1(numbers) + " vs. " + convert2(numbers));
}
private static long convert1(long[] numbers) {
long l = System.currentTimeMillis();
for (int i = 0; i < numbers.length; i++)
Converter1.convert(numbers[i]);
return System.currentTimeMillis() - l;
}
private static long convert2(long[] numbers) {
long l = System.currentTimeMillis();
for (int i = 0; i < numbers.length; i++)
Converter2.coolFormat(numbers[i], 0);
return System.currentTimeMillis() - l;
}
}
Possible output: 2309 vs. 11591 (about the same when only using positive numbers and much more extreme when reversing the order of execution, maybe it has something to do with garbage collection)
For anyone that wants to round. This is a great, easy to read solution, that takes advantage of the Java.Lang.Math library
public static String formatNumberExample(Number number) {
char[] suffix = {' ', 'k', 'M', 'B', 'T', 'P', 'E'};
long numValue = number.longValue();
int value = (int) Math.floor(Math.log10(numValue));
int base = value / 3;
if (value >= 3 && base < suffix.length) {
return new DecimalFormat("~#0.0").format(numValue / Math.pow(10, base * 3)) + suffix[base];
} else {
return new DecimalFormat("#,##0").format(numValue);
}
}
I don't know if it's the best approach but, this is what i did.
7=>7
12=>12
856=>856
1000=>1.0k
5821=>5.82k
10500=>10.5k
101800=>101.8k
2000000=>2.0m
7800000=>7.8m
92150000=>92.15m
123200000=>123.2m
9999999=>10.0m
--- Code---
public String Format(Integer number){
String[] suffix = new String[]{"k","m","b","t"};
int size = (number.intValue() != 0) ? (int) Math.log10(number) : 0;
if (size >= 3){
while (size % 3 != 0) {
size = size - 1;
}
}
double notation = Math.pow(10, size);
String result = (size >= 3) ? + (Math.round((number / notation) * 100) / 100.0d)+suffix[(size/3) - 1] : + number + "";
return result
}
The following code shows how you can do this with easy expansion in mind.
The "magic" lies mostly in the makeDecimal function which, for the correct values passed in, guarantees you will never have more than four characters in the output.
It first extracts the whole and tenths portions for a given divisor so, for example, 12,345,678 with a divisor of 1,000,000 will give a whole value of 12 and a tenths value of 3.
From that, it can decide whether it outputs just the whole part or both the whole and tenths part, using the rules:
If tenths part is zero, just output whole part and suffix.
If whole part is greater than nine, just output whole part and suffix.
Otherwise, output whole part, tenths part and suffix.
The code for that follows:
static private String makeDecimal(long val, long div, String sfx) {
val = val / (div / 10);
long whole = val / 10;
long tenths = val % 10;
if ((tenths == 0) || (whole >= 10))
return String.format("%d%s", whole, sfx);
return String.format("%d.%d%s", whole, tenths, sfx);
}
Then, it's a simple matter of calling that helper function with the correct values, including some constants to make life easier for the developer:
static final long THOU = 1000L;
static final long MILL = 1000000L;
static final long BILL = 1000000000L;
static final long TRIL = 1000000000000L;
static final long QUAD = 1000000000000000L;
static final long QUIN = 1000000000000000000L;
static private String Xlat(long val) {
if (val < THOU) return Long.toString(val);
if (val < MILL) return makeDecimal(val, THOU, "k");
if (val < BILL) return makeDecimal(val, MILL, "m");
if (val < TRIL) return makeDecimal(val, BILL, "b");
if (val < QUAD) return makeDecimal(val, TRIL, "t");
if (val < QUIN) return makeDecimal(val, QUAD, "q");
return makeDecimal(val, QUIN, "u");
}
The fact that the makeDecimal function does the grunt work means that expanding beyond 999,999,999 is just a matter of adding an extra line to Xlat, so easy that I've done it for you.
The final return in Xlat doesn't need a conditional since the largest value you can hold in a 64-bit signed long is only about 9.2 quintillion.
But if, by some bizarre requirement, Oracle decides to add a 128-bit longer type or a 1024-bit damn_long type, you'll be ready for it :-)
And, finally, a little test harness you can use for validating the functionality.
public static void main(String[] args) {
long vals[] = {
999L, 1000L, 5821L, 10500L, 101800L, 2000000L,
7800000L, 92150000L, 123200000L, 999999999L,
1000000000L, 1100000000L, 999999999999L,
1000000000000L, 999999999999999L,
1000000000000000L, 9223372036854775807L
};
for (long val: vals)
System.out.println ("" + val + " -> " + Xlat(val));
}
}
You can see from the output that it gives you what you need:
999 -> 999
1000 -> 1k
5821 -> 5.8k
10500 -> 10k
101800 -> 101k
2000000 -> 2m
7800000 -> 7.8m
92150000 -> 92m
123200000 -> 123m
999999999 -> 999m
1000000000 -> 1b
1100000000 -> 1.1b
999999999999 -> 999b
1000000000000 -> 1t
999999999999999 -> 999t
1000000000000000 -> 1q
9223372036854775807 -> 9.2u
And, as an aside, be aware that passing in a negative number to this function will result in a string too long for your requirements, since it follows the < THOU path). I figured that was okay since you only mention non-negative values in the question.
this is my code. clean and simple .
public static String getRoughNumber(long value) {
if (value <= 999) {
return String.valueOf(value);
}
final String[] units = new String[]{"", "K", "M", "B", "P"};
int digitGroups = (int) (Math.log10(value) / Math.log10(1000));
return new DecimalFormat("#,##0.#").format(value / Math.pow(1000, digitGroups)) + "" + units[digitGroups];
}
My Java is rusty, but here's how I'd implement it in C#:
private string FormatNumber(double value)
{
string[] suffixes = new string[] {" k", " m", " b", " t", " q"};
for (int j = suffixes.Length; j > 0; j--)
{
double unit = Math.Pow(1000, j);
if (value >= unit)
return (value / unit).ToString("#,##0.0") + suffixes[--j];
}
return value.ToString("#,##0");
}
It'd be easy to adjust this to use CS kilos (1,024) rather than metric kilos, or to add more units. It formats 1,000 as "1.0 k" rather than "1 k", but I trust that's immaterial.
To meet the more specific requirement "no more than four characters", remove the spaces before the suffixes and adjust the middle block like this:
if (value >= unit)
{
value /= unit;
return (value).ToString(value >= unit * 9.95 ? "#,##0" : "#,##0.0") + suffixes[--j];
}
My favorite. You could use "k" and so on as indicator for decimal too, as common in the electronic domain. This will give you an extra digit without additional space
Second column tries to use as much digits as possible
1000 => 1.0k | 1000
5821 => 5.8k | 5821
10500 => 10k | 10k5
101800 => 101k | 101k
2000000 => 2.0m | 2m
7800000 => 7.8m | 7m8
92150000 => 92m | 92m1
123200000 => 123m | 123m
9999999 => 9.9m | 9m99
This is the code
public class HTTest {
private static String[] unit = {"u", "k", "m", "g", "t"};
/**
* #param args
*/
public static void main(String[] args) {
int[] numbers = new int[]{1000, 5821, 10500, 101800, 2000000, 7800000, 92150000, 123200000, 9999999};
for(int n : numbers) {
System.out.println(n + " => " + myFormat(n) + " | " + myFormat2(n));
}
}
private static String myFormat(int pN) {
String str = Integer.toString(pN);
int len = str.length ()-1;
if (len <= 3) return str;
int level = len / 3;
int mode = len % 3;
switch (mode) {
case 0: return str.substring(0, 1) + "." + str.substring(1, 2) + unit[level];
case 1: return str.substring(0, 2) + unit[level];
case 2: return str.substring(0, 3) + unit[level];
}
return "how that?";
}
private static String trim1 (String pVal) {
if (pVal.equals("0")) return "";
return pVal;
}
private static String trim2 (String pVal) {
if (pVal.equals("00")) return "";
return pVal.substring(0, 1) + trim1(pVal.substring(1,2));
}
private static String myFormat2(int pN) {
String str = Integer.toString(pN);
int len = str.length () - 1;
if (len <= 3) return str;
int level = len / 3;
int mode = len % 3;
switch (mode) {
case 0: return str.substring(0, 1) + unit[level] + trim2(str.substring(1, 3));
case 2: return str.substring(0, 3) + unit[level];
case 1: return str.substring(0, 2) + unit[level] + trim1(str.substring(2, 3));
}
return "how that?";
}
}
Staying true to my comment that I'd value readability above performance, here's a version where it should be clear what's happening (assuming you've used BigDecimals before) without excessive commenting (I believe in self-documenting code), without worrying about performance (since I can't picture a scenario where you'd want to do this so many millions of times that performance even becomes a consideration).
This version:
uses BigDecimals for precision and to avoid rounding issues
works for rounding down as requested by the OP
works for other rounding modes, e.g. HALF_UP as in the tests
allows you to adjust the precision (change REQUIRED_PRECISION)
uses an enum to define the thresholds, i.e. could easily be adjusted to use KB/MB/GB/TB instead of k/m/b/t, etc., and could of course be extended beyond TRILLION if required
comes with thorough unit tests, since the test cases in the question weren't testing the borders
should work for zero and negative numbers
Threshold.java:
import java.math.BigDecimal;
public enum Threshold {
TRILLION("1000000000000", 12, 't', null),
BILLION("1000000000", 9, 'b', TRILLION),
MILLION("1000000", 6, 'm', BILLION),
THOUSAND("1000", 3, 'k', MILLION),
ZERO("0", 0, null, THOUSAND);
private BigDecimal value;
private int zeroes;
protected Character suffix;
private Threshold higherThreshold;
private Threshold(String aValueString, int aNumberOfZeroes, Character aSuffix,
Threshold aThreshold) {
value = new BigDecimal(aValueString);
zeroes = aNumberOfZeroes;
suffix = aSuffix;
higherThreshold = aThreshold;
}
public static Threshold thresholdFor(long aValue) {
return thresholdFor(new BigDecimal(aValue));
}
public static Threshold thresholdFor(BigDecimal aValue) {
for (Threshold eachThreshold : Threshold.values()) {
if (eachThreshold.value.compareTo(aValue) <= 0) {
return eachThreshold;
}
}
return TRILLION; // shouldn't be needed, but you might have to extend the enum
}
public int getNumberOfZeroes() {
return zeroes;
}
public String getSuffix() {
return suffix == null ? "" : "" + suffix;
}
public Threshold getHigherThreshold() {
return higherThreshold;
}
}
NumberShortener.java:
import java.math.BigDecimal;
import java.math.RoundingMode;
public class NumberShortener {
public static final int REQUIRED_PRECISION = 2;
public static BigDecimal toPrecisionWithoutLoss(BigDecimal aBigDecimal,
int aPrecision, RoundingMode aMode) {
int previousScale = aBigDecimal.scale();
int previousPrecision = aBigDecimal.precision();
int newPrecision = Math.max(previousPrecision - previousScale, aPrecision);
return aBigDecimal.setScale(previousScale + newPrecision - previousPrecision,
aMode);
}
private static BigDecimal scaledNumber(BigDecimal aNumber, RoundingMode aMode) {
Threshold threshold = Threshold.thresholdFor(aNumber);
BigDecimal adjustedNumber = aNumber.movePointLeft(threshold.getNumberOfZeroes());
BigDecimal scaledNumber = toPrecisionWithoutLoss(adjustedNumber, REQUIRED_PRECISION,
aMode).stripTrailingZeros();
// System.out.println("Number: <" + aNumber + ">, adjusted: <" + adjustedNumber
// + ">, rounded: <" + scaledNumber + ">");
return scaledNumber;
}
public static String shortenedNumber(long aNumber, RoundingMode aMode) {
boolean isNegative = aNumber < 0;
BigDecimal numberAsBigDecimal = new BigDecimal(isNegative ? -aNumber : aNumber);
Threshold threshold = Threshold.thresholdFor(numberAsBigDecimal);
BigDecimal scaledNumber = aNumber == 0 ? numberAsBigDecimal : scaledNumber(
numberAsBigDecimal, aMode);
if (scaledNumber.compareTo(new BigDecimal("1000")) >= 0) {
scaledNumber = scaledNumber(scaledNumber, aMode);
threshold = threshold.getHigherThreshold();
}
String sign = isNegative ? "-" : "";
String printNumber = sign + scaledNumber.stripTrailingZeros().toPlainString()
+ threshold.getSuffix();
// System.out.println("Number: <" + sign + numberAsBigDecimal + ">, rounded: <"
// + sign + scaledNumber + ">, print: <" + printNumber + ">");
return printNumber;
}
}
(Uncomment the println statements or change to use your favourite logger to see what it's doing.)
And finally, the tests in NumberShortenerTest (plain JUnit 4):
import static org.junit.Assert.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import org.junit.Test;
public class NumberShortenerTest {
private static final long[] NUMBERS_FROM_OP = new long[] { 1000, 5821, 10500, 101800, 2000000, 7800000, 92150000, 123200000 };
private static final String[] EXPECTED_FROM_OP = new String[] { "1k", "5.8k", "10k", "101k", "2m", "7.8m", "92m", "123m" };
private static final String[] EXPECTED_FROM_OP_HALF_UP = new String[] { "1k", "5.8k", "11k", "102k", "2m", "7.8m", "92m", "123m" };
private static final long[] NUMBERS_TO_TEST = new long[] { 1, 500, 999, 1000, 1001, 1009, 1049, 1050, 1099, 1100, 12345, 123456, 999999, 1000000,
1000099, 1000999, 1009999, 1099999, 1100000, 1234567, 999999999, 1000000000, 9123456789L, 123456789123L };
private static final String[] EXPECTED_FROM_TEST = new String[] { "1", "500", "999", "1k", "1k", "1k", "1k", "1k", "1k", "1.1k", "12k", "123k",
"999k", "1m", "1m", "1m", "1m", "1m", "1.1m", "1.2m", "999m", "1b", "9.1b", "123b" };
private static final String[] EXPECTED_FROM_TEST_HALF_UP = new String[] { "1", "500", "999", "1k", "1k", "1k", "1k", "1.1k", "1.1k", "1.1k", "12k",
"123k", "1m", "1m", "1m", "1m", "1m", "1.1m", "1.1m", "1.2m", "1b", "1b", "9.1b", "123b" };
#Test
public void testThresholdFor() {
assertEquals(Threshold.ZERO, Threshold.thresholdFor(1));
assertEquals(Threshold.ZERO, Threshold.thresholdFor(999));
assertEquals(Threshold.THOUSAND, Threshold.thresholdFor(1000));
assertEquals(Threshold.THOUSAND, Threshold.thresholdFor(1234));
assertEquals(Threshold.THOUSAND, Threshold.thresholdFor(9999));
assertEquals(Threshold.THOUSAND, Threshold.thresholdFor(999999));
assertEquals(Threshold.MILLION, Threshold.thresholdFor(1000000));
}
#Test
public void testToPrecision() {
RoundingMode mode = RoundingMode.DOWN;
assertEquals(new BigDecimal("1"), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("1.23456"), 1, mode));
assertEquals(new BigDecimal("1.2"), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("1.23456"), 2, mode));
assertEquals(new BigDecimal("1.23"), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("1.23456"), 3, mode));
assertEquals(new BigDecimal("1.234"), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("1.23456"), 4, mode));
assertEquals(new BigDecimal("999").toPlainString(), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("999"), 4, mode).stripTrailingZeros()
.toPlainString());
assertEquals(new BigDecimal("999").toPlainString(), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("999"), 2, mode).stripTrailingZeros()
.toPlainString());
assertEquals(new BigDecimal("999").toPlainString(), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("999.9"), 2, mode).stripTrailingZeros()
.toPlainString());
mode = RoundingMode.HALF_UP;
assertEquals(new BigDecimal("1"), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("1.23456"), 1, mode));
assertEquals(new BigDecimal("1.2"), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("1.23456"), 2, mode));
assertEquals(new BigDecimal("1.23"), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("1.23456"), 3, mode));
assertEquals(new BigDecimal("1.235"), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("1.23456"), 4, mode));
assertEquals(new BigDecimal("999").toPlainString(), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("999"), 4, mode).stripTrailingZeros()
.toPlainString());
assertEquals(new BigDecimal("999").toPlainString(), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("999"), 2, mode).stripTrailingZeros()
.toPlainString());
assertEquals(new BigDecimal("1000").toPlainString(), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("999.9"), 2, mode)
.stripTrailingZeros().toPlainString());
}
#Test
public void testNumbersFromOP() {
for (int i = 0; i < NUMBERS_FROM_OP.length; i++) {
assertEquals("Index " + i + ": " + NUMBERS_FROM_OP[i], EXPECTED_FROM_OP[i],
NumberShortener.shortenedNumber(NUMBERS_FROM_OP[i], RoundingMode.DOWN));
assertEquals("Index " + i + ": " + NUMBERS_FROM_OP[i], EXPECTED_FROM_OP_HALF_UP[i],
NumberShortener.shortenedNumber(NUMBERS_FROM_OP[i], RoundingMode.HALF_UP));
}
}
#Test
public void testBorders() {
assertEquals("Zero: " + 0, "0", NumberShortener.shortenedNumber(0, RoundingMode.DOWN));
assertEquals("Zero: " + 0, "0", NumberShortener.shortenedNumber(0, RoundingMode.HALF_UP));
for (int i = 0; i < NUMBERS_TO_TEST.length; i++) {
assertEquals("Index " + i + ": " + NUMBERS_TO_TEST[i], EXPECTED_FROM_TEST[i],
NumberShortener.shortenedNumber(NUMBERS_TO_TEST[i], RoundingMode.DOWN));
assertEquals("Index " + i + ": " + NUMBERS_TO_TEST[i], EXPECTED_FROM_TEST_HALF_UP[i],
NumberShortener.shortenedNumber(NUMBERS_TO_TEST[i], RoundingMode.HALF_UP));
}
}
#Test
public void testNegativeBorders() {
for (int i = 0; i < NUMBERS_TO_TEST.length; i++) {
assertEquals("Index " + i + ": -" + NUMBERS_TO_TEST[i], "-" + EXPECTED_FROM_TEST[i],
NumberShortener.shortenedNumber(-NUMBERS_TO_TEST[i], RoundingMode.DOWN));
assertEquals("Index " + i + ": -" + NUMBERS_TO_TEST[i], "-" + EXPECTED_FROM_TEST_HALF_UP[i],
NumberShortener.shortenedNumber(-NUMBERS_TO_TEST[i], RoundingMode.HALF_UP));
}
}
}
Feel free to point out in the comments if I missed a significant test case or if expected values should be adjusted.
Adding my own answer, Java code, self explanatory code..
import java.math.BigDecimal;
/**
* Method to convert number to formatted number.
*
* #author Gautham PJ
*/
public class ShortFormatNumbers
{
/**
* Main method. Execution starts here.
*/
public static void main(String[] args)
{
// The numbers that are being converted.
int[] numbers = {999, 1400, 2500, 45673463, 983456, 234234567};
// Call the "formatNumber" method on individual numbers to format
// the number.
for(int number : numbers)
{
System.out.println(number + ": " + formatNumber(number));
}
}
/**
* Format the number to display it in short format.
*
* The number is divided by 1000 to find which denomination to be added
* to the number. Dividing the number will give the smallest possible
* value with the denomination.
*
* #param the number that needs to be converted to short hand notation.
* #return the converted short hand notation for the number.
*/
private static String formatNumber(double number)
{
String[] denominations = {"", "k", "m", "b", "t"};
int denominationIndex = 0;
// If number is greater than 1000, divide the number by 1000 and
// increment the index for the denomination.
while(number > 1000.0)
{
denominationIndex++;
number = number / 1000.0;
}
// To round it to 2 digits.
BigDecimal bigDecimal = new BigDecimal(number);
bigDecimal = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_EVEN);
// Add the number with the denomination to get the final value.
String formattedNumber = bigDecimal + denominations[denominationIndex];
return formattedNumber;
}
}
//code longer but work sure...
public static String formatK(int number) {
if (number < 999) {
return String.valueOf(number);
}
if (number < 9999) {
String strNumber = String.valueOf(number);
String str1 = strNumber.substring(0, 1);
String str2 = strNumber.substring(1, 2);
if (str2.equals("0")) {
return str1 + "k";
} else {
return str1 + "." + str2 + "k";
}
}
if (number < 99999) {
String strNumber = String.valueOf(number);
String str1 = strNumber.substring(0, 2);
return str1 + "k";
}
if (number < 999999) {
String strNumber = String.valueOf(number);
String str1 = strNumber.substring(0, 3);
return str1 + "k";
}
if (number < 9999999) {
String strNumber = String.valueOf(number);
String str1 = strNumber.substring(0, 1);
String str2 = strNumber.substring(1, 2);
if (str2.equals("0")) {
return str1 + "m";
} else {
return str1 + "." + str2 + "m";
}
}
if (number < 99999999) {
String strNumber = String.valueOf(number);
String str1 = strNumber.substring(0, 2);
return str1 + "m";
}
if (number < 999999999) {
String strNumber = String.valueOf(number);
String str1 = strNumber.substring(0, 3);
return str1 + "m";
}
NumberFormat formatterHasDigi = new DecimalFormat("###,###,###");
return formatterHasDigi.format(number);
}
This code snippet just deadly simple, and clean code, and totally works:
private static char[] c = new char[]{'K', 'M', 'B', 'T'};
private String formatK(double n, int iteration) {
if (n < 1000) {
// print 999 or 999K
if (iteration <= 0) {
return String.valueOf((long) n);
} else {
return String.format("%d%s", Math.round(n), c[iteration-1]);
}
} else if (n < 10000) {
// Print 9.9K
return String.format("%.1f%s", n/1000, c[iteration]);
} else {
// Increase 1 iteration
return formatK(Math.round(n/1000), iteration+1);
}
}
try this :
public String Format(Integer number){
String[] suffix = new String[]{"k","m","b","t"};
int size = (number.intValue() != 0) ? (int) Math.log10(number) : 0;
if (size >= 3){
while (size % 3 != 0) {
size = size - 1;
}
}
double notation = Math.pow(10, size);
String result = (size >= 3) ? + (Math.round((number / notation) * 100) / 100.0d)+suffix[(size/3) - 1] : + number + "";
return result
}
There is a solution on the Maven Central
<dependency>
<groupId>com.github.bogdanovmn.humanreadablevalues</groupId>
<artifactId>human-readable-values</artifactId>
<version>1.0.1</version>
</dependency>
You can just get values for amount of bytes or seconds. Also you can create you own factorization class.
Docs
https://github.com/bogdanovmn/java-human-readable-values
Seconds example
assertEquals(
"2h 46m 40s",
new SecondsValue(10000).fullString()
);
assertEquals(
"2.8h",
new SecondsValue(10000).shortString()
);
Bytes example
assertEquals(
"9K 784b",
new BytesValue(10000).fullString()
);
assertEquals(
"9.8K",
new BytesValue(10000).shortString()
);
Set the divisor according to the the input number: 1000, 100000, 1000000, 1000000000 etc...
check the whole part(first part without fraction) of the number if its size is 1 then cast the input to long + String.
if the size is >= 2 then divide the input and use DecimalFormat to show fractional part as desired.
you can use // .setRoundingMode(RoundingMode.DOWN) to deal with rounding
public static String format(long num) {
String suffix = "", result;
double divisor = 0;
DecimalFormat df = new DecimalFormat("##");
DecimalFormat ds = new DecimalFormat("##.#");
// ds.setRoundingMode(RoundingMode.DOWN);
if ( num >= 1000 && num < 1000000 ) {
divisor = 1000;
suffix = "K";
} else if ( num >= 1000000 && num < 1000000000 ) {
divisor = 1000000;
suffix = "M";
} else if (num >= 1000000000) {
divisor = 1000000000;
suffix = "B";
} else {
System.out.print("The number is Too big > T or TOO small < K");
}
int numlengt = df.format(num / divisor).length();
if (numlengt >= 2) {
result = (long) (num / divisor) + suffix;
} else {
result = ds.format(num / divisor) + suffix;
}
return result;
}
public class NumberToReadableWordFormat {
public static void main(String[] args) {
Integer[] numbers = new Integer[]{1000, 5821, 10500, 101800, 2000000, 7800000, 92150000, 123200000, 9999999,999};
for(int n : numbers) {
System.out.println(n + " => " + coolFormat(n));
}
}
private static String[] c = new String[]{"K", "L", "Cr"};
private static String coolFormat(int n) {
int size = String.valueOf(n).length();
if (size>=4 && size<6) {
int value = (int) Math.pow(10, 1);
double d = (double) Math.round(n/1000.0 * value) / value;
return (double) Math.round(n/1000.0 * value) / value+" "+c[0];
} else if(size>5 && size<8) {
int value = (int) Math.pow(10, 1);
return (double) Math.round(n/100000.0 * value) / value+" "+c[1];
} else if(size>=8) {
int value = (int) Math.pow(10, 1);
return (double) Math.round(n/10000000.0 * value) / value+" "+c[2];
} else {
return n+"";
}
}
}
Output:
1000 => 1.0 K
5821 => 5.8 K
10500 => 10.5 K
101800 => 1.0 L
2000000 => 20.0 L
7800000 => 78.0 L
92150000 => 9.2 Cr
123200000 => 12.3 Cr
9999999 => 100.0 L
999 => 999
Here is a another simple solution for your problem.
let say
String abbr="M,K,T,B";
double yvalue=some random number;
String string ="#.##" //decimal places whatever you want
public String format(Double yvalue, String string,String abbr) {
DecimalFormat df = new DecimalFormat(getnumberformatpattern(string));
if (yvalue < 0) return "-" + format(-yvalue,string,abbr);
double finalvalue= yvalue;
String newnumber="";
if (abbr.indexOf("K")>0){
finalvalue= (yvalue / 1e3);
newnumber=df.format(finalvalue) +'K';
}
if (abbr.indexOf("M")>0 ){
if(yvalue>=1e6){
finalvalue= (yvalue / 1e6);
newnumber=df.format(finalvalue) +'M';
};
}
if (abbr.indexOf("B")>0 )
{
if((newnumber.indexOf("M")<0) || yvalue>=1e9){
finalvalue= (yvalue / 1e9);
newnumber=df.format(finalvalue) +'B'; }
}
if (abbr.indexOf("T")>0 ){
if((newnumber.indexOf("B")<0) || yvalue>=1e12){
finalvalue= (yvalue / 1e12);
newnumber=df.format(finalvalue) +'T'; }
}
return newnumber;
}
fun getKLCrValue(input: Long):String{
return if(input.toString().length<4){
input.toString()
}else if(input.toString().length<5)
( ""+getExactValue(input.toString()[0] +"."+ input.toString()[1]) +"K")
else if(input.toString().length<6)
(""+getExactValue(""+input.toString().subSequence(0, 2) +"."+ input.toString()[2]) +"K")
else if(input.toString().length<7)
(""+ getExactValue( input.toString()[0] +"."+input.toString().subSequence(1, 3))+"L")
else if(input.toString().length<8)
(""+ getExactValue( ""+input.toString().subSequence(0, 2)+"."+input.toString().subSequence(2,4))+"L")
else if(input.toString().length<9)
(""+ getExactValue( input.toString()[0] +"."+input.toString().subSequence(1,3))+"Cr")
else
(""+ getExactValue( ""+input.toString().subSequence(0, input.toString().length-7)+"."+input.toString().subSequence( input.toString().length-7, input.toString().length-5))+"cr")
}
private fun getExactValue(value: String): String {
return value.replace(".00", "")
}
You can just call getKLCrValue(1234) and you will get desired output
Output-->
1 -> 1
10 -> 10
12 -> 12
100 -> 100
123 -> 123
1000 -> 1K
1234 -> 1.2K
10000 -> 10K
12345 -> 12.3K
100000 -> 1L
123456 -> 1.23L
1000000 -> 10L
1234567 -> 12.34L
10000000 -> 1cr
12345678 -> 1.23cr
100000000 -> 10cr
123456789 -> 12.34cr
1000000000 -> 100cr
1234567890 -> 123.45cr
10000000000 -> 1000cr
11111111111 -> 1111.11cr

Categories

Resources