public static int fastBigIntegerBytesUnscaled(
      final int fastSignum, long fast0, long fast1, long fast2,
      long[] scratchLongs, byte[] buffer) {

    /*
     * Algorithm:
     * 1) Convert decimal to three 56-bit words (three is enough for the decimal since we
     *    represent the decimal with trailing zeroes trimmed).
     * 2) Skip leading zeroes in the words.
     * 3) Once we find real data (i.e. a non-zero byte), add a sign byte to buffer if necessary.
     * 4) Add bytes from the (rest of) 56-bit words.
     * 5) Return byte count.
     */

    if (fastSignum == 0) {
      buffer[0] = 0;
      return 1;
    }

    boolean isNegative = (fastSignum == -1);

    /*
     * Use common conversion method we share with fastSerializationUtilsWrite.
     */
    if (!doDecimalToBinaryConversion(
        fast0, fast1, fast2,
        FAST_HIVE_DECIMAL_TWO_POWER_56_INVERSE,
        BIG_INTEGER_BYTES_QUOTIENT_INTEGER_WORD_NUM,
        BIG_INTEGER_BYTES_QUOTIENT_INTEGER_DIGIT_NUM,
        FAST_HIVE_DECIMAL_TWO_POWER_56,
        scratchLongs)) {
      // Overflow.  This is not expected.
      return 0;
    }

    int byteIndex = 0;

    long word0 = scratchLongs[0];
    long word1 = scratchLongs[1];
    long word2 = scratchLongs[2];

    if (!isNegative) {

      // Positive number.

      long longWork = 0;

      int shift = INITIAL_SHIFT;

      if (word2 != 0L) {

        // Skip leading zeroes in word2.

        while (true) {
          longWork = (word2 >> shift) & LONG_BYTE_MASK;
          if (longWork != 0) {
            break;
          }
          if (shift == 0) {
            throw new RuntimeException("Unexpected #1");
          }
          shift -= Byte.SIZE;
        }

        // Now that we have found real data, emit sign byte if necessary.
        if ((longWork & LONG_BYTE_HIGH_BIT_MASK) != 0) {
          // Add sign byte since high bit is on.
          buffer[byteIndex++] = (byte) 0;
        }

        // Emit the rest of word2
        while (true) {
          buffer[byteIndex++] = (byte) longWork;
          if (shift == 0) {
            break;
          }
          shift -= Byte.SIZE;
          longWork = (word2 >> shift) & LONG_BYTE_MASK;
        }

        shift = INITIAL_SHIFT;
      }

      if (byteIndex == 0 && word1 == 0L) {

        // Skip word1, also.

      } else {

        if (byteIndex == 0) {

          // Skip leading zeroes in word1.

          while (true) {
            longWork = (word1 >> shift) & LONG_BYTE_MASK;
            if (longWork != 0) {
              break;
            }
            if (shift == 0) {
              throw new RuntimeException("Unexpected #2");
            }
            shift -= Byte.SIZE;
          }

          // Now that we have found real data, emit sign byte if necessary.
          if ((longWork & LONG_BYTE_HIGH_BIT_MASK) != 0) {
            // Add sign byte since high bit is on.
            buffer[byteIndex++] = (byte) 0;
          }

        } else {
          longWork = (word1 >> shift) & LONG_BYTE_MASK;
        }

        // Emit the rest of word1

        while (true) {
          buffer[byteIndex++] = (byte) longWork;
          if (shift == 0) {
            break;
          }
          shift -= Byte.SIZE;
          longWork = (word1 >> shift) & LONG_BYTE_MASK;
        }

        shift = INITIAL_SHIFT;
      }

      if (byteIndex == 0) {

        // Skip leading zeroes in word0.

        while (true) {
          longWork = (word0 >> shift) & LONG_BYTE_MASK;
          if (longWork != 0) {
            break;
          }
          if (shift == 0) {

            // All zeroes -- we should have handled this earlier.
            throw new RuntimeException("Unexpected #3");
          }
          shift -= Byte.SIZE;
        }

        // Now that we have found real data, emit sign byte if necessary.
        if ((longWork & LONG_BYTE_HIGH_BIT_MASK) != 0) {
          // Add sign byte since high bit is on.
          buffer[byteIndex++] = (byte) 0;
        }

      } else {
        longWork = (word0 >> shift) & LONG_BYTE_MASK;
      }

      // Emit the rest of word0.
      while (true) {
        buffer[byteIndex++] = (byte) longWork;
        if (shift == 0) {
          break;
        }
        shift -= Byte.SIZE;
        longWork = (word0 >> shift) & LONG_BYTE_MASK;
      }

    } else {

      // Negative number.

      // Subtract 1 for two's compliment adjustment.
      word0--;
      if (word0 < 0) {
        word0 += LONG_TWO_TO_56_POWER;
        word1--;
        if (word1 < 0) {
          word1 += LONG_TWO_TO_56_POWER;
          word2--;
          if (word2 < 0) {
            // Underflow.
            return 0;
          }
        }
      }

      long longWork = 0;

      int shift = INITIAL_SHIFT;

      if (word2 != 0L) {

        // Skip leading zeroes in word2.

        while (true) {
          longWork = (word2 >> shift) & LONG_BYTE_MASK;
          if (longWork != 0) {
            break;
          }
          if (shift == 0) {
            throw new RuntimeException("Unexpected #1");
          }
          shift -= Byte.SIZE;
        }

        // Now that we have found real data, emit sign byte if necessary and do negative fixup.

        longWork = (~longWork & LONG_BYTE_MASK);
        if (((longWork) & LONG_BYTE_HIGH_BIT_MASK) == 0) {
          // Add sign byte since high bit is off.
          buffer[byteIndex++] = BYTE_ALL_BITS;
        }

        // Invert words.
        word2 = ~word2;
        word1 = ~word1;
        word0 = ~word0;

        // Emit the rest of word2
        while (true) {
          buffer[byteIndex++] = (byte) longWork;
          if (shift == 0) {
            break;
          }
          shift -= Byte.SIZE;
          longWork = (word2 >> shift) & LONG_BYTE_MASK;
        }

        shift = INITIAL_SHIFT;
      }

      if (byteIndex == 0 && word1 == 0L) {

        // Skip word1, also.

      } else {

        if (byteIndex == 0) {

          // Skip leading zeroes in word1.

          while (true) {
            longWork = (word1 >> shift) & LONG_BYTE_MASK;
            if (longWork != 0) {
              break;
            }
            if (shift == 0) {
              throw new RuntimeException("Unexpected #2");
            }
            shift -= Byte.SIZE;
          }

          // Now that we have found real data, emit sign byte if necessary and do negative fixup.

          longWork = (~longWork & LONG_BYTE_MASK);
          if ((longWork & LONG_BYTE_HIGH_BIT_MASK) == 0) {
            // Add sign byte since high bit is off.
            buffer[byteIndex++] = BYTE_ALL_BITS;
          }

          // Invert words.
          word1 = ~word1;
          word0 = ~word0;

        } else {
          longWork = (word1 >> shift) & LONG_BYTE_MASK;
        }

        // Emit the rest of word1

        while (true) {
          buffer[byteIndex++] = (byte) longWork;
          if (shift == 0) {
            break;
          }
          shift -= Byte.SIZE;
          longWork = (word1 >> shift) & LONG_BYTE_MASK;
        }

        shift = INITIAL_SHIFT;
      }

      if (byteIndex == 0) {

        // Skip leading zeroes in word0.

        while (true) {
          longWork = (word0 >> shift) & LONG_BYTE_MASK;
          if (longWork != 0) {
            break;
          }
          if (shift == 0) {

            // All zeroes.

            // -1 special case.  Unsigned magnitude 1 - two's compliment adjustment 1 = 0.
            buffer[0] = BYTE_ALL_BITS;
            return 1;
          }
          shift -= Byte.SIZE;
        }

        // Now that we have found real data, emit sign byte if necessary and do negative fixup.

        longWork = (~longWork & LONG_BYTE_MASK);
        if ((longWork & LONG_BYTE_HIGH_BIT_MASK) == 0) {
          // Add sign byte since high bit is off.
          buffer[byteIndex++] = BYTE_ALL_BITS;
        }

        // Invert words.
        word0 = ~word0;

      } else {
        longWork = (word0 >> shift) & LONG_BYTE_MASK;
      }

      // Emit the rest of word0.
      while (true) {
        buffer[byteIndex++] = (byte) longWork;
        if (shift == 0) {
          break;
        }
        shift -= Byte.SIZE;
        longWork = (word0 >> shift) & LONG_BYTE_MASK;
      }
    }

    return byteIndex;
  }
*********************************************************************************************
  // Emulate BigInteger serialization used by LazyBinary, Avro, Parquet, and possibly others.

  public static int fastBigIntegerBytes(
      final int fastSignum, long fast0, long fast1, long fast2,
      int fastIntegerDigitCount, int fastScale,
      int fastSerializeScale,
      long[] scratchLongs, byte[] buffer) {
    if (fastSerializeScale != -1) {
      return
          fastBigIntegerBytesScaled(
              fastSignum, fast0, fast1, fast2,
              fastIntegerDigitCount, fastScale,
              fastSerializeScale,
              scratchLongs, buffer);
    } else {
      return
          fastBigIntegerBytesUnscaled(
              fastSignum, fast0, fast1, fast2,
              scratchLongs, buffer);
    }
  }

  /**
Return binary representation of this decimal's BigInteger equivalent unscaled value using
the format that the BigInteger's toByteArray method returns (and the BigInteger constructor
accepts).

Used by LazyBinary, Avro, and Parquet serialization.

Scratch objects necessary to do the decimal to binary conversion without actually creating a
BigInteger object are passed for better performance.

@param fastSignum the sign (-1, 0, or +1)
@param fast0 word 0 of the internal representation
@param fast1 word 1
@param fast2 word 2
@param scratchLongs scratch array of SCRATCH_LONGS_LEN longs
@param buffer scratch array of SCRATCH_BUFFER_LEN_BIG_INTEGER_BYTES bytes
@return The number of bytes used for the binary result in buffer.  Otherwise, 0 if the
        conversion failed.
storage-api/src/java/org/apache/hadoop/hive/common/type/FastHiveDecimalImpl.java