Daily Archives: November 16, 2015

Oracle’s internal formats.3

Negative values between -1 and 0

A value of -0.00412
40 we can use 0x40 xor 0x7f = 0x3f (which is the same exponent as for the positive value)
3C we can use 0x65 (101) – 0x3C = 0x29 (41)
51 we can use 0x65 (101) – 0x51 = 0x14 (20)
66 the minus sign

A value of -0.412
3f xor 7f = 40 (positive equivalent is 0xC0, highest bit differs) = -2
3c should be 41
51 should be 20
66

Seems to work.

+/- infinity

There is a byte array

FF
65

which is used for numbers larger than 9.999..9*10^125.

Smaller values then -9.999..9*10^125 will be stored as a single byte

00

Both values could be interpreted as +/- infinity.

Borders

Values with a smaller exponent than -130 will be stored as zero (one byte 0x80).

I have written the algorithms into a Java class:

import java.math.BigDecimal;
import java.util.Arrays;

public class OracleNumber {

	private final BigDecimal value;

	public static final OracleNumber ZERO = new OracleNumber(BigDecimal.ZERO);
	public static final OracleNumber POSITIVE_INFINITY = new OracleNumber(new BigDecimal("1E200"));
	public static final OracleNumber NEGATIVE_INFINITY = new OracleNumber(new BigDecimal("-1E200"));

	private OracleNumber(BigDecimal val) {
		this.value = val;
	}

	private OracleNumber(boolean negative, String mantissa, int exponent) {
		this.value = new BigDecimal((negative ? "-" : "") + mantissa + "0E" + exponent).stripTrailingZeros();
	}

	private static boolean isZero(short[] array) {
		return array.length == 1 && array[0] == 0x80;
	}

	private static boolean isNegative(short[] array) {
		return ((array[0] & 0x80) == 0);
	}

	private static boolean hasPositiveExponent(short[] array) {
		return (array[0] & 0x40) != 0;
	}

	private static boolean isPositiveInfinity(short[] array) {
		return (array.length == 2 && array[0] == 0xFF && array[1] == 0x65);
	}

	private static boolean isNegativeInfinity(short[] array) {
		return (array.length == 1 && array[0] == 0x0);
	}

	public static OracleNumber newInstance(short[] array) {

		short[] number = Arrays.copyOf(array, array.length);

		if (isZero(number)) {
			return OracleNumber.ZERO;
		}

		if (isNegativeInfinity(number)) {
			return OracleNumber.NEGATIVE_INFINITY;
		}

		if (isPositiveInfinity(number)) {
			return OracleNumber.POSITIVE_INFINITY;
		}

		if (isNegative(number)) {
			// convert exponent into the equivalent for positive numbers
			number[0] = (short) ((number[0] | 0x80) ^ 0x7F);
		}

		int exponent;

		if (hasPositiveExponent(number)) {
			exponent = ((number[0] & 0x3F) << 1) - 2;
		} else {
			exponent = -1 * (((number[0] ^ 0xBF) << 1) + 4);
		}

		// calculating mantissa
		String mantissa = "";
		for (int i = 1; i < number.length; i++) {
			if (isNegative(array)) {
				mantissa += (number[i] > 0x65) ? "" : (0x65 - number[i]);
			} else {
				mantissa += (number[i] - 1);
			}
			if (i == 1) {
				mantissa += ".";
			}
		}

		return new OracleNumber(isNegative(array), mantissa, exponent);
	}

	@Override
	public String toString() {
		return value.toString();
	}

	public BigDecimal getValue() {
		return new BigDecimal(value.toString());
	}
}

Oracle’s internal formats.2

Negative values

A value of -99.99
3e = 0011 1110, this should 10^0 = 1
02 = 0000 0010
02 = 0000 0010
66 = 0110 0110 (seems to be the minus sign)

A value of -98.98
3e = 0011 1110, this should 10^0 = 1
03 = we could use 101 (0x65) as base – 3 = 98
03 = same
66 = minus sign

A value of -412
3d = 0011 1101, this should 10^2 = 100
61 = 0110 0001 = 0x65 – 0x61 = 0x4
59 = 0101 1001 = 0x65 – 0x59 = 0xC (12)
66 = 0110 0110 (minus sign)

A value of -1
3e = 10^0
64 = 0x65 – 0x64 = 1
66 = minus sign

I can transform the exponent by

exponent xor 0x7F

which results in an exponent as for positive numbers. The last mantissa byte is always 0x66, which we can ignore (minus sign). The exponent contains in the highest bit the sign flag, so I can differ between positive and negative numbers by

exponent & 0x80 = 0 (negative) = 1 (positive)

Negative values less than 1

A value of -0.00412
40
3C
51
66

WTF?