package php.runtime.memory; import php.runtime.Memory; import php.runtime.memory.support.MemoryStringUtils; import java.nio.charset.Charset; import java.util.Locale; public class DoubleMemory extends Memory { double value; public DoubleMemory(double value) { super(Type.DOUBLE); this.value = value; } public static Memory valueOf(double value){ return new DoubleMemory(value); } public static Memory valueOf(float value){ return new DoubleMemory(value); } @Override public long toLong() { if (value == Double.POSITIVE_INFINITY) { return 0; } return (long) value; } @Override public double toDouble() { return value; } @Override public boolean toBoolean() { return value != 0.0; } @Override public String toString() { long longValue = (long) value; double abs = value < 0 ? - value : value; int exp = (int) Math.log10(abs); // php/0c02 if (longValue == value && exp < 18) { return longValue > Integer.MAX_VALUE ? Double.toString(longValue) : String.valueOf(longValue); } if (-5 < exp && exp < 18) { int pr = 13; char[] tmp = Double.toString(value).toCharArray(); for(int i = 0; i < tmp.length; i++){ switch (tmp[i]){ case '-': if (i == 0) continue; else break; case '0': pr += 1; case '.': continue; } break; } int digits = pr - exp; if (digits > pr) { digits = pr; } else if (digits < 0) { digits = 0; } String v = String.format(Locale.ENGLISH, "%." + digits + "f", value); int len = v.length(); int nonzero = -1; boolean dot = false; int i = len - 1; for(; i >= 0; i--){ char ch = v.charAt(i); if (ch == '.') dot = true; if (ch != '0' && nonzero < 0){ nonzero = ch == '.' ? i - 1 : i; } } if (dot && nonzero > 0) { return v.substring(0, nonzero + 1); } else { return v; } } else { return String.format(Locale.ENGLISH, "%.13E", value); } } @Override public Memory inc() { return new DoubleMemory(value + 1); } @Override public Memory dec() { return new DoubleMemory(value - 1); } @Override public Memory negative() { return new DoubleMemory(- value); } @Override public Memory toNumeric(){ return this; } @Override public Memory plus(Memory memory) { switch (memory.type){ case INT: return new DoubleMemory(value + ((LongMemory)memory).value); case DOUBLE: return new DoubleMemory(value + ((DoubleMemory)memory).value); case REFERENCE: return plus(memory.toValue()); default: return plus(memory.toNumeric()); } } @Override public Memory minus(Memory memory) { switch (memory.type){ case INT: return new DoubleMemory(value - ((LongMemory)memory).value); case DOUBLE: return new DoubleMemory(value - ((DoubleMemory)memory).value); case REFERENCE: return minus(memory.toValue()); default: return minus(memory.toNumeric()); } } @Override public Memory mul(Memory memory) { switch (memory.type){ case INT: return new DoubleMemory(value * ((LongMemory)memory).value); case DOUBLE: return new DoubleMemory(value * ((DoubleMemory)memory).value); case REFERENCE: return mul(memory.toValue()); default: return mul(memory.toNumeric()); } } @Override public Memory pow(Memory memory) { switch (memory.type){ case INT: return new DoubleMemory(Math.pow(value, ((LongMemory)memory).value)); case DOUBLE: return new DoubleMemory(Math.pow(value, ((LongMemory)memory).value)); case REFERENCE: return mul(memory.toImmutable()); default: return pow(memory.toNumeric()); } } @Override public Memory div(Memory memory) { switch (memory.type){ case INT: if (((LongMemory)memory).value == 0) return FALSE; return new DoubleMemory(value / ((LongMemory)memory).value); case DOUBLE: if (((DoubleMemory)memory).value == 0) return FALSE; return new DoubleMemory(value / ((DoubleMemory)memory).value); case REFERENCE: return div(memory.toValue()); default: return div(memory.toNumeric()); } } @Override public boolean equal(Memory memory) { switch (memory.type){ case INT: return almostEqual(value, ((LongMemory)memory).value); case DOUBLE: return almostEqual(value, ((DoubleMemory)memory).value); case REFERENCE: return equal(memory.toValue()); default: return almostEqual(value, memory.toDouble()); } } @Override public boolean identical(Memory memory) { return memory.getRealType() == Type.DOUBLE && ((DoubleMemory)memory).value == value; } @Override public boolean equal(double value) { return almostEqual(this.value, value); } @Override public boolean equal(long value) { return almostEqual(this.value, value); } @Override public boolean notEqual(Memory memory) { return !equal(memory); } @Override public boolean not() { return almostEqual(this.value, 0.0); } @Override public String concat(Memory memory) { return toString().concat(memory.toString()); } @Override public boolean smaller(Memory memory) { switch (memory.type){ case DOUBLE: return value < ((DoubleMemory)memory).value; case INT: return value < ((LongMemory)memory).value; case REFERENCE: return smaller(memory.toValue()); default: return smaller(memory.toDouble()); } } @Override public boolean smallerEq(Memory memory) { return smaller(memory) || equal(memory); } @Override public boolean greater(Memory memory) { return memory.smaller(this); } @Override public boolean greaterEq(Memory memory) { return memory.smallerEq(this); } @Override public Memory minus(long value) { return new DoubleMemory(this.value - value); } @Override public Memory plus(long value) { return new DoubleMemory(this.value + value); } @Override public Memory mul(long value) { return new DoubleMemory(this.value * value); } @Override public Memory mul(boolean value) { if (value) return this; else return CONST_DOUBLE_0; } @Override public Memory plus(boolean value) { if (value) return new DoubleMemory(this.value + 1); else return this; } @Override public Memory div(long value) { if (value == 0) return FALSE; return new DoubleMemory(this.value / value); } @Override public Memory div(double value) { if (value == 0.0) return FALSE; else return new DoubleMemory(this.value / value); } @Override public Memory div(boolean value) { if (!value) return FALSE; else return this; } public static boolean almostEqual(double o1 , double o2, double eps){ return Math.abs(o1 - o2) < eps; } public static boolean almostEqual(double o1, double o2){ return almostEqual(o1, o2, 0.0000000001); } @Override public int hashCode() { long temp = (long)value; return (int) (temp ^ (temp >>> 32)); } @Override public byte[] getBinaryBytes(Charset charset) { return MemoryStringUtils.getBinaryBytes(this); } }