mirror of
https://github.com/corda/corda.git
synced 2025-03-03 12:57:29 +00:00
implement various floating point instructions; fix Floats.java to actually test something
This commit is contained in:
parent
659555b6ce
commit
5f6258045e
2
makefile
2
makefile
@ -34,7 +34,7 @@ src = src
|
||||
classpath = classpath
|
||||
test = test
|
||||
|
||||
input = $(cls)/GC.class
|
||||
input = $(cls)/Floats.class
|
||||
|
||||
cxx = g++
|
||||
cc = gcc
|
||||
|
@ -374,29 +374,25 @@ Java_java_lang_reflect_Array_makeObjectArray
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_java_lang_Float_floatToRawIntBits(Thread*, jclass, jfloat v)
|
||||
{
|
||||
int32_t r; memcpy(&r, &v, 4);
|
||||
return r;
|
||||
return floatToBits(v);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jfloat JNICALL
|
||||
Java_java_lang_Float_intBitsToFloat(Thread*, jclass, jint v)
|
||||
{
|
||||
jfloat r; memcpy(&r, &v, 4);
|
||||
return r;
|
||||
return bitsToFloat(v);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
Java_java_lang_Double_doubleToRawLongBits(Thread*, jclass, jdouble v)
|
||||
{
|
||||
int64_t r; memcpy(&r, &v, 8);
|
||||
return r;
|
||||
return doubleToBits(v);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jdouble JNICALL
|
||||
Java_java_lang_Double_longBitsToDouble(Thread*, jclass, jlong v)
|
||||
{
|
||||
jdouble r; memcpy(&r, &v, 8);
|
||||
return r;
|
||||
return bitsToDouble(v);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jobject JNICALL
|
||||
|
28
src/common.h
28
src/common.h
@ -196,6 +196,34 @@ hash(const uint16_t* s, unsigned length)
|
||||
return h;
|
||||
}
|
||||
|
||||
inline uint32_t
|
||||
floatToBits(float f)
|
||||
{
|
||||
int32_t bits; memcpy(&bits, &f, 4);
|
||||
return bits;
|
||||
}
|
||||
|
||||
inline uint64_t
|
||||
doubleToBits(double d)
|
||||
{
|
||||
int64_t bits; memcpy(&bits, &d, 8);
|
||||
return bits;
|
||||
}
|
||||
|
||||
inline double
|
||||
bitsToDouble(uint64_t bits)
|
||||
{
|
||||
double d; memcpy(&d, &bits, 8);
|
||||
return d;
|
||||
}
|
||||
|
||||
inline float
|
||||
bitsToFloat(uint32_t bits)
|
||||
{
|
||||
float f; memcpy(&f, &bits, 4);
|
||||
return f;
|
||||
}
|
||||
|
||||
class Machine;
|
||||
class Thread;
|
||||
|
||||
|
385
src/compile.cpp
385
src/compile.cpp
@ -980,14 +980,142 @@ visitStack(MyThread* t, Heap::Visitor* v)
|
||||
}
|
||||
}
|
||||
|
||||
intptr_t
|
||||
compareDoublesG(uint64_t bi, uint64_t ai)
|
||||
{
|
||||
double a = bitsToDouble(ai);
|
||||
double b = bitsToDouble(bi);
|
||||
|
||||
if (a < b) {
|
||||
return -1;
|
||||
} else if (a > b) {
|
||||
return 1;
|
||||
} else if (a == b) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
intptr_t
|
||||
compareDoublesL(uint64_t bi, uint64_t ai)
|
||||
{
|
||||
double a = bitsToDouble(ai);
|
||||
double b = bitsToDouble(bi);
|
||||
|
||||
if (a < b) {
|
||||
return -1;
|
||||
} else if (a > b) {
|
||||
return 1;
|
||||
} else if (a == b) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
intptr_t
|
||||
compareFloatsG(uint32_t bi, uint32_t ai)
|
||||
{
|
||||
float a = bitsToFloat(ai);
|
||||
float b = bitsToFloat(bi);
|
||||
|
||||
if (a < b) {
|
||||
return -1;
|
||||
} else if (a > b) {
|
||||
return 1;
|
||||
} else if (a == b) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
intptr_t
|
||||
compareFloatsL(uint32_t bi, uint32_t ai)
|
||||
{
|
||||
float a = bitsToFloat(ai);
|
||||
float b = bitsToFloat(bi);
|
||||
|
||||
if (a < b) {
|
||||
return -1;
|
||||
} else if (a > b) {
|
||||
return 1;
|
||||
} else if (a == b) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t
|
||||
addDouble(uint64_t b, uint64_t a)
|
||||
{
|
||||
return doubleToBits(bitsToDouble(a) + bitsToDouble(b));
|
||||
}
|
||||
|
||||
uint64_t
|
||||
subtractDouble(uint64_t b, uint64_t a)
|
||||
{
|
||||
return doubleToBits(bitsToDouble(a) - bitsToDouble(b));
|
||||
}
|
||||
|
||||
uint64_t
|
||||
multiplyDouble(uint64_t b, uint64_t a)
|
||||
{
|
||||
return doubleToBits(bitsToDouble(a) * bitsToDouble(b));
|
||||
}
|
||||
|
||||
uint64_t
|
||||
divideDouble(uint64_t b, uint64_t a)
|
||||
{
|
||||
return doubleToBits(bitsToDouble(a) / bitsToDouble(b));
|
||||
}
|
||||
|
||||
uint64_t
|
||||
moduloDouble(uint64_t b, uint64_t a)
|
||||
{
|
||||
return doubleToBits(fmod(bitsToDouble(a), bitsToDouble(b)));
|
||||
}
|
||||
|
||||
uint32_t
|
||||
addFloat(uint32_t b, uint32_t a)
|
||||
{
|
||||
return floatToBits(bitsToFloat(a) + bitsToFloat(b));
|
||||
}
|
||||
|
||||
uint32_t
|
||||
subtractFloat(uint32_t b, uint32_t a)
|
||||
{
|
||||
return floatToBits(bitsToFloat(a) - bitsToFloat(b));
|
||||
}
|
||||
|
||||
uint32_t
|
||||
multiplyFloat(uint32_t b, uint32_t a)
|
||||
{
|
||||
return floatToBits(bitsToFloat(a) * bitsToFloat(b));
|
||||
}
|
||||
|
||||
uint32_t
|
||||
divideFloat(uint32_t b, uint32_t a)
|
||||
{
|
||||
return floatToBits(bitsToFloat(a) / bitsToFloat(b));
|
||||
}
|
||||
|
||||
uint32_t
|
||||
moduloFloat(uint32_t b, uint32_t a)
|
||||
{
|
||||
return floatToBits(fmod(bitsToFloat(a), bitsToFloat(b)));
|
||||
}
|
||||
|
||||
int64_t
|
||||
divideLong(MyThread*, int64_t a, int64_t b)
|
||||
divideLong(int64_t b, int64_t a)
|
||||
{
|
||||
return a / b;
|
||||
}
|
||||
|
||||
int64_t
|
||||
moduloLong(MyThread*, int64_t a, int64_t b)
|
||||
moduloLong(int64_t b, int64_t a)
|
||||
{
|
||||
return a % b;
|
||||
}
|
||||
@ -2550,11 +2678,241 @@ class JavaCompiler: public Compiler {
|
||||
next.mark();
|
||||
} break;
|
||||
|
||||
case dadd: {
|
||||
if (BytesPerWord == 8) {
|
||||
popLong(rdi);
|
||||
popLong(rsi);
|
||||
directCall(reinterpret_cast<void*>(addDouble));
|
||||
pushLong(rax);
|
||||
} else {
|
||||
directCall(reinterpret_cast<void*>(addDouble));
|
||||
add(BytesPerWord * 4, rsp);
|
||||
stackMapper.poppedLong();
|
||||
stackMapper.poppedLong();
|
||||
pushLong(rax, rdx);
|
||||
}
|
||||
} break;
|
||||
|
||||
case dcmpg: {
|
||||
if (BytesPerWord == 8) {
|
||||
popLong(rdi);
|
||||
popLong(rsi);
|
||||
directCall(reinterpret_cast<void*>(compareDoublesG));
|
||||
pushInt(rax);
|
||||
} else {
|
||||
directCall(reinterpret_cast<void*>(compareDoublesG));
|
||||
add(BytesPerWord * 4, rsp);
|
||||
stackMapper.poppedLong();
|
||||
stackMapper.poppedLong();
|
||||
pushInt(rax);
|
||||
}
|
||||
} break;
|
||||
|
||||
case dcmpl: {
|
||||
if (BytesPerWord == 8) {
|
||||
popLong(rdi);
|
||||
popLong(rsi);
|
||||
directCall(reinterpret_cast<void*>(compareDoublesL));
|
||||
pushInt(rax);
|
||||
} else {
|
||||
directCall(reinterpret_cast<void*>(compareDoublesL));
|
||||
add(BytesPerWord * 4, rsp);
|
||||
stackMapper.poppedLong();
|
||||
stackMapper.poppedLong();
|
||||
pushInt(rax);
|
||||
}
|
||||
} break;
|
||||
|
||||
case dconst_0: {
|
||||
pushLong(doubleToBits(0.0));
|
||||
} break;
|
||||
|
||||
case dconst_1: {
|
||||
pushLong(doubleToBits(1.0));
|
||||
} break;
|
||||
|
||||
case ddiv: {
|
||||
if (BytesPerWord == 8) {
|
||||
popLong(rdi);
|
||||
popLong(rsi);
|
||||
directCall(reinterpret_cast<void*>(divideDouble));
|
||||
pushLong(rax);
|
||||
} else {
|
||||
directCall(reinterpret_cast<void*>(divideDouble));
|
||||
add(BytesPerWord * 4, rsp);
|
||||
stackMapper.poppedLong();
|
||||
stackMapper.poppedLong();
|
||||
pushLong(rax, rdx);
|
||||
}
|
||||
} break;
|
||||
|
||||
case dmul: {
|
||||
if (BytesPerWord == 8) {
|
||||
popLong(rdi);
|
||||
popLong(rsi);
|
||||
directCall(reinterpret_cast<void*>(multiplyDouble));
|
||||
pushLong(rax);
|
||||
} else {
|
||||
directCall(reinterpret_cast<void*>(multiplyDouble));
|
||||
add(BytesPerWord * 4, rsp);
|
||||
stackMapper.poppedLong();
|
||||
stackMapper.poppedLong();
|
||||
pushLong(rax, rdx);
|
||||
}
|
||||
} break;
|
||||
|
||||
case vm::drem: {
|
||||
if (BytesPerWord == 8) {
|
||||
popLong(rdi);
|
||||
popLong(rsi);
|
||||
directCall(reinterpret_cast<void*>(moduloDouble));
|
||||
pushLong(rax);
|
||||
} else {
|
||||
directCall(reinterpret_cast<void*>(moduloDouble));
|
||||
add(BytesPerWord * 4, rsp);
|
||||
stackMapper.poppedLong();
|
||||
stackMapper.poppedLong();
|
||||
pushLong(rax, rdx);
|
||||
}
|
||||
} break;
|
||||
|
||||
case dsub: {
|
||||
if (BytesPerWord == 8) {
|
||||
popLong(rdi);
|
||||
popLong(rsi);
|
||||
directCall(reinterpret_cast<void*>(subtractDouble));
|
||||
pushLong(rax);
|
||||
} else {
|
||||
directCall(reinterpret_cast<void*>(subtractDouble));
|
||||
add(BytesPerWord * 4, rsp);
|
||||
stackMapper.poppedLong();
|
||||
stackMapper.poppedLong();
|
||||
pushLong(rax, rdx);
|
||||
}
|
||||
} break;
|
||||
|
||||
case dup:
|
||||
push(rsp, 0);
|
||||
stackMapper.dupped();
|
||||
break;
|
||||
|
||||
case fadd: {
|
||||
if (BytesPerWord == 8) {
|
||||
popInt(rdi);
|
||||
popInt(rsi);
|
||||
directCall(reinterpret_cast<void*>(addFloat));
|
||||
pushInt(rax);
|
||||
} else {
|
||||
directCall(reinterpret_cast<void*>(addFloat));
|
||||
add(BytesPerWord * 2, rsp);
|
||||
stackMapper.poppedInt();
|
||||
stackMapper.poppedInt();
|
||||
pushInt(rax);
|
||||
}
|
||||
} break;
|
||||
|
||||
case fcmpg: {
|
||||
if (BytesPerWord == 8) {
|
||||
popInt(rdi);
|
||||
popInt(rsi);
|
||||
directCall(reinterpret_cast<void*>(compareFloatsG));
|
||||
pushInt(rax);
|
||||
} else {
|
||||
directCall(reinterpret_cast<void*>(compareFloatsG));
|
||||
add(BytesPerWord * 2, rsp);
|
||||
stackMapper.poppedInt();
|
||||
stackMapper.poppedInt();
|
||||
pushInt(rax);
|
||||
}
|
||||
} break;
|
||||
|
||||
case fcmpl: {
|
||||
if (BytesPerWord == 8) {
|
||||
popInt(rdi);
|
||||
popInt(rsi);
|
||||
directCall(reinterpret_cast<void*>(compareFloatsL));
|
||||
pushInt(rax);
|
||||
} else {
|
||||
directCall(reinterpret_cast<void*>(compareFloatsL));
|
||||
add(BytesPerWord * 2, rsp);
|
||||
stackMapper.poppedInt();
|
||||
stackMapper.poppedInt();
|
||||
pushInt(rax);
|
||||
}
|
||||
} break;
|
||||
|
||||
case fconst_0: {
|
||||
pushInt(floatToBits(0.0));
|
||||
} break;
|
||||
|
||||
case fconst_1: {
|
||||
pushInt(floatToBits(1.0));
|
||||
} break;
|
||||
|
||||
case fconst_2: {
|
||||
pushInt(floatToBits(2.0));
|
||||
} break;
|
||||
|
||||
case fdiv: {
|
||||
if (BytesPerWord == 8) {
|
||||
popInt(rdi);
|
||||
popInt(rsi);
|
||||
directCall(reinterpret_cast<void*>(divideFloat));
|
||||
pushInt(rax);
|
||||
} else {
|
||||
directCall(reinterpret_cast<void*>(divideFloat));
|
||||
add(BytesPerWord * 2, rsp);
|
||||
stackMapper.poppedInt();
|
||||
stackMapper.poppedInt();
|
||||
pushInt(rax);
|
||||
}
|
||||
} break;
|
||||
|
||||
case fmul: {
|
||||
if (BytesPerWord == 8) {
|
||||
popInt(rdi);
|
||||
popInt(rsi);
|
||||
directCall(reinterpret_cast<void*>(multiplyFloat));
|
||||
pushInt(rax);
|
||||
} else {
|
||||
directCall(reinterpret_cast<void*>(multiplyFloat));
|
||||
add(BytesPerWord * 2, rsp);
|
||||
stackMapper.poppedInt();
|
||||
stackMapper.poppedInt();
|
||||
pushInt(rax);
|
||||
}
|
||||
} break;
|
||||
|
||||
case frem: {
|
||||
if (BytesPerWord == 8) {
|
||||
popInt(rdi);
|
||||
popInt(rsi);
|
||||
directCall(reinterpret_cast<void*>(moduloFloat));
|
||||
pushInt(rax);
|
||||
} else {
|
||||
directCall(reinterpret_cast<void*>(moduloFloat));
|
||||
add(BytesPerWord * 2, rsp);
|
||||
stackMapper.poppedInt();
|
||||
stackMapper.poppedInt();
|
||||
pushInt(rax);
|
||||
}
|
||||
} break;
|
||||
|
||||
case fsub: {
|
||||
if (BytesPerWord == 8) {
|
||||
popInt(rdi);
|
||||
popInt(rsi);
|
||||
directCall(reinterpret_cast<void*>(subtractFloat));
|
||||
pushInt(rax);
|
||||
} else {
|
||||
directCall(reinterpret_cast<void*>(subtractFloat));
|
||||
add(BytesPerWord * 2, rsp);
|
||||
stackMapper.poppedInt();
|
||||
stackMapper.poppedInt();
|
||||
pushInt(rax);
|
||||
}
|
||||
} break;
|
||||
|
||||
case getfield: {
|
||||
uint16_t index = codeReadInt16(t, code, ip);
|
||||
|
||||
@ -3222,22 +3580,27 @@ class JavaCompiler: public Compiler {
|
||||
break;
|
||||
|
||||
case lload:
|
||||
case dload:
|
||||
loadLong(codeBody(t, code, ip++));
|
||||
break;
|
||||
|
||||
case lload_0:
|
||||
case dload_0:
|
||||
loadLong(0);
|
||||
break;
|
||||
|
||||
case lload_1:
|
||||
case dload_1:
|
||||
loadLong(1);
|
||||
break;
|
||||
|
||||
case lload_2:
|
||||
case dload_2:
|
||||
loadLong(2);
|
||||
break;
|
||||
|
||||
case lload_3:
|
||||
case dload_3:
|
||||
loadLong(3);
|
||||
break;
|
||||
|
||||
@ -3293,23 +3656,41 @@ class JavaCompiler: public Compiler {
|
||||
}
|
||||
break;
|
||||
|
||||
case lreturn:
|
||||
case dreturn:
|
||||
if (BytesPerWord == 8) {
|
||||
popLong(rax);
|
||||
} else {
|
||||
popLong(rax, rdx);
|
||||
}
|
||||
mov(rbp, rsp);
|
||||
pop(rbp);
|
||||
ret();
|
||||
stackMapper.exited();
|
||||
break;
|
||||
|
||||
case lstore:
|
||||
case dstore:
|
||||
storeLong(codeBody(t, code, ip++));
|
||||
break;
|
||||
|
||||
case lstore_0:
|
||||
case dstore_0:
|
||||
storeLong(0);
|
||||
break;
|
||||
|
||||
case lstore_1:
|
||||
case dstore_1:
|
||||
storeLong(1);
|
||||
break;
|
||||
|
||||
case lstore_2:
|
||||
case dstore_2:
|
||||
storeLong(2);
|
||||
break;
|
||||
|
||||
case lstore_3:
|
||||
case dstore_3:
|
||||
storeLong(3);
|
||||
break;
|
||||
|
||||
|
@ -64,8 +64,7 @@ pushInt(Thread* t, uint32_t v)
|
||||
inline void
|
||||
pushFloat(Thread* t, float v)
|
||||
{
|
||||
uint32_t a; memcpy(&a, &v, sizeof(uint32_t));
|
||||
pushInt(t, a);
|
||||
pushInt(t, floatToBits(v));
|
||||
}
|
||||
|
||||
inline void
|
||||
@ -82,8 +81,7 @@ pushLong(Thread* t, uint64_t v)
|
||||
inline void
|
||||
pushDouble(Thread* t, double v)
|
||||
{
|
||||
uint64_t a; memcpy(&a, &v, sizeof(uint64_t));
|
||||
pushLong(t, a);
|
||||
pushLong(t, doubleToBits(v));
|
||||
}
|
||||
|
||||
inline object
|
||||
@ -115,9 +113,7 @@ popInt(Thread* t)
|
||||
inline float
|
||||
popFloat(Thread* t)
|
||||
{
|
||||
uint32_t a = popInt(t);
|
||||
float f; memcpy(&f, &a, sizeof(float));
|
||||
return f;
|
||||
return bitsToFloat(popInt(t));
|
||||
}
|
||||
|
||||
inline uint64_t
|
||||
@ -138,9 +134,7 @@ popLong(Thread* t)
|
||||
inline float
|
||||
popDouble(Thread* t)
|
||||
{
|
||||
uint64_t a = popLong(t);
|
||||
double d; memcpy(&d, &a, sizeof(double));
|
||||
return d;
|
||||
return bitsToDouble(popLong(t));
|
||||
}
|
||||
|
||||
inline object
|
||||
@ -1072,9 +1066,7 @@ interpret(Thread* t)
|
||||
if (LIKELY(index >= 0 and
|
||||
static_cast<uintptr_t>(index) < doubleArrayLength(t, array)))
|
||||
{
|
||||
double d;
|
||||
memcpy(&d, &doubleArrayBody(t, array, index), sizeof(double));
|
||||
pushDouble(t, d);
|
||||
pushLong(t, doubleArrayBody(t, array, index));
|
||||
} else {
|
||||
object message = makeString(t, "%d not in [0,%d)", index,
|
||||
doubleArrayLength(t, array));
|
||||
@ -1113,14 +1105,30 @@ interpret(Thread* t)
|
||||
double b = popDouble(t);
|
||||
double a = popDouble(t);
|
||||
|
||||
pushInt(t, (a > b ? 1 : 0));
|
||||
if (a < b) {
|
||||
pushInt(t, static_cast<unsigned>(-1));
|
||||
} else if (a > b) {
|
||||
pushInt(t, 1);
|
||||
} else if (a == b) {
|
||||
pushInt(t, 0);
|
||||
} else {
|
||||
pushInt(t, 1);
|
||||
}
|
||||
} goto loop;
|
||||
|
||||
case dcmpl: {
|
||||
double b = popDouble(t);
|
||||
double a = popDouble(t);
|
||||
|
||||
pushInt(t, (a < b ? 1 : 0));
|
||||
if (a < b) {
|
||||
pushInt(t, static_cast<unsigned>(-1));
|
||||
} else if (a > b) {
|
||||
pushInt(t, 1);
|
||||
} else if (a == b) {
|
||||
pushInt(t, 0);
|
||||
} else {
|
||||
pushInt(t, static_cast<unsigned>(-1));
|
||||
}
|
||||
} goto loop;
|
||||
|
||||
case dconst_0: {
|
||||
@ -1258,8 +1266,7 @@ interpret(Thread* t)
|
||||
if (LIKELY(index >= 0 and
|
||||
static_cast<uintptr_t>(index) < floatArrayLength(t, array)))
|
||||
{
|
||||
float f; memcpy(&f, &floatArrayBody(t, array, index), sizeof(float));
|
||||
pushFloat(t, f);
|
||||
pushInt(t, floatArrayBody(t, array, index));
|
||||
} else {
|
||||
object message = makeString(t, "%d not in [0,%d)", index,
|
||||
floatArrayLength(t, array));
|
||||
@ -1467,15 +1474,11 @@ interpret(Thread* t)
|
||||
} goto loop;
|
||||
|
||||
case i2d: {
|
||||
double f = static_cast<double>(popInt(t));
|
||||
int64_t i; memcpy(&i, &f, 8);
|
||||
pushLong(t, i);
|
||||
pushDouble(t, static_cast<double>(popInt(t)));
|
||||
} goto loop;
|
||||
|
||||
case i2f: {
|
||||
float f = static_cast<float>(popInt(t));
|
||||
int32_t i; memcpy(&i, &f, 4);
|
||||
pushInt(t, i);
|
||||
pushFloat(t, static_cast<float>(popInt(t)));
|
||||
} goto loop;
|
||||
|
||||
case i2l: {
|
||||
@ -2689,10 +2692,7 @@ pushArguments(Thread* t, object this_, const char* spec, bool indirectObjects,
|
||||
|
||||
case 'F': {
|
||||
++ s;
|
||||
float f = va_arg(a, double);
|
||||
uint32_t i;
|
||||
memcpy(&i, &f, 4);
|
||||
pushInt(t, i);
|
||||
pushFloat(t, va_arg(a, double));
|
||||
} break;
|
||||
|
||||
default:
|
||||
|
@ -531,7 +531,7 @@ parsePool(Thread* t, Stream& s)
|
||||
} break;
|
||||
|
||||
case CONSTANT_Double: {
|
||||
object value = makeLong(t, s.readDouble());
|
||||
object value = makeDouble(t, s.readDouble());
|
||||
set(t, arrayBody(t, pool, i), value);
|
||||
++i;
|
||||
} break;
|
||||
|
@ -3,18 +3,34 @@ public class Floats {
|
||||
if (! v) throw new RuntimeException();
|
||||
}
|
||||
|
||||
private static double multiply(double a, double b) {
|
||||
return a * b;
|
||||
}
|
||||
|
||||
private static float multiply(float a, float b) {
|
||||
return a * b;
|
||||
}
|
||||
|
||||
private static double divide(double a, double b) {
|
||||
return a / b;
|
||||
}
|
||||
|
||||
private static double subtract(double a, double b) {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
expect(0.5d * 0.5d == 0.25d);
|
||||
expect(0.5f * 0.5f == 0.25f);
|
||||
expect(multiply(0.5d, 0.5d) == 0.25d);
|
||||
expect(multiply(0.5f, 0.5f) == 0.25f);
|
||||
|
||||
expect(0.5d * 0.5d < 0.5d);
|
||||
expect(0.5f * 0.5f < 0.5f);
|
||||
expect(multiply(0.5d, 0.5d) < 0.5d);
|
||||
expect(multiply(0.5f, 0.5f) < 0.5f);
|
||||
|
||||
expect(0.5d * 0.5d > 0.1d);
|
||||
expect(0.5f * 0.5f > 0.1f);
|
||||
expect(multiply(0.5d, 0.5d) > 0.1d);
|
||||
expect(multiply(0.5f, 0.5f) > 0.1f);
|
||||
|
||||
expect(0.5d / 0.5d == 1.0d);
|
||||
expect(divide(0.5d, 0.5d) == 1.0d);
|
||||
|
||||
expect(0.5d - 0.5d == 0.0d);
|
||||
expect(subtract(0.5d, 0.5d) == 0.0d);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user