content: 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) '-';
          }
      }
  }
  