Completes java.lang.Float implementation

This commit is contained in:
konsoletyper 2014-03-08 00:17:25 +04:00
parent 4143e6c8d7
commit ca6e325b74
4 changed files with 217 additions and 4 deletions

View File

@ -260,7 +260,7 @@ public class TDouble extends TNumber implements TComparable<TDouble> {
} else {
doubleMantissa = abs * 0x1p1022 * binaryExponent(negExp - 1022);
}
long mantissa = (long)(doubleMantissa) & 0xFFFFFFFFFFFFFL;
long mantissa = (long)(doubleMantissa + 0.5) & 0xFFFFFFFFFFFFFL;
return mantissa | ((exp + 1023L) << 52) | (value < 0 ? (1L << 63) : 0);
}
@ -275,7 +275,7 @@ public class TDouble extends TNumber implements TComparable<TDouble> {
}
}
boolean negative = (bits & (1 << 63)) != 0;
int rawExp = (int)((bits >> 52) & 0x7FFL) - 1023;
int rawExp = (int)((bits >> 52) & 0x7FFL);
long mantissa = bits & 0xFFFFFFFFFFFFFL;
if (rawExp == 0) {
mantissa <<= 1;
@ -350,7 +350,7 @@ public class TDouble extends TNumber implements TComparable<TDouble> {
return new TString(buffer, 0, sz);
}
public static double binaryExponent(int n) {
private static double binaryExponent(int n) {
double result = 1;
if (n >= 0) {
double d = 2;

View File

@ -89,6 +89,11 @@ public class TFloat extends TNumber implements TComparable<TFloat> {
return other instanceof TFloat && ((TFloat)other).value == value;
}
@Override
public int hashCode() {
return floatToIntBits(value);
}
@GeneratedBy(FloatNativeGenerator.class)
public static native boolean isNaN(float v);
@ -231,4 +236,144 @@ public class TFloat extends TNumber implements TComparable<TFloat> {
public int compareTo(TFloat other) {
return compare(value, other.value);
}
public static int floatToRawIntBits(float value) {
return floatToIntBits(value);
}
public static int floatToIntBits(float value) {
if (value == POSITIVE_INFINITY) {
return 0x7F800000;
} else if (value == NEGATIVE_INFINITY) {
return 0xFF800000;
} else if (isNaN(value)) {
return 0x7FC00000;
}
float abs = TMath.abs(value);
int exp = TMath.getExponent(abs);
int negExp = -exp + 23;
if (exp < -126) {
exp = -127;
negExp = 126 + 23;
}
float doubleMantissa;
if (negExp <= 126) {
doubleMantissa = abs * binaryExponent(negExp);
} else {
doubleMantissa = abs * 0x1p126f * binaryExponent(negExp - 126);
}
int mantissa = (int)(doubleMantissa + 0.5f) & 0x7FFFFF;
return mantissa | ((exp + 127) << 23) | (value < 0 ? (1 << 31) : 0);
}
public static float intBitsToFloat(int bits) {
if ((bits & 0x7F800000) == 0x7F800000) {
if (bits == 0x7F800000) {
return POSITIVE_INFINITY;
} else if (bits == 0xFF800000) {
return NEGATIVE_INFINITY;
} else {
return NaN;
}
}
boolean negative = (bits & (1 << 31)) != 0;
int rawExp = ((bits >> 23) & 0x7F8) - 127;
int mantissa = bits & 0x7FFFFF;
if (rawExp == 0) {
mantissa <<= 1;
} else {
mantissa |= (1L << 23);
}
float value = mantissa * binaryExponent(rawExp - 127 - 23);
return !negative ? value : -value;
}
private static float binaryExponent(int n) {
float result = 1;
if (n >= 0) {
float d = 2;
while (n != 0) {
if (n % 2 != 0) {
result *= d;
}
n /= 2;
d *= d;
}
} else {
n = -n;
float d = 0.5f;
while (n != 0) {
if (n % 2 != 0) {
result *= d;
}
n /= 2;
d *= d;
}
}
return result;
}
public static TString toHexString(float f) {
if (isNaN(f)) {
return TString.wrap("NaN");
} else if (isInfinite(f)) {
return f > 0 ? TString.wrap("Infinity") : TString.wrap("-Infinity");
}
char[] buffer = new char[18];
int sz = 0;
int bits = floatToIntBits(f);
boolean subNormal = false;
int exp = ((bits >>> 23) & 0xFF) - 127;
int mantissa = (bits & 0x7FFFFF) << 1;
if (exp == -127) {
++exp;
subNormal = true;
}
for (int i = 0; i < 6; ++i) {
int digit = mantissa & 0xF;
if (digit > 0 || sz > 0) {
buffer[sz++] = TCharacter.forDigit(digit, 16);
}
mantissa >>>= 4;
}
if (sz == 0) {
buffer[sz++] = '0';
}
buffer[sz++] = '.';
buffer[sz++] = subNormal ? '0' : '1';
buffer[sz++] = 'x';
buffer[sz++] = '0';
if ((bits & (1L << 31)) != 0) {
buffer[sz++] = '-';
}
int half = sz / 2;
for (int i = 0; i < half; ++i) {
char tmp = buffer[i];
buffer[i] = buffer[sz - i - 1];
buffer[sz - i - 1] = tmp;
}
buffer[sz++] = 'p';
if (exp < 0) {
exp = -exp;
buffer[sz++] = '-';
}
int pos = 100;
boolean first = true;
for (int i = 0; i < 3; ++i) {
int digit = exp / pos;
if (digit > 0 || !first) {
buffer[sz++] = TCharacter.forDigit(digit, 10);
first = false;
}
exp %= pos;
pos /= 10;
}
if (first) {
buffer[sz++] = '0';
}
return new TString(buffer, 0, sz);
}
}

View File

@ -242,7 +242,36 @@ public final class TMath extends TObject {
}
public static int getExponent(float f) {
return getExponent(f);
f = abs(f);
int exp = 0;
float[] exponents = FloatExponents.exponents;
float[] negativeExponents = FloatExponents.negativeExponents;
if (f > 1) {
int expBit = 1 << (exponents.length - 1);
for (int i = exponents.length - 1; i >= 0; --i) {
if (f >= exponents[i]) {
f *= negativeExponents[i];
exp |= expBit;
}
expBit >>>= 1;
}
} else if (f < 1) {
int expBit = 1 << (negativeExponents.length - 1);
int offset = 0;
if (f <= 0x1p-127) {
f *= 0x1p23f;
offset = 23;
}
for (int i = negativeExponents.length - 1; i >= 0; --i) {
if (f <= negativeExponents[i]) {
f *= exponents[i];
exp |= expBit;
}
expBit >>>= 1;
}
exp = -(exp + offset);
}
return exp;
}
public static double nextAfter(double start, double direction) {
@ -273,4 +302,10 @@ public final class TMath extends TObject {
public static double[] negativeExponents = { 0x1p-1, 0x1p-2, 0x1p-4, 0x1p-8, 0x1p-16, 0x1p-32,
0x1p-64, 0x1p-128, 0x1p-256, 0x1p-512 };
}
private static class FloatExponents {
public static float[] exponents = { 0x1p1f, 0x1p2f, 0x1p4f, 0x1p8f, 0x1p16f, 0x1p32f, 0x1p64f };
public static float[] negativeExponents = { 0x1p-1f, 0x1p-2f, 0x1p-4f, 0x1p-8f, 0x1p-16f, 0x1p-32f,
0x1p-64f };
}
}

View File

@ -48,4 +48,37 @@ public class FloatTest {
assertEquals(0, Double.parseDouble("00000"), 1E-12);
assertEquals(0, Double.parseDouble("00000.0000"), 1E-12);
}
@Test
public void floatBitsExtracted() {
assertEquals(0x4591A2B4, Float.floatToIntBits(0x1.234567p+12f));
}
@Test
public void subNormalFloatBitsExtracted() {
assertEquals(0x000092, Float.floatToIntBits(0x0.000123p-126f));
}
@Test
public void floatBitsPacked() {
assertEquals(0x1.234567p+12f, Float.intBitsToFloat(0x4591A2B4), 1e7);
}
@Test
public void subNormalFloatBitsPacked() {
assertEquals(0x0.000123p-126f, Float.intBitsToFloat(0x000092), 0x000008p-126);
}
@Test
public void hexStringBuilt() {
assertEquals("0x1.23456p17", Float.toHexString(0x1.23456p17f));
assertEquals("0x1.0p0", Float.toHexString(1));
assertEquals("-0x1.0p0", Float.toHexString(-1));
assertEquals("0x1.0p1", Float.toHexString(2));
assertEquals("0x1.8p1", Float.toHexString(3));
assertEquals("0x1.0p-1", Float.toHexString(0.5f));
assertEquals("0x1.0p-2", Float.toHexString(0.25f));
assertEquals("0x1.0p-126", Float.toHexString(0x1.0p-126f));
assertEquals("0x0.001p-126", Float.toHexString(0x0.001p-126f));
}
}