mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Adds double decimal representation generator
This commit is contained in:
parent
59581d28d6
commit
a9bd61e463
|
@ -37,7 +37,7 @@
|
|||
</goals>
|
||||
<phase>process-test-classes</phase>
|
||||
<configuration>
|
||||
<minifying>true</minifying>
|
||||
<minifying>false</minifying>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
package org.teavm.classlib.java.lang;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.teavm.codegen.SourceWriter;
|
||||
import org.teavm.javascript.ni.Generator;
|
||||
import org.teavm.javascript.ni.GeneratorContext;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class DoubleNativeGenerator implements Generator {
|
||||
@Override
|
||||
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
|
||||
switch (methodRef.getName()) {
|
||||
case "isNaN":
|
||||
generateIsNaN(context, writer);
|
||||
break;
|
||||
case "isInfinite":
|
||||
generateIsInfinite(context, writer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void generateIsNaN(GeneratorContext context, SourceWriter writer) throws IOException {
|
||||
writer.append("return (isNaN(").append(context.getParameterName(1)).append(")").ws().append("?")
|
||||
.ws().append("1").ws().append(":").ws().append("0").ws().append(");").softNewLine();
|
||||
}
|
||||
|
||||
private void generateIsInfinite(GeneratorContext context, SourceWriter writer) throws IOException {
|
||||
writer.append("return (isFinite(").append(context.getParameterName(1)).append(")").ws().append("?")
|
||||
.ws().append("0").ws().append(":").ws().append("1").append(");").softNewLine();
|
||||
}
|
||||
}
|
|
@ -12,13 +12,24 @@ import org.teavm.javascript.ni.Rename;
|
|||
*/
|
||||
class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequence {
|
||||
private static final float[] powersOfTen = { 1E1f, 1E2f, 1E4f, 1E8f, 1E16f, 1E32f };
|
||||
private static final double[] doublePowersOfTen = { 1E1, 1E2, 1E4, 1E8, 1E16, 1E32, 1E64, 1E128, 1E256 };
|
||||
private static final float[] negPowersOfTen = { 1E-1f, 1E-2f, 1E-4f, 1E-8f, 1E-16f, 1E-32f };
|
||||
private static final double[] negDoublePowersOfTen = { 1E-1, 1E-2, 1E-4, 1E-8, 1E-16, 1E-32,
|
||||
1E-64, 1E-128, 1E-256 };
|
||||
private static final int[] intPowersOfTen = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000,
|
||||
1000000000 };
|
||||
private static final long[] longPowersOfTen = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000,
|
||||
1000000000, 10000000000L, 100000000000L, 1000000000000L, 10000000000000L, 100000000000000L,
|
||||
1000000000000000L, 10000000000000000L, 100000000000000000L, 1000000000000000000L };
|
||||
private static final long[] longLogPowersOfTen = { 1, 10, 100, 10000, 100000000, 10000000000000000L, };
|
||||
private static final int FLOAT_DECIMAL_PRECISION = 7;
|
||||
private static final int DOUBLE_DECIMAL_PRECISION = 16;
|
||||
private static final float FLOAT_DECIMAL_FACTOR = 1E6f;
|
||||
private static final double DOUBLE_DECIMAL_FACTOR = 1E15f;
|
||||
private static final int FLOAT_MAX_EXPONENT = 38;
|
||||
private static final int DOUBLE_MAX_EXPONENT = 308;
|
||||
private static final int FLOAT_MAX_POS = 1000000;
|
||||
private static final long DOUBLE_MAX_POS = 1000000000000000L;
|
||||
char[] buffer;
|
||||
int length;
|
||||
|
||||
|
@ -128,13 +139,13 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ
|
|||
buffer[length++] = '.';
|
||||
buffer[length++] = '0';
|
||||
return this;
|
||||
} else if (Float.isNaN(value)) {
|
||||
} else if (TFloat.isNaN(value)) {
|
||||
ensureCapacity(length + 3);
|
||||
buffer[length++] = 'N';
|
||||
buffer[length++] = 'a';
|
||||
buffer[length++] = 'N';
|
||||
return this;
|
||||
} else if (Float.isInfinite(value)) {
|
||||
} else if (TFloat.isInfinite(value)) {
|
||||
if (value > 0) {
|
||||
ensureCapacity(8);
|
||||
} else {
|
||||
|
@ -237,7 +248,6 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ
|
|||
intDigit = 0;
|
||||
}
|
||||
buffer[length++] = (char)('0' + intDigit);
|
||||
value = (value - intDigit) * 10;
|
||||
if (--intPart == 0) {
|
||||
buffer[length++] = '.';
|
||||
}
|
||||
|
@ -259,6 +269,157 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ
|
|||
return this;
|
||||
}
|
||||
|
||||
protected TAbstractStringBuilder append(double value) {
|
||||
if (value == 0) {
|
||||
ensureCapacity(length + 3);
|
||||
buffer[length++] = '0';
|
||||
buffer[length++] = '.';
|
||||
buffer[length++] = '0';
|
||||
return this;
|
||||
} else if (value == -0) {
|
||||
ensureCapacity(length + 4);
|
||||
buffer[length++] = '-';
|
||||
buffer[length++] = '0';
|
||||
buffer[length++] = '.';
|
||||
buffer[length++] = '0';
|
||||
return this;
|
||||
} else if (TDouble.isNaN(value)) {
|
||||
ensureCapacity(length + 3);
|
||||
buffer[length++] = 'N';
|
||||
buffer[length++] = 'a';
|
||||
buffer[length++] = 'N';
|
||||
return this;
|
||||
} else if (TDouble.isInfinite(value)) {
|
||||
if (value > 0) {
|
||||
ensureCapacity(8);
|
||||
} else {
|
||||
ensureCapacity(9);
|
||||
buffer[length++] = '-';
|
||||
}
|
||||
buffer[length++] = 'I';
|
||||
buffer[length++] = 'n';
|
||||
buffer[length++] = 'f';
|
||||
buffer[length++] = 'i';
|
||||
buffer[length++] = 'n';
|
||||
buffer[length++] = 'i';
|
||||
buffer[length++] = 't';
|
||||
buffer[length++] = 'y';
|
||||
return this;
|
||||
}
|
||||
// Get absolute value
|
||||
boolean negative = false;
|
||||
int sz = 1; // Decimal point always included
|
||||
if (value < 0) {
|
||||
negative = true;
|
||||
value = -value;
|
||||
++sz; // including '-' sign of mantissa
|
||||
}
|
||||
|
||||
// Split into decimal mantissa and decimal exponent
|
||||
int exp = 0;
|
||||
long mantissa = 0;
|
||||
int intPart = 1;
|
||||
int digits = 0;
|
||||
if (value >= 1) {
|
||||
int bit = 256;
|
||||
exp = 0;
|
||||
double digit = 1;
|
||||
for (int i = doublePowersOfTen.length - 1; i >= 0; --i) {
|
||||
if ((exp | bit) <= DOUBLE_MAX_EXPONENT && doublePowersOfTen[i] * digit < value) {
|
||||
digit *= doublePowersOfTen[i];
|
||||
exp |= bit;
|
||||
}
|
||||
bit >>= 1;
|
||||
}
|
||||
mantissa = (long)((value / (digit / DOUBLE_DECIMAL_FACTOR)) + 0.5f);
|
||||
} else {
|
||||
++sz;
|
||||
int bit = 256;
|
||||
exp = 0;
|
||||
double digit = 1;
|
||||
for (int i = negDoublePowersOfTen.length - 1; i >= 0; --i) {
|
||||
if ((exp | bit) <= DOUBLE_MAX_EXPONENT && negDoublePowersOfTen[i] * digit * 10 > value) {
|
||||
digit *= negPowersOfTen[i];
|
||||
exp |= bit;
|
||||
}
|
||||
bit >>= 1;
|
||||
}
|
||||
exp = -exp;
|
||||
mantissa = (long)(((value * DOUBLE_MAX_POS) / digit) + 0.5f);
|
||||
}
|
||||
|
||||
// Remove trailing zeros
|
||||
digits = DOUBLE_DECIMAL_PRECISION;
|
||||
int zeros = trailingDecimalZeros(mantissa);
|
||||
if (zeros > 0) {
|
||||
digits -= zeros;
|
||||
}
|
||||
|
||||
// Handle special case of exponent close to 0
|
||||
if (exp < 7 && exp >= -3) {
|
||||
if (exp >= 0) {
|
||||
intPart = exp + 1;
|
||||
digits = Math.max(digits, intPart + 1);
|
||||
exp = 0;
|
||||
} else if (exp < 0) {
|
||||
mantissa /= longPowersOfTen[-exp];
|
||||
digits -= exp;
|
||||
exp = 0;
|
||||
}
|
||||
}
|
||||
sz += digits;
|
||||
|
||||
// Extend buffer to store exponent
|
||||
if (exp != 0) {
|
||||
sz += 2;
|
||||
if (exp < 10 || exp > 10) {
|
||||
++sz;
|
||||
}
|
||||
if (exp < 100 || exp > 100) {
|
||||
++sz;
|
||||
}
|
||||
}
|
||||
|
||||
// Print mantissa
|
||||
ensureCapacity(length + sz);
|
||||
if (negative) {
|
||||
buffer[length++] = '-';
|
||||
}
|
||||
long pos = DOUBLE_MAX_POS;
|
||||
for (int i = 0; i < digits; ++i) {
|
||||
int intDigit;
|
||||
if (pos > 0) {
|
||||
intDigit = (int)(mantissa / pos);
|
||||
mantissa %= pos;
|
||||
} else {
|
||||
intDigit = 0;
|
||||
}
|
||||
buffer[length++] = (char)('0' + intDigit);
|
||||
if (--intPart == 0) {
|
||||
buffer[length++] = '.';
|
||||
}
|
||||
pos /= 10;
|
||||
}
|
||||
|
||||
// Print exponent
|
||||
if (exp != 0) {
|
||||
buffer[length++] = 'E';
|
||||
if (exp < 0) {
|
||||
exp = -exp;
|
||||
buffer[length++] = '-';
|
||||
}
|
||||
if (exp > 100) {
|
||||
buffer[length++] = (char)('0' + exp / 100);
|
||||
exp %= 100;
|
||||
}
|
||||
if (exp > 10) {
|
||||
buffer[length++] = (char)('0' + exp / 10);
|
||||
}
|
||||
buffer[length++] = (char)('0' + exp % 10);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private static int trailingDecimalZeros(int n) {
|
||||
if (n % 1000000000 == 0) {
|
||||
return 9;
|
||||
|
@ -283,6 +444,20 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ
|
|||
return result;
|
||||
}
|
||||
|
||||
private static int trailingDecimalZeros(long n) {
|
||||
long zeros = 1;
|
||||
int result = 0;
|
||||
int bit = 16;
|
||||
for (int i = longLogPowersOfTen.length - 1; i >= 0; --i) {
|
||||
if (n % zeros == 0) {
|
||||
result |= bit;
|
||||
zeros *= longLogPowersOfTen[i];
|
||||
}
|
||||
bit >>>= 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected TAbstractStringBuilder append(char c) {
|
||||
ensureCapacity(length + 1);
|
||||
buffer[length++] = c;
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package org.teavm.classlib.java.lang;
|
||||
|
||||
import org.teavm.javascript.ni.GeneratedBy;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class TDouble {
|
||||
@GeneratedBy(DoubleNativeGenerator.class)
|
||||
public static native boolean isNaN(double v);
|
||||
|
||||
@GeneratedBy(DoubleNativeGenerator.class)
|
||||
public static native boolean isInfinite(double v);
|
||||
}
|
|
@ -29,6 +29,12 @@ public class TStringBuilder extends TAbstractStringBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TStringBuilder append(double value) {
|
||||
super.append(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TStringBuilder append(char c) {
|
||||
super.append(c);
|
||||
|
|
|
@ -190,6 +190,13 @@ public class StringBuilderTest {
|
|||
assertEquals("-Infinity", sb.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doubleAppended() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(1.2345678E150);
|
||||
assertEquals("1.2345678E150", sb.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appendsCodePoint() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
|
Loading…
Reference in New Issue
Block a user