Here's a relatively simple implementation. It doesn't support negative numbers, for simplicity. A version that does is below. Comments are in-line in the code.
public static byte[] asciiDigits(int value) {
if (value < 0) throw new IllegalArgumentException();
// Iterate through least-significant digits first
byte[] reverseOrder = new byte[10];
int digits = 0;
for (; value > 0; ++digits) {
int digit = value % 10;
reverseOrder[digits] = (byte) ('0' + digit);
value /= 10;
}
// Now size down the array to the right size and reverse it
byte[] bytes = new byte[digits];
for (int i = 0; i < digits; ++i) {
bytes[i] = reverseOrder[digits - i - 1];
}
return bytes;
}
And this one supports negatives. The basic idea is to convert it to a positive number, do all the same steps, and append the minus sign.
public static byte[] asciiDigits(int value) {
boolean isNegative = false;
if (value < 0) {
// The only value where the absolute value is not representable, so just hardcode the array
if (value == Integer.MIN_VALUE) {
return new byte[] { 45, 50, 49, 52, 55, 52, 56, 51, 54, 52, 56 };
}
value = -value;
isNegative = true;
}
// Iterate through least-significant digits first.
// We don't yet know how many digits there may be, but 10 is the most digits an int could have
byte[] reverseOrderBytes = new byte[10];
int digits = 0;
for (; value > 0; ++digits) {
int digit = value % 10;
reverseOrderBytes[digits] = (byte) ('0' + digit);
value /= 10;
}
// Now reduce the size of the array to the correct size and reverse it, possibly prepending a minus sign
int signAdjustment = isNegative ? 1 : 0;
byte[] bytes = new byte[digits + signAdjustment];
if (isNegative) {
bytes[0] = 45; // minus sign
}
for (int i = 0; i < digits; ++i) {
bytes[i + signAdjustment] = reverseOrderBytes[digits - i - 1];
}
return bytes;
}
The temporary array seems like the most obvious candidate for removal, so I wrote a version that calculates the number of digits first (a couple of comparisons), then iterates through the least-significant digits first, but writes to the array back-to-front.
The numDigits
method was from this answer to another question.
public static byte[] asciiDigits(int value) {
if (value == Integer.MIN_VALUE) {
return new byte[] { 45, 50, 49, 52, 55, 52, 56, 51, 54, 52, 56 };
}
int numDigits = numDigits(value);
boolean isNegative = value < 0;
int signAdjustment = isNegative ? 1 : 0;
byte[] bytes = new byte[numDigits + signAdjustment];
if (isNegative) {
bytes[0] = 45; // minus sign
value = -value;
}
for (int i = 0; i < numDigits; ++i) {
int digit = value % 10;
bytes[numDigits + signAdjustment - i - 1] = (byte) ('0' + digit);
value /= 10;
}
return bytes;
}
private static int numDigits(int n) {
if (n < 0) {
n = -n;
}
if (n < 100000) {
if (n < 100) {
if (n < 10) return 1;
return 2;
}
else {
if (n < 1000) return 3;
if (n < 10000) return 4;
return 5;
}
}
else {
if (n < 10000000) {
if (n < 1000000) return 6;
return 7;
}
else {
if (n < 100000000) return 8;
if (n < 1000000000) return 9;
return 10;
}
}
}
I haven't benchmarked any of these. The third version intuitively seems the best, but it's often hard to predict.