1 36 package org.jruby; 37 38 import java.text.DecimalFormat ; 39 40 import org.jruby.runtime.CallbackFactory; 41 import org.jruby.runtime.ClassIndex; 42 import org.jruby.runtime.ObjectAllocator; 43 import org.jruby.runtime.builtin.IRubyObject; 44 import org.jruby.runtime.marshal.MarshalStream; 45 import org.jruby.runtime.marshal.UnmarshalStream; 46 47 51 public class RubyFloat extends RubyNumeric { 52 53 public static RubyClass createFloatClass(Ruby runtime) { 54 RubyClass floatc = runtime.defineClass("Float", runtime.getClass("Numeric"), 55 ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR); 56 floatc.index = ClassIndex.FLOAT; 57 58 CallbackFactory callbackFactory = runtime.callbackFactory(RubyFloat.class); 59 floatc.getSingletonClass().undefineMethod("allocate"); 60 floatc.getSingletonClass().undefineMethod("new"); 61 62 floatc.getMetaClass().defineFastMethod("induced_from", callbackFactory.getFastSingletonMethod( 63 "induced_from", RubyKernel.IRUBY_OBJECT)); 64 floatc.includeModule(runtime.getModule("Precision")); 65 66 floatc.defineConstant("ROUNDS", RubyFixnum.newFixnum(runtime, 1)); 68 floatc.defineConstant("RADIX", RubyFixnum.newFixnum(runtime, 2)); 69 floatc.defineConstant("MANT_DIG", RubyFixnum.newFixnum(runtime, 53)); 70 floatc.defineConstant("DIG", RubyFixnum.newFixnum(runtime, 15)); 71 floatc.defineConstant("MIN_EXP", RubyFixnum.newFixnum(runtime, -1021)); 73 floatc.defineConstant("MAX_EXP", RubyFixnum.newFixnum(runtime, 1024)); 75 floatc.defineConstant("MIN_10_EXP", RubyFixnum.newFixnum(runtime, -307)); 76 floatc.defineConstant("MAX_10_EXP", RubyFixnum.newFixnum(runtime, -308)); 77 floatc.defineConstant("MIN", RubyFloat.newFloat(runtime, Double.MIN_VALUE)); 78 floatc.defineConstant("MAX", RubyFloat.newFloat(runtime, Double.MAX_VALUE)); 79 floatc.defineConstant("EPSILON", RubyFloat.newFloat(runtime, 2.2204460492503131e-16)); 80 81 floatc.defineFastMethod("to_s", callbackFactory.getFastMethod("to_s")); 82 floatc.defineFastMethod("coerce", callbackFactory.getFastMethod("coerce", RubyKernel.IRUBY_OBJECT)); 83 floatc.defineFastMethod("-@", callbackFactory.getFastMethod("uminus")); 84 floatc.defineFastMethod("+", callbackFactory.getFastMethod("plus", RubyKernel.IRUBY_OBJECT)); 85 floatc.defineFastMethod("-", callbackFactory.getFastMethod("minus", RubyKernel.IRUBY_OBJECT)); 86 floatc.defineFastMethod("*", callbackFactory.getFastMethod("mul", RubyKernel.IRUBY_OBJECT)); 87 floatc.defineFastMethod("/", callbackFactory.getFastMethod("fdiv", RubyKernel.IRUBY_OBJECT)); 88 floatc.defineFastMethod("%", callbackFactory.getFastMethod("mod", RubyKernel.IRUBY_OBJECT)); 89 floatc.defineFastMethod("modulo", callbackFactory.getFastMethod("mod", RubyKernel.IRUBY_OBJECT)); 90 floatc.defineFastMethod("divmod", callbackFactory.getFastMethod("divmod", RubyKernel.IRUBY_OBJECT)); 91 floatc.defineFastMethod("**", callbackFactory.getFastMethod("pow", RubyKernel.IRUBY_OBJECT)); 92 floatc.defineFastMethod("==", callbackFactory.getFastMethod("equal", RubyKernel.IRUBY_OBJECT)); 93 floatc.defineFastMethod("<=>", callbackFactory.getFastMethod("cmp", RubyKernel.IRUBY_OBJECT)); 94 floatc.defineFastMethod(">", callbackFactory.getFastMethod("gt", RubyKernel.IRUBY_OBJECT)); 95 floatc.defineFastMethod(">=", callbackFactory.getFastMethod("ge", RubyKernel.IRUBY_OBJECT)); 96 floatc.defineFastMethod("<", callbackFactory.getFastMethod("lt", RubyKernel.IRUBY_OBJECT)); 97 floatc.defineFastMethod("<=", callbackFactory.getFastMethod("le", RubyKernel.IRUBY_OBJECT)); 98 floatc.defineFastMethod("eql?", callbackFactory.getFastMethod("eql_p", RubyKernel.IRUBY_OBJECT)); 99 floatc.defineFastMethod("hash", callbackFactory.getFastMethod("hash")); 100 floatc.defineFastMethod("to_f", callbackFactory.getFastMethod("to_f")); 101 floatc.defineFastMethod("abs", callbackFactory.getFastMethod("abs")); 102 floatc.defineFastMethod("zero?", callbackFactory.getFastMethod("zero_p")); 103 104 floatc.defineFastMethod("to_i", callbackFactory.getFastMethod("truncate")); 105 floatc.defineFastMethod("to_int", callbackFactory.getFastMethod("truncate")); 106 floatc.defineFastMethod("floor", callbackFactory.getFastMethod("floor")); 107 floatc.defineFastMethod("ceil", callbackFactory.getFastMethod("ceil")); 108 floatc.defineFastMethod("round", callbackFactory.getFastMethod("round")); 109 floatc.defineFastMethod("truncate", callbackFactory.getFastMethod("truncate")); 110 111 floatc.defineFastMethod("nan?", callbackFactory.getFastMethod("nan_p")); 112 floatc.defineFastMethod("infinite?", callbackFactory.getFastMethod("infinite_p")); 113 floatc.defineFastMethod("finite?", callbackFactory.getFastMethod("finite_p")); 114 115 return floatc; 116 } 117 118 private final double value; 119 120 public int getNativeTypeIndex() { 121 return ClassIndex.FLOAT; 122 } 123 124 public RubyFloat(Ruby runtime) { 125 this(runtime, 0.0); 126 } 127 128 public RubyFloat(Ruby runtime, double value) { 129 super(runtime, runtime.getClass("Float")); 130 this.value = value; 131 } 132 133 public Class getJavaClass() { 134 return Double.TYPE; 135 } 136 137 140 public double getValue() { 141 return this.value; 142 } 143 144 public double getDoubleValue() { 145 return value; 146 } 147 148 public long getLongValue() { 149 return (long) value; 150 } 151 152 public RubyFloat convertToFloat() { 153 return this; 154 } 155 156 protected int compareValue(RubyNumeric other) { 157 double otherVal = other.getDoubleValue(); 158 return getValue() > otherVal ? 1 : getValue() < otherVal ? -1 : 0; 159 } 160 161 public static RubyFloat newFloat(Ruby runtime, double value) { 162 return new RubyFloat(runtime, value); 163 } 164 165 169 170 173 public static IRubyObject induced_from(IRubyObject recv, IRubyObject number) { 174 if (number instanceof RubyFixnum || number instanceof RubyBignum) { 175 return number.callMethod(recv.getRuntime().getCurrentContext(), "to_f"); 176 } 177 if (number instanceof RubyFloat) { 178 return number; 179 } 180 throw recv.getRuntime().newTypeError( 181 "failed to convert " + number.getMetaClass() + " into Float"); 182 } 183 184 private final static DecimalFormat FORMAT = new DecimalFormat ("##############0.0##############"); 185 186 189 public IRubyObject to_s() { 190 if (Double.isInfinite(value)) { 191 return RubyString.newString(getRuntime(), value < 0 ? "-Infinity" : "Infinity"); 192 } 193 194 if (Double.isNaN(value)) { 195 return RubyString.newString(getRuntime(), "NaN"); 196 } 197 198 String val = ""+value; 199 200 if(val.indexOf('E') != -1) { 201 String v2 = FORMAT.format(value); 202 int ix = v2.length()-1; 203 while(v2.charAt(ix) == '0' && v2.charAt(ix-1) != '.') { 204 ix--; 205 } 206 if(ix > 15 || "0.0".equals(v2.substring(0,ix+1))) { 207 val = val.replaceFirst("E(\\d)","e+$1").replaceFirst("E-","e-"); 208 } else { 209 val = v2.substring(0,ix+1); 210 } 211 } 212 213 return RubyString.newString(getRuntime(), val); 214 } 215 216 219 public IRubyObject coerce(IRubyObject other) { 220 return getRuntime().newArray( 222 newFloat(getRuntime(), ((RubyNumeric) other).getDoubleValue()), this); 223 } 224 225 228 public IRubyObject uminus() { 229 return RubyFloat.newFloat(getRuntime(), -value); 230 } 231 232 235 public IRubyObject plus(IRubyObject other) { 236 if (other instanceof RubyNumeric) { 237 return RubyFloat.newFloat(getRuntime(), value + ((RubyNumeric) other).getDoubleValue()); 238 } 239 return coerceBin("+", other); 240 } 241 242 245 public IRubyObject minus(IRubyObject other) { 246 if (other instanceof RubyNumeric) { 247 return RubyFloat.newFloat(getRuntime(), value - ((RubyNumeric) other).getDoubleValue()); 248 } 249 return coerceBin("-", other); 250 } 251 252 255 public IRubyObject mul(IRubyObject other) { 256 if (other instanceof RubyNumeric) { 257 return RubyFloat.newFloat(getRuntime(), value * ((RubyNumeric) other).getDoubleValue()); 258 } 259 return coerceBin("*", other); 260 } 261 262 265 public IRubyObject fdiv(IRubyObject other) { if (other instanceof RubyNumeric) { 267 return RubyFloat.newFloat(getRuntime(), value / ((RubyNumeric) other).getDoubleValue()); 268 } 269 return coerceBin("div", other); 270 } 271 272 275 public IRubyObject mod(IRubyObject other) { 276 if (other instanceof RubyNumeric) { 277 double y = ((RubyNumeric) other).getDoubleValue(); 278 double x = value; 280 281 double mod = Math.IEEEremainder(x, y); 282 if (y * mod < 0) { 283 mod += y; 284 } 285 286 return RubyFloat.newFloat(getRuntime(), mod); 287 } 288 return coerceBin("%", other); 289 } 290 291 294 public IRubyObject divmod(IRubyObject other) { 295 if (other instanceof RubyNumeric) { 296 double y = ((RubyNumeric) other).getDoubleValue(); 297 double x = value; 298 299 double mod = Math.IEEEremainder(x, y); 300 double div = (x - mod) / y; 301 302 if (y * mod < 0) { 303 mod += y; 304 div -= 1.0; 305 } 306 final Ruby runtime = getRuntime(); 307 IRubyObject car = dbl2num(runtime, div); 308 RubyFloat cdr = RubyFloat.newFloat(runtime, mod); 309 return RubyArray.newArray(runtime, car, cdr); 310 } 311 return coerceBin("%", other); 312 } 313 314 317 public IRubyObject pow(IRubyObject other) { 318 if (other instanceof RubyNumeric) { 319 return RubyFloat.newFloat(getRuntime(), Math.pow(value, ((RubyNumeric) other) 320 .getDoubleValue())); 321 } 322 return coerceBin("/", other); 323 } 324 325 328 public IRubyObject equal(IRubyObject other) { 329 if (Double.isNaN(value)) { 330 return getRuntime().getFalse(); 331 } 332 if (other instanceof RubyNumeric) { 333 return RubyBoolean.newBoolean(getRuntime(), value == ((RubyNumeric) other) 334 .getDoubleValue()); 335 } 336 return super.equal(other); 338 339 } 340 341 344 public IRubyObject cmp(IRubyObject other) { 345 if (other instanceof RubyNumeric) { 346 double b = ((RubyNumeric) other).getDoubleValue(); 347 return dbl_cmp(getRuntime(), value, b); 348 } 349 return coerceCmp("<=>", other); 350 } 351 352 355 public IRubyObject gt(IRubyObject other) { 356 if (other instanceof RubyNumeric) { 357 double b = ((RubyNumeric) other).getDoubleValue(); 358 return RubyBoolean.newBoolean(getRuntime(), !Double.isNaN(b) && value > b); 359 } 360 return coerceRelOp(">", other); 361 } 362 363 366 public IRubyObject ge(IRubyObject other) { 367 if (other instanceof RubyNumeric) { 368 double b = ((RubyNumeric) other).getDoubleValue(); 369 return RubyBoolean.newBoolean(getRuntime(), !Double.isNaN(b) && value >= b); 370 } 371 return coerceRelOp(">=", other); 372 } 373 374 377 public IRubyObject lt(IRubyObject other) { 378 if (other instanceof RubyNumeric) { 379 double b = ((RubyNumeric) other).getDoubleValue(); 380 return RubyBoolean.newBoolean(getRuntime(), !Double.isNaN(b) && value < b); 381 } 382 return coerceRelOp("<", other); 383 } 384 385 388 public IRubyObject le(IRubyObject other) { 389 if (other instanceof RubyNumeric) { 390 double b = ((RubyNumeric) other).getDoubleValue(); 391 return RubyBoolean.newBoolean(getRuntime(), !Double.isNaN(b) && value <= b); 392 } 393 return coerceRelOp("<=", other); 394 } 395 396 399 public IRubyObject eql_p(IRubyObject other) { 400 if (other instanceof RubyFloat) { 401 double b = ((RubyFloat) other).value; 402 if (Double.isNaN(value) || Double.isNaN(b)) { 403 return getRuntime().getFalse(); 404 } 405 if (value == b) { 406 return getRuntime().getTrue(); 407 } 408 } 409 return getRuntime().getFalse(); 410 } 411 412 415 public RubyFixnum hash() { 416 long l = Double.doubleToLongBits(value); 417 return getRuntime().newFixnum((long) (l ^ l >>> 32)); 418 } 419 420 423 public IRubyObject to_f() { 424 return this; 425 } 426 427 430 public IRubyObject abs() { 431 if (value < 0) { 432 return RubyFloat.newFloat(getRuntime(), Math.abs(value)); 433 } 434 return this; 435 } 436 437 440 public IRubyObject zero_p() { 441 return RubyBoolean.newBoolean(getRuntime(), value == 0.0); 442 } 443 444 447 public IRubyObject truncate() { 448 double f = value; 449 if (f > 0.0) { 450 f = Math.floor(f); 451 } 452 if (f > 0.0) { 453 f = Math.ceil(f); 454 } 455 return dbl2num(getRuntime(), f); 456 } 457 458 461 public IRubyObject floor() { 462 return dbl2num(getRuntime(), Math.floor(value)); 463 } 464 465 468 public IRubyObject ceil() { 469 return dbl2num(getRuntime(), Math.ceil(value)); 470 } 471 472 475 public IRubyObject round() { 476 double f = value; 477 if (f > 0.0) { 478 f = Math.floor(f + 0.5); 479 } 480 if (f < 0.0) { 481 f = Math.ceil(f - 0.5); 482 } 483 return dbl2num(getRuntime(), f); 484 } 485 486 489 public IRubyObject nan_p() { 490 return RubyBoolean.newBoolean(getRuntime(), Double.isNaN(value)); 491 } 492 493 496 public IRubyObject infinite_p() { 497 if (Double.isInfinite(value)) { 498 return RubyFixnum.newFixnum(getRuntime(), value < 0 ? -1 : 1); 499 } 500 return getRuntime().getNil(); 501 } 502 503 506 public IRubyObject finite_p() { 507 if (Double.isInfinite(value) || Double.isNaN(value)) { 508 return getRuntime().getFalse(); 509 } 510 return getRuntime().getTrue(); 511 } 512 513 public static void marshalTo(RubyFloat aFloat, MarshalStream output) throws java.io.IOException { 514 String strValue = aFloat.toString(); 515 516 if (Double.isInfinite(aFloat.value)) { 517 strValue = aFloat.value < 0 ? "-inf" : "inf"; 518 } else if (Double.isNaN(aFloat.value)) { 519 strValue = "nan"; 520 } 521 output.writeString(strValue); 522 } 523 524 public static RubyFloat unmarshalFrom(UnmarshalStream input) throws java.io.IOException { 525 return RubyFloat.newFloat(input.getRuntime(), Double.parseDouble(RubyString.byteListToString(input.unmarshalString()))); 526 } 527 528 } 529 | Popular Tags |