1 package net.sf.saxon.value; 2 import net.sf.saxon.Err; 3 import net.sf.saxon.ConversionContext; 4 import net.sf.saxon.expr.Token; 5 import net.sf.saxon.expr.XPathContext; 6 import net.sf.saxon.om.FastStringBuffer; 7 import net.sf.saxon.trans.DynamicError; 8 import net.sf.saxon.trans.XPathException; 9 import net.sf.saxon.type.BuiltInAtomicType; 10 import net.sf.saxon.type.ItemType; 11 import net.sf.saxon.type.Type; 12 import net.sf.saxon.type.ValidationException; 13 14 import java.math.BigDecimal ; 15 import java.util.regex.Matcher ; 16 17 20 21 public final class DoubleValue extends NumericValue { 22 23 public static final DoubleValue ZERO = new DoubleValue(0.0); 24 public static final DoubleValue NaN = new DoubleValue(Double.NaN); 25 26 private double value; 27 28 33 34 public DoubleValue(CharSequence val) throws ValidationException { 35 try { 36 value = Value.stringToNumber(val); 37 } catch (NumberFormatException e) { 38 throw new ValidationException("Cannot convert string " + Err.wrap(val, Err.VALUE) + " to a double"); 39 } 40 } 41 42 46 47 public DoubleValue(double value) { 48 this.value = value; 49 } 50 51 55 56 public double getDoubleValue() { 57 return value; 58 } 59 60 64 65 public int hashCode() { 66 if (value > Integer.MIN_VALUE && value < Integer.MAX_VALUE) { 67 return (int)value; 68 } else { 69 return new Double (value).hashCode(); 70 } 71 } 72 73 76 77 public boolean isNaN() { 78 return Double.isNaN(value); 79 } 80 81 86 public boolean effectiveBooleanValue(XPathContext context) { 87 return (value!=0.0 && !Double.isNaN(value)); 88 } 89 90 96 97 public AtomicValue convertPrimitive(BuiltInAtomicType requiredType, boolean validate, ConversionContext conversion) { 98 switch(requiredType.getPrimitiveType()) { 99 case Type.BOOLEAN: 100 return BooleanValue.get(effectiveBooleanValue(null)); 101 case Type.DOUBLE: 102 case Type.NUMBER: 103 case Type.ATOMIC: 104 case Type.ITEM: 105 return this; 106 case Type.INTEGER: 107 if (Double.isNaN(value)) { 108 ValidationException err = new ValidationException("Cannot convert double NaN to an integer"); 109 err.setErrorCode("FORG0001"); 111 return new ValidationErrorValue(err); 112 } 113 if (Double.isInfinite(value)) { 114 ValidationException err = new ValidationException("Cannot convert double infinity to an integer"); 115 err.setErrorCode("FORG0001"); 117 return new ValidationErrorValue(err); 118 } 119 if (value > Long.MAX_VALUE || value < Long.MIN_VALUE) { 120 return new BigIntegerValue(new BigDecimal (value).toBigInteger()); 121 } 122 return new IntegerValue((long)value); 123 case Type.DECIMAL: 124 try { 125 return new DecimalValue(value); 126 } catch (ValidationException e) { 127 return new ValidationErrorValue(e); 128 } 129 case Type.FLOAT: 130 return new FloatValue((float)value); 131 case Type.STRING: 132 return new StringValue(getStringValueCS()); 133 case Type.UNTYPED_ATOMIC: 134 return new UntypedAtomicValue(getStringValueCS()); 135 default: 136 ValidationException err = new ValidationException("Cannot convert double to " + 137 requiredType.getDisplayName()); 138 err.setErrorCode("FORG0001"); 140 return new ValidationErrorValue(err); 141 } 142 } 143 144 private static java.util.regex.Pattern nonExponentialPattern = 145 java.util.regex.Pattern.compile( 146 "(-?[0-9])([0-9]+?)(0*)\\.([0-9]*)"); 147 148 152 public String getStringValue() { 153 return doubleToString(value, Double.toString(value)); 154 } 155 156 164 165 static String doubleToString(double value, String javaString) { 166 if (value==0.0) { 167 if (javaString.charAt(0) == '-') { 168 return "-0"; 169 } else { 170 return "0"; 171 } 172 } 173 if (Double.isInfinite(value)) { 174 return (value > 0 ? "INF" : "-INF"); 175 } 176 if (Double.isNaN(value)) { 177 return "NaN"; 178 } 179 double absval = Math.abs(value); 180 String s = javaString; 181 if (absval < 1.0e-6 || absval >= 1.0e+6) { 182 if (s.indexOf('E')<0) { 183 FastStringBuffer sb = new FastStringBuffer(32); 187 Matcher matcher = nonExponentialPattern.matcher(s); 188 if (matcher.matches()) { 189 sb.append(matcher.group(1)); 190 sb.append('.'); 191 sb.append(matcher.group(2)); 192 String fraction = matcher.group(4); 193 if ("0".equals(fraction)) { 194 sb.append("E" + (matcher.group(2).length() + matcher.group(3).length())); 195 return sb.toString(); 196 } else { 197 sb.append(matcher.group(3)); 198 sb.append(matcher.group(4)); 199 sb.append("E" + (matcher.group(2).length() + matcher.group(3).length())); 200 return sb.toString(); 201 } 202 } else { 203 return s; 205 } 206 } else { 207 return s; 208 } 209 } 210 int len = s.length(); 211 if (s.endsWith("E0")) { 212 s = s.substring(0, len - 2); 213 } 214 if (s.endsWith(".0")) { 215 return s.substring(0, len - 2); 216 } 217 int e = s.indexOf('E'); 218 if (e < 0) { 219 while (s.charAt(len - 1) == '0' && s.charAt(len - 2) != '.') { 222 s = s.substring(0, --len); 223 } 224 return s; 225 } 226 int exp = Integer.parseInt(s.substring(e + 1)); 227 String sign; 228 if (s.charAt(0) == '-') { 229 sign = "-"; 230 s = s.substring(1); 231 --e; 232 } else { 233 sign = ""; 234 } 235 int nDigits = e - 2; 236 if (exp >= nDigits) { 237 return sign + s.substring(0, 1) + s.substring(2, e) + zeros(exp - nDigits); 238 } else if (exp > 0) { 239 return sign + s.substring(0, 1) + s.substring(2, 2 + exp) + '.' + s.substring(2 + exp, e); 240 } else { 241 while (s.charAt(e-1) == '0') e--; 242 return sign + "0." + zeros(-1 - exp) + s.substring(0, 1) + s.substring(2, e); 243 } 244 } 245 246 private static String zeros(int n) { 247 char[] buf = new char[n]; 248 for (int i = 0; i < n; i++) 249 buf[i] = '0'; 250 return new String (buf); 251 } 252 253 257 258 public ItemType getItemType() { 259 return Type.DOUBLE_TYPE; 260 } 261 262 265 266 public NumericValue negate() { 267 return new DoubleValue(-value); 268 } 269 270 273 274 public NumericValue floor() { 275 return new DoubleValue(Math.floor(value)); 276 } 277 278 281 282 public NumericValue ceiling() { 283 return new DoubleValue(Math.ceil(value)); 284 } 285 286 289 290 public NumericValue round() { 291 if (Double.isNaN(value)) { 292 return this; 293 } 294 if (Double.isInfinite(value)) { 295 return this; 296 } 297 if (value == 0.0) { 298 return this; } 300 if (value > -0.5 && value < 0.0) { 301 return new DoubleValue(-0.0); 302 } 303 if (value > Long.MIN_VALUE && value < Long.MAX_VALUE) { 304 return new DoubleValue(Math.round(value)); 305 } 306 307 312 return this; 313 } 314 315 318 319 public NumericValue roundToHalfEven(int scale) { 320 if (Double.isNaN(value)) return this; 321 if (Double.isInfinite(value)) return this; 322 if (value==0.0) return this; 324 326 double factor = Math.pow(10, scale+1); 327 double d = Math.abs(value * factor); 328 329 331 double rem = d % 10; 332 if (rem > 5) { 333 d += (10-rem); 334 } else if (rem < 5){ 335 d -= rem; 336 } else { 337 if ((d % 20) == 15) { 339 d +=5 ; 340 } else { 341 d -=5; 342 } 343 } 344 345 347 d /= factor; 348 if (value < 0) { 349 d = 0.0 -d; 350 } 351 return new DoubleValue(d); 352 353 } 354 355 359 360 public double signum() { 361 if (Double.isNaN(value)) { 362 return value; 363 } 364 if (value > 0) return 1; 365 if (value == 0) return 0; 366 return -1; 367 } 368 369 373 374 public boolean isWholeNumber() { 375 return value == Math.floor(value) && !Double.isInfinite(value); 376 } 377 378 381 382 public NumericValue arithmetic(int operator, NumericValue other, XPathContext context) throws XPathException { 383 if (other instanceof DoubleValue) { 384 switch(operator) { 385 case Token.PLUS: 386 return new DoubleValue(value + ((DoubleValue)other).value); 387 case Token.MINUS: 388 return new DoubleValue(value - ((DoubleValue)other).value); 389 case Token.MULT: 390 return new DoubleValue(value * ((DoubleValue)other).value); 391 case Token.DIV: 392 return new DoubleValue(value / ((DoubleValue)other).value); 393 case Token.IDIV: 394 if (((DoubleValue)other).value == 0.0) { 395 DynamicError e = new DynamicError("Integer division by zero"); 396 e.setErrorCode("FOAR0001"); 397 e.setXPathContext(context); 398 throw e; 399 } 400 return (NumericValue)(new DoubleValue(value / ((DoubleValue)other).value).convert(Type.INTEGER, context)); 401 case Token.MOD: 402 return new DoubleValue(value % ((DoubleValue)other).value); 403 default: 404 throw new UnsupportedOperationException ("Unknown operator"); 405 } 406 } else { 407 return arithmetic(operator, (DoubleValue)other.convert(Type.DOUBLE, context), context); 408 } 409 } 410 411 418 419 public boolean schemaEquals(Value obj) { 420 if (obj instanceof AtomicValue) { 421 obj = ((AtomicValue)obj).getPrimitiveValue(); 422 } 423 if (obj instanceof DoubleValue) { 424 return value == ((DoubleValue)obj).value; 425 } else { 426 return false; 427 } 428 } 429 430 431 434 435 public Object convertToJava(Class target, XPathContext context) throws XPathException { 436 if (target==Object .class) { 437 return new Double (value); 438 } else if (target.isAssignableFrom(DoubleValue.class)) { 439 return this; 440 } else if (target==boolean.class) { 441 return Boolean.valueOf(effectiveBooleanValue(context)); 442 } else if (target==Boolean .class) { 443 return Boolean.valueOf(effectiveBooleanValue(context)); 444 } else if (target==String .class || target==CharSequence .class) { 445 return getStringValue(); 446 } else if (target==double.class || target==Double .class) { 447 return new Double (value); 448 } else if (target==float.class ||target==Float .class ) { 449 return new Float (value); 450 } else if (target==long.class || target==Long .class) { 451 return new Long ((long)value); 452 } else if (target==int.class || target==Integer .class) { 453 return new Integer ((int)value); 454 } else if (target==short.class || target==Short .class) { 455 return new Short ((short)value); 456 } else if (target==byte.class || target==Byte .class) { 457 return new Byte ((byte)value); 458 } else if (target==char.class || target==Character .class) { 459 return new Character ((char)value); 460 } else { 461 Object o = super.convertToJava(target, context); 462 if (o == null) { 463 DynamicError err = new DynamicError("Conversion of double to " + target.getName() + 464 " is not supported"); 465 err.setXPathContext(context); 466 err.setErrorCode("SAXON:0000"); 467 } 468 return o; 469 } 470 } 471 472 479 } 480 481 499 | Popular Tags |