DecimalUtils.java
package com.alibaba.fastjson2.benchmark.fastcode;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
public class DecimalUtils {
public static String toString(long unscaledVal, int scale) {
if (scale == 0) {
return Long.toString(unscaledVal);
}
boolean negative = false;
if (unscaledVal < 0) {
unscaledVal = -unscaledVal;
negative = true;
}
int size = stringSize(unscaledVal);
byte[] buf;
int off = 0;
if (scale < 0) {
buf = new byte[size - scale + (negative ? 1 : 0)];
if (negative) {
buf[0] = '-';
off = 1;
}
getChars(unscaledVal, off + size, buf);
Arrays.fill(buf, off + size, buf.length, (byte) '0');
} else {
int insertionPoint = size - scale;
if (insertionPoint <= 0) {
buf = new byte[size + 2 - insertionPoint + (negative ? 1 : 0)];
if (negative) {
buf[0] = '-';
off = 1;
}
buf[off] = '0';
buf[off + 1] = '.';
for (int i = 0; i < -insertionPoint; i++) {
buf[off + i + 2] = '0';
}
getChars(unscaledVal, buf.length, buf);
} else {
long power = POWER_TEN[scale - 1];
long div = unscaledVal / power;
long rem = unscaledVal - div * power;
int divSize = size - scale;
buf = new byte[size + (negative ? 2 : 1)];
if (negative) {
buf[0] = '-';
off = 1;
}
getChars(div, off + divSize, buf);
buf[divSize + off] = '.';
getChars(rem, buf.length, buf);
}
}
return new String(buf);
}
@SuppressWarnings("deprecated")
public static String toString(BigInteger unscaledVal, int scale) {
if (scale == 0) {
return unscaledVal.toString(10);
}
boolean negative = false;
if (unscaledVal.signum() < 0) {
negative = true;
unscaledVal = unscaledVal.negate();
}
String unscaledValString = unscaledVal.toString(10);
int size = unscaledValString.length();
byte[] buf;
int off = 0;
if (scale < 0) {
buf = new byte[size - scale + (negative ? 1 : 0)];
if (negative) {
buf[0] = '-';
off = 1;
}
unscaledValString.getBytes(0, size, buf, off);
Arrays.fill(buf, off + size, buf.length, (byte) '0');
} else {
int insertionPoint = size - scale;
if (insertionPoint <= 0) {
buf = new byte[size + 2 - insertionPoint + (negative ? 1 : 0)];
if (negative) {
buf[0] = '-';
off = 1;
}
buf[off] = '0';
buf[off + 1] = '.';
off += 2;
for (int i = 0; i < -insertionPoint; i++) {
buf[off++] = '0';
}
unscaledValString.getBytes(0, size, buf, off);
} else {
buf = new byte[size + (negative ? 2 : 1)];
if (negative) {
buf[0] = '-';
off = 1;
}
unscaledValString.getBytes(0, insertionPoint, buf, off);
off += insertionPoint;
buf[off] = '.';
unscaledValString.getBytes(insertionPoint, size, buf, off + 1);
}
}
return new String(buf);
}
static final long[] POWER_TEN = {
10,
100,
1000,
10000,
100000,
1000000,
10000000,
100000000,
1000000000,
10000000000L,
100000000000L,
1000000000000L,
10000000000000L,
100000000000000L,
1000000000000000L,
10000000000000000L,
100000000000000000L,
1000000000000000000L,
};
static String layout(long intCompact, int scale, boolean sci) {
if (scale == 0) {
return Long.toString(intCompact);
}
long unscaledVal;
boolean negative = false;
if (intCompact < 0) {
unscaledVal = -intCompact;
negative = true;
} else {
unscaledVal = intCompact;
}
int coeffLen = stringSize(unscaledVal);
long adjusted = -(long) scale + (coeffLen - 1);
byte[] buf;
int off = 0;
if ((scale >= 0) && (adjusted >= -6)) {
int pad = scale - coeffLen;
if (pad >= 0) {
buf = new byte[coeffLen + 2 + pad + (negative ? 1 : 0)];
if (negative) {
buf[0] = '-';
off = 1;
}
buf[off] = '0';
buf[off + 1] = '.';
off += 2;
for (int i = 0; i < pad; i++) {
buf[off++] = '0';
}
getChars(unscaledVal, buf.length, buf);
} else {
buf = new byte[coeffLen + 1 + (negative ? 1 : 0)];
if (negative) {
buf[0] = '-';
off = 1;
}
long power = POWER_TEN[scale - 1];
long div = unscaledVal / power;
long rem = unscaledVal - div * power;
getChars(div, off + coeffLen - scale, buf);
buf[off + coeffLen - scale] = '.';
getChars(rem, off + coeffLen + 1, buf);
}
} else {
if (sci) {
if (coeffLen > 1) {
int adjustedSize = adjusted != 0 ? stringSize(Math.abs(adjusted)) + 2 : 0;
buf = new byte[coeffLen + adjustedSize + 1 + (negative ? 1 : 0)];
if (negative) {
buf[0] = '-';
off = 1;
}
long power = POWER_TEN[coeffLen - 2];
long div = unscaledVal / power;
long rem = unscaledVal - div * power;
buf[off] = (byte) (div + '0');
buf[off + 1] = '.';
getChars(rem, off + coeffLen + 1, buf);
off += coeffLen + 1;
} else {
int adjustedSize = adjusted != 0 ? stringSize(Math.abs(adjusted)) + 2 : 0;
buf = new byte[adjustedSize + (negative ? 2 : 1)];
if (negative) {
buf[0] = '-';
off = 1;
}
buf[off++] = (byte) (unscaledVal + '0');
}
} else {
int sig = (int) (adjusted % 3);
if (sig < 0) {
sig += 3; // [adjusted was negative]
}
adjusted -= sig; // now a multiple of 3
sig++;
int adjustedSize = adjusted != 0 ? stringSize(Math.abs(adjusted)) + 2 : 0;
if (unscaledVal == 0) {
switch (sig) {
case 1: {
buf = new byte[adjustedSize + 1];
buf[0] = '0'; // exponent is a multiple of three
off = 1;
break;
}
case 2: {
adjusted += 3;
adjustedSize = adjusted != 0 ? stringSize(Math.abs(adjusted)) + 2 : 0;
buf = new byte[adjustedSize + 4];
buf[0] = '0';
buf[1] = '.';
buf[2] = '0';
buf[3] = '0';
off = 4;
break;
}
case 3: {
adjusted += 3;
adjustedSize = adjusted != 0 ? stringSize(Math.abs(adjusted)) + 2 : 0;
buf = new byte[adjustedSize + 3];
buf[0] = '0';
buf[1] = '.';
buf[2] = '0';
off = 3;
break;
}
default:
throw new AssertionError("Unexpected sig value " + sig);
}
} else if (sig >= coeffLen) {
buf = new byte[adjustedSize + (negative ? 2 : 1) + sig - coeffLen];
if (negative) {
buf[0] = '-';
off = 1;
}
getChars(unscaledVal, off + coeffLen, buf);
off += coeffLen;
for (int i = sig - coeffLen; i > 0; i--) {
buf[off++] = '0';
}
} else {
buf = new byte[adjustedSize + (negative ? 2 : 1) + coeffLen];
if (negative) {
buf[0] = '-';
off = 1;
}
long power = POWER_TEN[coeffLen - sig - 1];
long div = unscaledVal / power;
long rem = unscaledVal - div * power;
getChars(div, off + sig, buf);
buf[off + sig] = '.';
getChars(rem, off + coeffLen + 1, buf);
off += coeffLen + 1;
}
}
if (adjusted != 0) { // [!sci could have made 0]
buf[off] = 'E';
buf[off + 1] = (byte) (adjusted > 0 ? '+' : '-');
getChars(Math.abs(adjusted), buf.length, buf);
}
}
return new String(buf);
}
static String layout(BigInteger intVal, int scale, boolean sci) {
if (scale == 0) {
return intVal.toString();
}
BigInteger unscaledVal;
boolean negative = false;
int signum = intVal.signum();
if (signum < 0) {
unscaledVal = intVal.negate();
negative = true;
} else {
unscaledVal = intVal;
}
byte[] buf;
int off = 0;
String unscaledValString = unscaledVal.toString(10);
byte[] coeff = unscaledValString.getBytes(StandardCharsets.ISO_8859_1);
int coeffLen = coeff.length;
long adjusted = -(long) scale + (coeffLen - 1);
if ((scale >= 0) && (adjusted >= -6)) {
int pad = scale - coeffLen;
if (pad >= 0) {
buf = new byte[coeffLen + 2 + pad + (negative ? 1 : 0)];
if (negative) {
buf[0] = '-';
off = 1;
}
buf[off] = '0';
buf[off + 1] = '.';
off += 2;
for (int i = 0; i < pad; i++) {
buf[off++] = '0';
}
System.arraycopy(coeff, 0, buf, off, coeffLen);
} else {
buf = new byte[coeffLen + 1 + (negative ? 1 : 0)];
if (negative) {
buf[0] = '-';
off = 1;
}
System.arraycopy(coeff, 0, buf, off, -pad);
buf[off - pad] = '.';
System.arraycopy(coeff, -pad, buf, off - pad + 1, scale);
}
} else {
if (sci) { // Scientific notation
if (coeffLen > 1) {
int adjustedSize = adjusted != 0 ? stringSize(Math.abs(adjusted)) + 2 : 0;
buf = new byte[coeffLen + adjustedSize + 1 + (negative ? 1 : 0)];
if (negative) {
buf[0] = '-';
off = 1;
}
buf[off] = coeff[0];
buf[off + 1] = '.';
System.arraycopy(coeff, 1, buf, off + 2, coeffLen - 1);
off += coeffLen + 1;
} else {
int adjustedSize = adjusted != 0 ? stringSize(Math.abs(adjusted)) + 2 : 0;
buf = new byte[adjustedSize + (negative ? 2 : 1)];
if (negative) {
buf[0] = '-';
off = 1;
}
buf[off++] = coeff[0];
}
} else {
int sig = (int) (adjusted % 3);
if (sig < 0) {
sig += 3; // [adjusted was negative]
}
adjusted -= sig; // now a multiple of 3
sig++;
int adjustedSize = adjusted != 0 ? stringSize(Math.abs(adjusted)) + 2 : 0;
if (signum == 0) {
switch (sig) {
case 1: {
buf = new byte[adjustedSize + 1];
buf[0] = '0'; // exponent is a multiple of three
off = 1;
break;
}
case 2: {
adjusted += 3;
adjustedSize = adjusted != 0 ? stringSize(Math.abs(adjusted)) + 2 : 0;
buf = new byte[adjustedSize + 4];
buf[0] = '0';
buf[1] = '.';
buf[2] = '0';
buf[3] = '0';
off = 4;
break;
}
case 3: {
adjusted += 3;
adjustedSize = adjusted != 0 ? stringSize(Math.abs(adjusted)) + 2 : 0;
buf = new byte[adjustedSize + 3];
buf[0] = '0';
buf[1] = '.';
buf[2] = '0';
off = 3;
break;
}
default:
throw new AssertionError("Unexpected sig value " + sig);
}
} else if (sig >= coeffLen) {
buf = new byte[adjustedSize + (negative ? 2 : 1) + sig - coeffLen];
if (negative) {
buf[0] = '-';
off = 1;
}
System.arraycopy(coeff, 0, buf, off, coeffLen);
off += coeffLen;
for (int i = sig - coeffLen; i > 0; i--) {
buf[off++] = '0';
}
} else {
buf = new byte[adjustedSize + (negative ? 2 : 1) + coeffLen];
if (negative) {
buf[0] = '-';
off = 1;
}
System.arraycopy(coeff, 0, buf, off, sig);
buf[off + sig] = '.';
System.arraycopy(coeff, sig, buf, off + sig + 1, coeffLen - sig);
off += coeffLen + 1;
}
}
if (adjusted != 0) { // [!sci could have made 0]
buf[off] = 'E';
buf[off + 1] = (byte) (adjusted > 0 ? '+' : '-');
getChars(Math.abs(adjusted), buf.length, buf);
}
}
return new String(buf);
}
static int stringSize(long x) {
long p = 10;
for (int i = 1; i < 19; i++) {
if (x < p) {
return i;
}
p = 10 * p;
}
return 19;
}
public static final short[] PACKED_DIGITS = new short[]{
0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, 0x3630, 0x3730, 0x3830, 0x3930,
0x3031, 0x3131, 0x3231, 0x3331, 0x3431, 0x3531, 0x3631, 0x3731, 0x3831, 0x3931,
0x3032, 0x3132, 0x3232, 0x3332, 0x3432, 0x3532, 0x3632, 0x3732, 0x3832, 0x3932,
0x3033, 0x3133, 0x3233, 0x3333, 0x3433, 0x3533, 0x3633, 0x3733, 0x3833, 0x3933,
0x3034, 0x3134, 0x3234, 0x3334, 0x3434, 0x3534, 0x3634, 0x3734, 0x3834, 0x3934,
0x3035, 0x3135, 0x3235, 0x3335, 0x3435, 0x3535, 0x3635, 0x3735, 0x3835, 0x3935,
0x3036, 0x3136, 0x3236, 0x3336, 0x3436, 0x3536, 0x3636, 0x3736, 0x3836, 0x3936,
0x3037, 0x3137, 0x3237, 0x3337, 0x3437, 0x3537, 0x3637, 0x3737, 0x3837, 0x3937,
0x3038, 0x3138, 0x3238, 0x3338, 0x3438, 0x3538, 0x3638, 0x3738, 0x3838, 0x3938,
0x3039, 0x3139, 0x3239, 0x3339, 0x3439, 0x3539, 0x3639, 0x3739, 0x3839, 0x3939
};
static void getChars(long i, int index, byte[] buf) {
long q;
int charPos = index;
boolean negative = (i < 0);
if (negative) {
i = -i;
}
// Get 2 digits/iteration using longs until quotient fits into an int
while (i > Integer.MAX_VALUE) {
q = i / 100;
short v = PACKED_DIGITS[(int) (i - q * 100)];
buf[--charPos] = (byte) (v >> 8);
buf[--charPos] = (byte) v;
i = q;
}
// Get 2 digits/iteration using ints
int q2;
int i2 = (int) i;
while (i2 >= 100) {
q2 = i2 / 100;
short v = PACKED_DIGITS[i2 - q2 * 100];
buf[--charPos] = (byte) (v >> 8);
buf[--charPos] = (byte) v;
i2 = q2;
}
// We know there are at most two digits left at this point.
if (i2 > 9) {
short v = PACKED_DIGITS[i2];
buf[--charPos] = (byte) (v >> 8);
buf[--charPos] = (byte) v;
} else {
buf[--charPos] = (byte) ('0' + i2);
}
if (negative) {
buf[charPos - 1] = (byte) '-';
}
}
}