001: /***** BEGIN LICENSE BLOCK *****
002: * Version: CPL 1.0/GPL 2.0/LGPL 2.1
003: *
004: * The contents of this file are subject to the Common Public
005: * License Version 1.0 (the "License"); you may not use this file
006: * except in compliance with the License. You may obtain a copy of
007: * the License at http://www.eclipse.org/legal/cpl-v10.html
008: *
009: * Software distributed under the License is distributed on an "AS
010: * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
011: * implied. See the License for the specific language governing
012: * rights and limitations under the License.
013: *
014: * Copyright (C) 2001 Alan Moore <alan_moore@gmx.net>
015: * Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
016: * Copyright (C) 2002 Don Schwartz <schwardo@users.sourceforge.net>
017: * Copyright (C) 2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
018: * Copyright (C) 2002-2004 Thomas E Enebo <enebo@acm.org>
019: * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
020: * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
021: * Copyright (C) 2004 Charles O Nutter <headius@headius.com>
022: * Copyright (C) 2006 Miguel Covarrubias <mlcovarrubias@gmail.com>
023: *
024: * Alternatively, the contents of this file may be used under the terms of
025: * either of the GNU General Public License Version 2 or later (the "GPL"),
026: * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
027: * in which case the provisions of the GPL or the LGPL are applicable instead
028: * of those above. If you wish to allow use of your version of this file only
029: * under the terms of either the GPL or the LGPL, and not to allow others to
030: * use your version of this file under the terms of the CPL, indicate your
031: * decision by deleting the provisions above and replace them with the notice
032: * and other provisions required by the GPL or the LGPL. If you do not delete
033: * the provisions above, a recipient may use your version of this file under
034: * the terms of any one of the CPL, the GPL or the LGPL.
035: ***** END LICENSE BLOCK *****/package org.jruby;
036:
037: import java.text.DecimalFormat;
038: import java.text.DecimalFormatSymbols;
039: import java.util.Locale;
040:
041: import org.jruby.runtime.CallbackFactory;
042: import org.jruby.runtime.ClassIndex;
043: import org.jruby.runtime.MethodIndex;
044: import org.jruby.runtime.ObjectAllocator;
045: import org.jruby.runtime.builtin.IRubyObject;
046: import org.jruby.runtime.marshal.MarshalStream;
047: import org.jruby.runtime.marshal.UnmarshalStream;
048:
049: /**
050: *
051: * @author jpetersen
052: */
053: public class RubyFloat extends RubyNumeric {
054:
055: public static RubyClass createFloatClass(Ruby runtime) {
056: RubyClass floatc = runtime.defineClass("Float", runtime
057: .getClass("Numeric"),
058: ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);
059: floatc.index = ClassIndex.FLOAT;
060:
061: CallbackFactory callbackFactory = runtime
062: .callbackFactory(RubyFloat.class);
063: floatc.getSingletonClass().undefineMethod("allocate");
064: floatc.getSingletonClass().undefineMethod("new");
065:
066: floatc.getMetaClass().defineFastMethod(
067: "induced_from",
068: callbackFactory.getFastSingletonMethod("induced_from",
069: RubyKernel.IRUBY_OBJECT));
070: floatc.includeModule(runtime.getModule("Precision"));
071:
072: // Java Doubles are 64 bit long:
073: floatc.defineConstant("ROUNDS", RubyFixnum
074: .newFixnum(runtime, 1));
075: floatc
076: .defineConstant("RADIX", RubyFixnum.newFixnum(runtime,
077: 2));
078: floatc.defineConstant("MANT_DIG", RubyFixnum.newFixnum(runtime,
079: 53));
080: floatc.defineConstant("DIG", RubyFixnum.newFixnum(runtime, 15));
081: // Double.MAX_EXPONENT since Java 1.6
082: floatc.defineConstant("MIN_EXP", RubyFixnum.newFixnum(runtime,
083: -1021));
084: // Double.MAX_EXPONENT since Java 1.6
085: floatc.defineConstant("MAX_EXP", RubyFixnum.newFixnum(runtime,
086: 1024));
087: floatc.defineConstant("MIN_10_EXP", RubyFixnum.newFixnum(
088: runtime, -307));
089: floatc.defineConstant("MAX_10_EXP", RubyFixnum.newFixnum(
090: runtime, -308));
091: floatc.defineConstant("MIN", RubyFloat.newFloat(runtime,
092: Double.MIN_VALUE));
093: floatc.defineConstant("MAX", RubyFloat.newFloat(runtime,
094: Double.MAX_VALUE));
095: floatc.defineConstant("EPSILON", RubyFloat.newFloat(runtime,
096: 2.2204460492503131e-16));
097:
098: floatc.defineFastMethod("to_s", callbackFactory
099: .getFastMethod("to_s"));
100: floatc.defineFastMethod("coerce", callbackFactory
101: .getFastMethod("coerce", RubyKernel.IRUBY_OBJECT));
102: floatc.defineFastMethod("-@", callbackFactory
103: .getFastMethod("uminus"));
104: floatc.defineFastMethod("+", callbackFactory.getFastMethod(
105: "plus", RubyKernel.IRUBY_OBJECT));
106: floatc.defineFastMethod("-", callbackFactory.getFastMethod(
107: "minus", RubyKernel.IRUBY_OBJECT));
108: floatc.defineFastMethod("*", callbackFactory.getFastMethod(
109: "mul", RubyKernel.IRUBY_OBJECT));
110: floatc.defineFastMethod("/", callbackFactory.getFastMethod(
111: "fdiv", RubyKernel.IRUBY_OBJECT));
112: floatc.defineFastMethod("%", callbackFactory.getFastMethod(
113: "mod", RubyKernel.IRUBY_OBJECT));
114: floatc.defineFastMethod("modulo", callbackFactory
115: .getFastMethod("mod", RubyKernel.IRUBY_OBJECT));
116: floatc.defineFastMethod("divmod", callbackFactory
117: .getFastMethod("divmod", RubyKernel.IRUBY_OBJECT));
118: floatc.defineFastMethod("**", callbackFactory.getFastMethod(
119: "pow", RubyKernel.IRUBY_OBJECT));
120: floatc.defineFastMethod("==", callbackFactory.getFastMethod(
121: "equal", RubyKernel.IRUBY_OBJECT));
122: floatc.defineFastMethod("<=>", callbackFactory.getFastMethod(
123: "cmp", RubyKernel.IRUBY_OBJECT));
124: floatc.defineFastMethod(">", callbackFactory.getFastMethod(
125: "gt", RubyKernel.IRUBY_OBJECT));
126: floatc.defineFastMethod(">=", callbackFactory.getFastMethod(
127: "ge", RubyKernel.IRUBY_OBJECT));
128: floatc.defineFastMethod("<", callbackFactory.getFastMethod(
129: "lt", RubyKernel.IRUBY_OBJECT));
130: floatc.defineFastMethod("<=", callbackFactory.getFastMethod(
131: "le", RubyKernel.IRUBY_OBJECT));
132: floatc.defineFastMethod("eql?", callbackFactory.getFastMethod(
133: "eql_p", RubyKernel.IRUBY_OBJECT));
134: floatc.defineFastMethod("hash", callbackFactory
135: .getFastMethod("hash"));
136: floatc.defineFastMethod("to_f", callbackFactory
137: .getFastMethod("to_f"));
138: floatc.defineFastMethod("abs", callbackFactory
139: .getFastMethod("abs"));
140: floatc.defineFastMethod("zero?", callbackFactory
141: .getFastMethod("zero_p"));
142:
143: floatc.defineFastMethod("to_i", callbackFactory
144: .getFastMethod("truncate"));
145: floatc.defineFastMethod("to_int", callbackFactory
146: .getFastMethod("truncate"));
147: floatc.defineFastMethod("floor", callbackFactory
148: .getFastMethod("floor"));
149: floatc.defineFastMethod("ceil", callbackFactory
150: .getFastMethod("ceil"));
151: floatc.defineFastMethod("round", callbackFactory
152: .getFastMethod("round"));
153: floatc.defineFastMethod("truncate", callbackFactory
154: .getFastMethod("truncate"));
155:
156: floatc.defineFastMethod("nan?", callbackFactory
157: .getFastMethod("nan_p"));
158: floatc.defineFastMethod("infinite?", callbackFactory
159: .getFastMethod("infinite_p"));
160: floatc.defineFastMethod("finite?", callbackFactory
161: .getFastMethod("finite_p"));
162:
163: return floatc;
164: }
165:
166: private final double value;
167:
168: public int getNativeTypeIndex() {
169: return ClassIndex.FLOAT;
170: }
171:
172: public RubyFloat(Ruby runtime) {
173: this (runtime, 0.0);
174: }
175:
176: public RubyFloat(Ruby runtime, double value) {
177: super (runtime, runtime.getClass("Float"));
178: this .value = value;
179: }
180:
181: public Class getJavaClass() {
182: return Double.TYPE;
183: }
184:
185: /** Getter for property value.
186: * @return Value of property value.
187: */
188: public double getValue() {
189: return this .value;
190: }
191:
192: public double getDoubleValue() {
193: return value;
194: }
195:
196: public long getLongValue() {
197: return (long) value;
198: }
199:
200: public RubyFloat convertToFloat() {
201: return this ;
202: }
203:
204: protected int compareValue(RubyNumeric other) {
205: double otherVal = other.getDoubleValue();
206: return getValue() > otherVal ? 1 : getValue() < otherVal ? -1
207: : 0;
208: }
209:
210: public static RubyFloat newFloat(Ruby runtime, double value) {
211: return new RubyFloat(runtime, value);
212: }
213:
214: /* ================
215: * Instance Methods
216: * ================
217: */
218:
219: /** rb_flo_induced_from
220: *
221: */
222: public static IRubyObject induced_from(IRubyObject recv,
223: IRubyObject number) {
224: if (number instanceof RubyFixnum
225: || number instanceof RubyBignum) {
226: return number.callMethod(recv.getRuntime()
227: .getCurrentContext(), MethodIndex.TO_F, "to_f");
228: }
229: if (number instanceof RubyFloat) {
230: return number;
231: }
232: throw recv.getRuntime().newTypeError(
233: "failed to convert " + number.getMetaClass()
234: + " into Float");
235: }
236:
237: private final static DecimalFormat FORMAT = new DecimalFormat(
238: "##############0.0##############",
239: new DecimalFormatSymbols(Locale.ENGLISH));
240:
241: /** flo_to_s
242: *
243: */
244: public IRubyObject to_s() {
245: if (Double.isInfinite(value)) {
246: return RubyString.newString(getRuntime(),
247: value < 0 ? "-Infinity" : "Infinity");
248: }
249:
250: if (Double.isNaN(value)) {
251: return RubyString.newString(getRuntime(), "NaN");
252: }
253:
254: String val = "" + value;
255:
256: if (val.indexOf('E') != -1) {
257: String v2 = FORMAT.format(value);
258: int ix = v2.length() - 1;
259: while (v2.charAt(ix) == '0' && v2.charAt(ix - 1) != '.') {
260: ix--;
261: }
262: if (ix > 15 || "0.0".equals(v2.substring(0, ix + 1))) {
263: val = val.replaceFirst("E(\\d)", "e+$1").replaceFirst(
264: "E-", "e-");
265: } else {
266: val = v2.substring(0, ix + 1);
267: }
268: }
269:
270: return RubyString.newString(getRuntime(), val);
271: }
272:
273: /** flo_coerce
274: *
275: */
276: public IRubyObject coerce(IRubyObject other) {
277: // MRI doesn't type check here either
278: return getRuntime().newArray(
279: newFloat(getRuntime(), ((RubyNumeric) other)
280: .getDoubleValue()), this );
281: }
282:
283: /** flo_uminus
284: *
285: */
286: public IRubyObject uminus() {
287: return RubyFloat.newFloat(getRuntime(), -value);
288: }
289:
290: /** flo_plus
291: *
292: */
293: public IRubyObject plus(IRubyObject other) {
294: if (other instanceof RubyNumeric) {
295: return RubyFloat.newFloat(getRuntime(), value
296: + ((RubyNumeric) other).getDoubleValue());
297: }
298: return coerceBin("+", other);
299: }
300:
301: /** flo_minus
302: *
303: */
304: public IRubyObject minus(IRubyObject other) {
305: if (other instanceof RubyNumeric) {
306: return RubyFloat.newFloat(getRuntime(), value
307: - ((RubyNumeric) other).getDoubleValue());
308: }
309: return coerceBin("-", other);
310: }
311:
312: /** flo_mul
313: *
314: */
315: public IRubyObject mul(IRubyObject other) {
316: if (other instanceof RubyNumeric) {
317: return RubyFloat.newFloat(getRuntime(), value
318: * ((RubyNumeric) other).getDoubleValue());
319: }
320: return coerceBin("*", other);
321: }
322:
323: /** flo_div
324: *
325: */
326: public IRubyObject fdiv(IRubyObject other) { // don't override Numeric#div !
327: if (other instanceof RubyNumeric) {
328: return RubyFloat.newFloat(getRuntime(), value
329: / ((RubyNumeric) other).getDoubleValue());
330: }
331: return coerceBin("div", other);
332: }
333:
334: /** flo_mod
335: *
336: */
337: public IRubyObject mod(IRubyObject other) {
338: if (other instanceof RubyNumeric) {
339: double y = ((RubyNumeric) other).getDoubleValue();
340: // Modelled after c ruby implementation (java /,% not same as ruby)
341: double x = value;
342:
343: double mod = Math.IEEEremainder(x, y);
344: if (y * mod < 0) {
345: mod += y;
346: }
347:
348: return RubyFloat.newFloat(getRuntime(), mod);
349: }
350: return coerceBin("%", other);
351: }
352:
353: /** flo_divmod
354: *
355: */
356: public IRubyObject divmod(IRubyObject other) {
357: if (other instanceof RubyNumeric) {
358: double y = ((RubyNumeric) other).getDoubleValue();
359: double x = value;
360:
361: double mod = Math.IEEEremainder(x, y);
362: double div = (x - mod) / y;
363:
364: if (y * mod < 0) {
365: mod += y;
366: div -= 1.0;
367: }
368: final Ruby runtime = getRuntime();
369: IRubyObject car = dbl2num(runtime, div);
370: RubyFloat cdr = RubyFloat.newFloat(runtime, mod);
371: return RubyArray.newArray(runtime, car, cdr);
372: }
373: return coerceBin("%", other);
374: }
375:
376: /** flo_pow
377: *
378: */
379: public IRubyObject pow(IRubyObject other) {
380: if (other instanceof RubyNumeric) {
381: return RubyFloat.newFloat(getRuntime(), Math.pow(value,
382: ((RubyNumeric) other).getDoubleValue()));
383: }
384: return coerceBin("/", other);
385: }
386:
387: /** flo_eq
388: *
389: */
390: public IRubyObject equal(IRubyObject other) {
391: if (Double.isNaN(value)) {
392: return getRuntime().getFalse();
393: }
394: if (other instanceof RubyNumeric) {
395: return RubyBoolean.newBoolean(getRuntime(),
396: value == ((RubyNumeric) other).getDoubleValue());
397: }
398: // Numeric.equal
399: return super .equal(other);
400:
401: }
402:
403: /** flo_cmp
404: *
405: */
406: public IRubyObject cmp(IRubyObject other) {
407: if (other instanceof RubyNumeric) {
408: double b = ((RubyNumeric) other).getDoubleValue();
409: return dbl_cmp(getRuntime(), value, b);
410: }
411: return coerceCmp("<=>", other);
412: }
413:
414: /** flo_gt
415: *
416: */
417: public IRubyObject gt(IRubyObject other) {
418: if (other instanceof RubyNumeric) {
419: double b = ((RubyNumeric) other).getDoubleValue();
420: return RubyBoolean.newBoolean(getRuntime(), !Double
421: .isNaN(b)
422: && value > b);
423: }
424: return coerceRelOp(">", other);
425: }
426:
427: /** flo_ge
428: *
429: */
430: public IRubyObject ge(IRubyObject other) {
431: if (other instanceof RubyNumeric) {
432: double b = ((RubyNumeric) other).getDoubleValue();
433: return RubyBoolean.newBoolean(getRuntime(), !Double
434: .isNaN(b)
435: && value >= b);
436: }
437: return coerceRelOp(">=", other);
438: }
439:
440: /** flo_lt
441: *
442: */
443: public IRubyObject lt(IRubyObject other) {
444: if (other instanceof RubyNumeric) {
445: double b = ((RubyNumeric) other).getDoubleValue();
446: return RubyBoolean.newBoolean(getRuntime(), !Double
447: .isNaN(b)
448: && value < b);
449: }
450: return coerceRelOp("<", other);
451: }
452:
453: /** flo_le
454: *
455: */
456: public IRubyObject le(IRubyObject other) {
457: if (other instanceof RubyNumeric) {
458: double b = ((RubyNumeric) other).getDoubleValue();
459: return RubyBoolean.newBoolean(getRuntime(), !Double
460: .isNaN(b)
461: && value <= b);
462: }
463: return coerceRelOp("<=", other);
464: }
465:
466: /** flo_eql
467: *
468: */
469: public IRubyObject eql_p(IRubyObject other) {
470: if (other instanceof RubyFloat) {
471: double b = ((RubyFloat) other).value;
472: if (Double.isNaN(value) || Double.isNaN(b)) {
473: return getRuntime().getFalse();
474: }
475: if (value == b) {
476: return getRuntime().getTrue();
477: }
478: }
479: return getRuntime().getFalse();
480: }
481:
482: /** flo_hash
483: *
484: */
485: public RubyFixnum hash() {
486: return getRuntime().newFixnum(hashCode());
487: }
488:
489: public final int hashCode() {
490: long l = Double.doubleToLongBits(value);
491: return (int) (l ^ l >>> 32);
492: }
493:
494: /** flo_fo
495: *
496: */
497: public IRubyObject to_f() {
498: return this ;
499: }
500:
501: /** flo_abs
502: *
503: */
504: public IRubyObject abs() {
505: if (value < 0) {
506: return RubyFloat.newFloat(getRuntime(), Math.abs(value));
507: }
508: return this ;
509: }
510:
511: /** flo_zero_p
512: *
513: */
514: public IRubyObject zero_p() {
515: return RubyBoolean.newBoolean(getRuntime(), value == 0.0);
516: }
517:
518: /** flo_truncate
519: *
520: */
521: public IRubyObject truncate() {
522: double f = value;
523: if (f > 0.0) {
524: f = Math.floor(f);
525: }
526: if (f > 0.0) {
527: f = Math.ceil(f);
528: }
529: return dbl2num(getRuntime(), f);
530: }
531:
532: /** loor
533: *
534: */
535: public IRubyObject floor() {
536: return dbl2num(getRuntime(), Math.floor(value));
537: }
538:
539: /** flo_ceil
540: *
541: */
542: public IRubyObject ceil() {
543: return dbl2num(getRuntime(), Math.ceil(value));
544: }
545:
546: /** flo_round
547: *
548: */
549: public IRubyObject round() {
550: double f = value;
551: if (f > 0.0) {
552: f = Math.floor(f + 0.5);
553: }
554: if (f < 0.0) {
555: f = Math.ceil(f - 0.5);
556: }
557: return dbl2num(getRuntime(), f);
558: }
559:
560: /** flo_is_nan_p
561: *
562: */
563: public IRubyObject nan_p() {
564: return RubyBoolean
565: .newBoolean(getRuntime(), Double.isNaN(value));
566: }
567:
568: /** flo_is_infinite_p
569: *
570: */
571: public IRubyObject infinite_p() {
572: if (Double.isInfinite(value)) {
573: return RubyFixnum.newFixnum(getRuntime(), value < 0 ? -1
574: : 1);
575: }
576: return getRuntime().getNil();
577: }
578:
579: /** flo_is_finite_p
580: *
581: */
582: public IRubyObject finite_p() {
583: if (Double.isInfinite(value) || Double.isNaN(value)) {
584: return getRuntime().getFalse();
585: }
586: return getRuntime().getTrue();
587: }
588:
589: public static void marshalTo(RubyFloat aFloat, MarshalStream output)
590: throws java.io.IOException {
591: String strValue = aFloat.toString();
592:
593: if (Double.isInfinite(aFloat.value)) {
594: strValue = aFloat.value < 0 ? "-inf" : "inf";
595: } else if (Double.isNaN(aFloat.value)) {
596: strValue = "nan";
597: }
598: output.writeString(strValue);
599: }
600:
601: public static RubyFloat unmarshalFrom(UnmarshalStream input)
602: throws java.io.IOException {
603: RubyFloat result = RubyFloat.newFloat(input.getRuntime(),
604: org.jruby.util.Convert.byteListToDouble(input
605: .unmarshalString(), false));
606: input.registerLinkTarget(result);
607: return result;
608: }
609:
610: }
|