class UnscaledDecimal128Arithmetic {

    public static void multiply256(Slice left, Slice right, Slice result)
    {
        checkArgument(result.length() >= NUMBER_OF_LONGS * Long.BYTES * 2);

        long l0 = toUnsignedLong(getInt(left, 0));
        long l1 = toUnsignedLong(getInt(left, 1));
        long l2 = toUnsignedLong(getInt(left, 2));
        long l3 = toUnsignedLong(getInt(left, 3));

        long r0 = toUnsignedLong(getInt(right, 0));
        long r1 = toUnsignedLong(getInt(right, 1));
        long r2 = toUnsignedLong(getInt(right, 2));
        long r3 = toUnsignedLong(getInt(right, 3));

        long z0 = 0;
        long z1 = 0;
        long z2 = 0;
        long z3 = 0;
        long z4 = 0;
        long z5 = 0;
        long z6 = 0;
        long z7 = 0;

        if (l0 != 0) {
            long accumulator = r0 * l0;
            z0 = accumulator & LOW_32_BITS;
            accumulator = (accumulator >>> 32) + r1 * l0;

            z1 = accumulator & LOW_32_BITS;
            accumulator = (accumulator >>> 32) + r2 * l0;

            z2 = accumulator & LOW_32_BITS;
            accumulator = (accumulator >>> 32) + r3 * l0;

            z3 = accumulator & LOW_32_BITS;
            z4 = (accumulator >>> 32) & LOW_32_BITS;
        }

        if (l1 != 0) {
            long accumulator = r0 * l1 + z1;
            z1 = accumulator & LOW_32_BITS;
            accumulator = (accumulator >>> 32) + r1 * l1 + z2;

            z2 = accumulator & LOW_32_BITS;
            accumulator = (accumulator >>> 32) + r2 * l1 + z3;

            z3 = accumulator & LOW_32_BITS;
            accumulator = (accumulator >>> 32) + r3 * l1 + z4;

            z4 = accumulator & LOW_32_BITS;
            z5 = (accumulator >>> 32) & LOW_32_BITS;
        }

        if (l2 != 0) {
            long accumulator = r0 * l2 + z2;
            z2 = accumulator & LOW_32_BITS;
            accumulator = (accumulator >>> 32) + r1 * l2 + z3;

            z3 = accumulator & LOW_32_BITS;
            accumulator = (accumulator >>> 32) + r2 * l2 + z4;

            z4 = accumulator & LOW_32_BITS;
            accumulator = (accumulator >>> 32) + r3 * l2 + z5;

            z5 = accumulator & LOW_32_BITS;
            z6 = (accumulator >>> 32) & LOW_32_BITS;
        }

        if (l3 != 0) {
            long accumulator = r0 * l3 + z3;
            z3 = accumulator & LOW_32_BITS;
            accumulator = (accumulator >>> 32) + r1 * l3 + z4;

            z4 = accumulator & LOW_32_BITS;
            accumulator = (accumulator >>> 32) + r2 * l3 + z5;

            z5 = accumulator & LOW_32_BITS;
            accumulator = (accumulator >>> 32) + r3 * l3 + z6;

            z6 = accumulator & LOW_32_BITS;
            z7 = (accumulator >>> 32) & LOW_32_BITS;
        }

        setRawInt(result, 0, (int) z0);
        setRawInt(result, 1, (int) z1);
        setRawInt(result, 2, (int) z2);
        setRawInt(result, 3, (int) z3);
        setRawInt(result, 4, (int) z4);
        setRawInt(result, 5, (int) z5);
        setRawInt(result, 6, (int) z6);
        setRawInt(result, 7, (int) z7);
    }

    private  UnscaledDecimal128Arithmetic();

}