1 package gnu.xquery.util; 2 import gnu.bytecode.*; 3 import gnu.mapping.*; 4 import gnu.expr.*; 5 import gnu.xml.TextUtils; 6 import gnu.kawa.xml.*; 7 import gnu.kawa.functions.*; 8 import java.math.*; 9 import gnu.math.*; 10 11 public class ArithOp extends Procedure1or2 12 implements CanInline, Inlineable 13 { 14 char op; 15 16 static final BigInteger TEN = BigInteger.valueOf(10); 17 18 public static final ArithOp add = new ArithOp("+", '+', 2); 19 public static final ArithOp sub = new ArithOp("-", '-', 2); 20 public static final ArithOp mul = new ArithOp("*", '*', 2); 21 public static final ArithOp div = new ArithOp("div", 'd', 2); 22 public static final ArithOp idiv = new ArithOp("idiv", 'i', 2); 23 public static final ArithOp mod = new ArithOp("mod", 'm', 2); 24 public static final ArithOp plus = new ArithOp("+", 'P', 1); 25 public static final ArithOp minus = new ArithOp("-", 'M', 1); 26 27 ArithOp (String name, char op, int nargs) 28 { 29 super(name); 30 this.op = op; 31 } 32 33 public Object apply1 (Object arg1) 34 throws java.lang.Throwable 35 { 36 if (arg1 == Values.empty || arg1 == null) 37 return arg1; 38 if (arg1 instanceof KNode || arg1 instanceof UntypedAtomic) 39 arg1 = XDataType.doubleType.valueOf(TextUtils.stringValue(arg1)); 40 switch (op) 41 { 42 case 'P': 43 return AddOp.apply2(1, gnu.math.IntNum.zero(), arg1); 44 case 'M': 45 int code1 = Arithmetic.classifyValue(arg1); 46 switch (code1) 47 { 48 case Arithmetic.FLOAT_CODE: 49 return XDataType.makeFloat(- Arithmetic.asFloat(arg1)); 50 case Arithmetic.DOUBLE_CODE: 51 return XDataType.makeDouble(- Arithmetic.asDouble(arg1)); 52 default: 53 if (arg1 instanceof Numeric) 54 return ((Numeric) arg1).neg(); 55 return AddOp.apply2(-1, gnu.math.IntNum.zero(), arg1); 56 } 57 } 58 throw new UnsupportedOperationException (getName()); 59 } 60 61 public static BigDecimal div (BigDecimal d1, BigDecimal d2) 62 { 63 64 66 BigDecimal d = d1.divide(d2, 18, BigDecimal.ROUND_HALF_EVEN); 67 68 BigInteger unscaled = d.unscaledValue(); 69 if (unscaled.signum() == 0) 70 return BigDecimal.valueOf(0); 71 int sc = 0; 72 while (sc < 18) 73 { 74 BigInteger[] divmod = unscaled.divideAndRemainder(TEN); 75 if (divmod[1].signum() != 0) 76 break; 77 sc++; 78 unscaled = divmod[0]; 79 } 80 return sc == 0 ? d : new BigDecimal(unscaled, d.scale() - sc); 81 82 83 } 84 85 public Object apply2 (Object arg1, Object arg2) 86 throws java.lang.Throwable 87 { 88 if (arg1 == Values.empty || arg1 == null) 89 return arg1; 90 if (arg2 == Values.empty || arg2 == null) 91 return arg2; 92 if (arg1 instanceof KNode || arg1 instanceof UntypedAtomic) 93 arg1 = XDataType.doubleType.valueOf(TextUtils.stringValue(arg1)); 94 if (arg2 instanceof KNode || arg2 instanceof UntypedAtomic) 95 arg2 = XDataType.doubleType.valueOf(TextUtils.stringValue(arg2)); 96 switch (op) 97 { 98 case '+': 99 return AddOp.apply2(1, arg1, arg2); 100 case '-': 101 return AddOp.apply2(-1, arg1, arg2); 102 case '*': 103 return MultiplyOp.$St.apply2(arg1, arg2); 104 } 105 int code1 = Arithmetic.classifyValue(arg1); 106 int code2 = Arithmetic.classifyValue(arg2); 107 int code = code1 < code2 ? code2 : code1; 108 switch (op) 109 { 110 case 'd': if (code1 < 0 || code2 < 0) 112 break; 113 else if (code <= Arithmetic.RATNUM_CODE) 114 { 115 BigDecimal d1 = (BigDecimal) XDataType.decimalType.cast(arg1); 116 BigDecimal d2 = (BigDecimal) XDataType.decimalType.cast(arg2); 118 return div(d1, d2); 120 } 121 else if (code == Arithmetic.FLOAT_CODE) 122 { 123 return new Float (((Number ) arg1).floatValue() 124 / ((Number ) arg2).floatValue()); 125 } 126 else if (code == Arithmetic.DOUBLE_CODE) 127 { 128 return new Double (((Number ) arg1).doubleValue() 129 / ((Number ) arg2).doubleValue()); 130 } 131 else if (arg1 instanceof Duration && arg2 instanceof Duration) 132 { 133 Duration dur1 = (Duration) arg1; 134 Duration dur2 = (Duration) arg2; 135 if (dur1.unit() == Unit.second && dur2.unit() == Unit.second) 136 { 137 long s1 = dur1.getTotalSeconds(); 138 long s2 = dur2.getTotalSeconds(); 139 int n1 = dur1.getNanoSecondsOnly(); 140 int n2 = dur2.getNanoSecondsOnly(); 141 BigDecimal sec1 = TimeUtils.secondsBigDecimalFromDuration(s1, n1); 142 BigDecimal sec2 = TimeUtils.secondsBigDecimalFromDuration(s2, n2); 143 return div(sec1, sec2); 144 } 145 if (dur1.unit() == Unit.month && dur2.unit() == Unit.month) 146 { 147 BigDecimal m1 = BigDecimal.valueOf(dur1.getTotalMonths()); 148 BigDecimal m2 = BigDecimal.valueOf(dur2.getTotalMonths()); 149 return div(m1, m2); 150 } 151 throw new ArithmeticException ("divide of incompatible durations"); 152 } 153 else if (code >= 0) 154 return Arithmetic.asNumeric(arg1).div(Arithmetic.asNumeric(arg2)); 155 case 'i': if (code1 < 0 || code2 < 0) 157 break; 158 else if (code <= Arithmetic.INTNUM_CODE) 159 { 160 IntNum i1 = Arithmetic.asIntNum(arg1); 161 IntNum i2 = Arithmetic.asIntNum(arg2); 162 return IntNum.quotient(i1, i2); 163 } 164 else if (code <= Arithmetic.RATNUM_CODE) 165 { 166 BigDecimal d1 = (BigDecimal) XDataType.decimalType.cast(arg1); 167 BigDecimal d2 = (BigDecimal) XDataType.decimalType.cast(arg2); 169 return Arithmetic.asIntNum(d1.divide(d2, 0, 171 BigDecimal.ROUND_DOWN)); 172 } 173 else if (code <= Arithmetic.FLOAT_CODE) 174 { 175 float f 176 = ((Number ) arg1).floatValue() / ((Number ) arg2).floatValue(); 177 return RealNum.toExactInt((double) f, RealNum.TRUNCATE); 178 } 179 else 180 { 181 double d 182 = ((Number ) arg1).doubleValue() / ((Number ) arg2).doubleValue(); 183 return RealNum.toExactInt(d, RealNum.TRUNCATE); 184 } 185 case 'm': if (code1 < 0 || code2 < 0) 187 break; 188 else if (code <= Arithmetic.INTNUM_CODE) 189 { 190 IntNum i1 = Arithmetic.asIntNum(arg1); 191 IntNum i2 = Arithmetic.asIntNum(arg2); 192 return IntNum.remainder(i1, i2); 193 } 194 else if (code <= Arithmetic.RATNUM_CODE) 195 { 196 return sub.apply2(arg1, mul.apply2(idiv.apply2(arg1, arg2), arg2)); 197 } 198 else if (code <= Arithmetic.FLOAT_CODE) 199 { 200 float f1 = Arithmetic.asFloat(arg1); 201 float f2 = Arithmetic.asFloat(arg2); 202 return gnu.kawa.xml.XDataType.makeFloat(f1 % f2); 203 } 204 else if (code <= Arithmetic.FLONUM_CODE) 205 { 206 double d1 = Arithmetic.asDouble(arg1); 207 double d2 = Arithmetic.asDouble(arg2); 208 double d = d1 % d2; 209 if (code == Arithmetic.FLONUM_CODE) 210 return DFloNum.make(d); 211 else 212 return gnu.kawa.xml.XDataType.makeDouble(d); 213 } 214 } 215 throw new UnsupportedOperationException (getName()); 216 } 217 218 public Expression inline (ApplyExp exp, ExpWalker walker) 219 { 220 return exp; 222 } 223 224 public void compile (ApplyExp exp, Compilation comp, Target target) 225 { 226 ApplyExp.compile(exp, comp, target); 228 } 229 230 public Type getReturnType (Expression[] args) 231 { 232 return Type.pointer_type; 233 } 234 } 235 | Popular Tags |