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());
}
}