mirror of
https://github.com/corda/corda.git
synced 2025-01-19 11:16:54 +00:00
fix float to integer conversion
Java requires that NaNs be converted to zero and that numbers at or beyond the limits of integer representation be clamped to the largest or smallest value that can be represented, respectively.
This commit is contained in:
parent
47503854d5
commit
b98abe3f94
@ -14,6 +14,10 @@ public final class Float extends Number {
|
||||
public static final Class TYPE = Class.forCanonicalName("F");
|
||||
private static final int EXP_BIT_MASK = 0x7F800000;
|
||||
private static final int SIGNIF_BIT_MASK = 0x007FFFFF;
|
||||
|
||||
public static final float NEGATIVE_INFINITY = -1.0f / 0.0f;
|
||||
public static final float POSITIVE_INFINITY = 1.0f / 0.0f;
|
||||
public static final float NaN = 0.0f / 0.0f;
|
||||
|
||||
private final float value;
|
||||
|
||||
|
@ -2379,7 +2379,11 @@ class MyArchitecture: public Assembler::Architecture {
|
||||
break;
|
||||
|
||||
case Float2Int:
|
||||
if (vfpSupported() && bSize == 4) {
|
||||
// todo: Java requires different semantics than SSE for
|
||||
// converting floats to integers, we we need to either use
|
||||
// thunks or produce inline machine code which handles edge
|
||||
// cases properly.
|
||||
if (false && vfpSupported() && bSize == 4) {
|
||||
*aTypeMask = (1 << RegisterOperand);
|
||||
*aRegisterMask = FPR_MASK64;
|
||||
} else {
|
||||
|
@ -2587,13 +2587,25 @@ doubleToFloat(int64_t a)
|
||||
int64_t
|
||||
doubleToInt(int64_t a)
|
||||
{
|
||||
return static_cast<int32_t>(bitsToDouble(a));
|
||||
double f = bitsToDouble(a);
|
||||
switch (fpclassify(f)) {
|
||||
case FP_NAN: return 0;
|
||||
case FP_INFINITE: return isinf(f) == 1 ? INT32_MAX : INT32_MIN;
|
||||
default: return f >= INT32_MAX ? INT32_MAX
|
||||
: (f <= INT32_MIN ? INT32_MIN : static_cast<int32_t>(f));
|
||||
}
|
||||
}
|
||||
|
||||
int64_t
|
||||
doubleToLong(int64_t a)
|
||||
{
|
||||
return static_cast<int64_t>(bitsToDouble(a));
|
||||
double f = bitsToDouble(a);
|
||||
switch (fpclassify(f)) {
|
||||
case FP_NAN: return 0;
|
||||
case FP_INFINITE: return isinf(f) == 1 ? INT64_MAX : INT64_MIN;
|
||||
default: return f >= INT64_MAX ? INT64_MAX
|
||||
: (f <= INT64_MIN ? INT64_MIN : static_cast<int64_t>(f));
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t
|
||||
@ -2735,13 +2747,24 @@ floatToDouble(int32_t a)
|
||||
int64_t
|
||||
floatToInt(int32_t a)
|
||||
{
|
||||
return static_cast<int32_t>(bitsToFloat(a));
|
||||
float f = bitsToFloat(a);
|
||||
switch (fpclassify(f)) {
|
||||
case FP_NAN: return 0;
|
||||
case FP_INFINITE: return isinf(f) == 1 ? INT32_MAX : INT32_MIN;
|
||||
default: return f >= INT32_MAX ? INT32_MAX
|
||||
: (f <= INT32_MIN ? INT32_MIN : static_cast<int32_t>(f));
|
||||
}
|
||||
}
|
||||
|
||||
int64_t
|
||||
floatToLong(int32_t a)
|
||||
{
|
||||
return static_cast<int64_t>(bitsToFloat(a));
|
||||
float f = bitsToFloat(a);
|
||||
switch (fpclassify(f)) {
|
||||
case FP_NAN: return 0;
|
||||
case FP_INFINITE: return isinf(f) == 1 ? INT64_MAX : INT64_MIN;
|
||||
default: return static_cast<int64_t>(f);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t
|
||||
|
@ -1078,11 +1078,28 @@ interpret3(Thread* t, const int base)
|
||||
} goto loop;
|
||||
|
||||
case d2i: {
|
||||
pushInt(t, static_cast<int32_t>(popDouble(t)));
|
||||
double f = popDouble(t);
|
||||
switch (fpclassify(f)) {
|
||||
case FP_NAN: pushInt(t, 0); break;
|
||||
case FP_INFINITE: pushInt(t, isinf(f) == 1 ? INT32_MAX : INT32_MIN); break;
|
||||
default: pushInt
|
||||
(t, f >= INT32_MAX ? INT32_MAX
|
||||
: (f <= INT32_MIN ? INT32_MIN : static_cast<int32_t>(f)));
|
||||
break;
|
||||
}
|
||||
} goto loop;
|
||||
|
||||
case d2l: {
|
||||
pushLong(t, static_cast<int64_t>(popDouble(t)));
|
||||
double f = popDouble(t);
|
||||
switch (fpclassify(f)) {
|
||||
case FP_NAN: pushLong(t, 0); break;
|
||||
case FP_INFINITE: pushLong(t, isinf(f) == 1 ? INT64_MAX : INT64_MIN);
|
||||
break;
|
||||
default: pushLong
|
||||
(t, f >= INT64_MAX ? INT64_MAX
|
||||
: (f <= INT64_MIN ? INT64_MIN : static_cast<int64_t>(f)));
|
||||
break;
|
||||
}
|
||||
} goto loop;
|
||||
|
||||
case dadd: {
|
||||
@ -1278,11 +1295,24 @@ interpret3(Thread* t, const int base)
|
||||
} goto loop;
|
||||
|
||||
case f2i: {
|
||||
pushInt(t, static_cast<int32_t>(popFloat(t)));
|
||||
float f = popFloat(t);
|
||||
switch (fpclassify(f)) {
|
||||
case FP_NAN: pushInt(t, 0); break;
|
||||
case FP_INFINITE: pushInt(t, isinf(f) == 1 ? INT32_MAX : INT32_MIN); break;
|
||||
default: pushInt(t, f >= INT32_MAX ? INT32_MAX
|
||||
: (f <= INT32_MIN ? INT32_MIN : static_cast<int32_t>(f)));
|
||||
break;
|
||||
}
|
||||
} goto loop;
|
||||
|
||||
case f2l: {
|
||||
pushLong(t, static_cast<int64_t>(popFloat(t)));
|
||||
float f = popFloat(t);
|
||||
switch (fpclassify(f)) {
|
||||
case FP_NAN: pushLong(t, 0); break;
|
||||
case FP_INFINITE: pushLong(t, isinf(f) == 1 ? INT64_MAX : INT64_MIN);
|
||||
break;
|
||||
default: pushLong(t, static_cast<int64_t>(f)); break;
|
||||
}
|
||||
} goto loop;
|
||||
|
||||
case fadd: {
|
||||
|
@ -3064,7 +3064,11 @@ class MyArchitecture: public Assembler::Architecture {
|
||||
break;
|
||||
|
||||
case Float2Int:
|
||||
if (useSSE(&c) and bSize <= TargetBytesPerWord) {
|
||||
// todo: Java requires different semantics than SSE for
|
||||
// converting floats to integers, we we need to either use
|
||||
// thunks or produce inline machine code which handles edge
|
||||
// cases properly.
|
||||
if (false and useSSE(&c) and bSize <= TargetBytesPerWord) {
|
||||
*aTypeMask = (1 << RegisterOperand) | (1 << MemoryOperand);
|
||||
*aRegisterMask = (static_cast<uint64_t>(FloatRegisterMask) << 32)
|
||||
| FloatRegisterMask;
|
||||
|
@ -272,5 +272,62 @@ public class Floats {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{ double v = Double.NaN;
|
||||
expect(0 == (int) v); }
|
||||
|
||||
{ double v = Double.NEGATIVE_INFINITY;
|
||||
expect(Integer.MIN_VALUE == (int) v); }
|
||||
|
||||
{ double v = Long.MIN_VALUE;
|
||||
expect(Integer.MIN_VALUE == (int) v); }
|
||||
|
||||
{ double v = Double.POSITIVE_INFINITY;
|
||||
expect(Integer.MAX_VALUE == (int) v); }
|
||||
|
||||
{ double v = Long.MAX_VALUE;
|
||||
expect(Integer.MAX_VALUE == (int) v); }
|
||||
|
||||
{ float v = Float.NaN;
|
||||
expect(0 == (int) v); }
|
||||
|
||||
{ float v = Float.NEGATIVE_INFINITY;
|
||||
expect(Integer.MIN_VALUE == (int) v); }
|
||||
|
||||
{ float v = Integer.MIN_VALUE;
|
||||
expect(Integer.MIN_VALUE == (int) v); }
|
||||
|
||||
{ float v = Float.POSITIVE_INFINITY;
|
||||
expect(Integer.MAX_VALUE == (int) v); }
|
||||
|
||||
{ float v = Integer.MAX_VALUE;
|
||||
expect(Integer.MAX_VALUE == (int) v); }
|
||||
|
||||
{ double v = Double.NaN;
|
||||
expect(0 == (long) v); }
|
||||
|
||||
{ double v = Double.NEGATIVE_INFINITY;
|
||||
expect(Long.MIN_VALUE == (long) v); }
|
||||
|
||||
{ double v = Long.MIN_VALUE;
|
||||
expect(Long.MIN_VALUE == (long) v); }
|
||||
|
||||
{ double v = Double.POSITIVE_INFINITY;
|
||||
expect(Long.MAX_VALUE == (long) v); }
|
||||
|
||||
{ double v = Long.MAX_VALUE;
|
||||
expect(Long.MAX_VALUE == (long) v); }
|
||||
|
||||
{ float v = Float.NaN;
|
||||
expect(0 == (long) v); }
|
||||
|
||||
{ float v = Float.NEGATIVE_INFINITY;
|
||||
expect(Long.MIN_VALUE == (long) v); }
|
||||
|
||||
{ float v = Integer.MIN_VALUE;
|
||||
expect(Integer.MIN_VALUE == (long) v); }
|
||||
|
||||
{ float v = Float.POSITIVE_INFINITY;
|
||||
expect(Long.MAX_VALUE == (long) v); }
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user