KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jruby > RubyFloat


1 /***** BEGIN LICENSE BLOCK *****
2  * Version: CPL 1.0/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Common Public
5  * License Version 1.0 (the "License"); you may not use this file
6  * except in compliance with the License. You may obtain a copy of
7  * the License at http://www.eclipse.org/legal/cpl-v10.html
8  *
9  * Software distributed under the License is distributed on an "AS
10  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11  * implied. See the License for the specific language governing
12  * rights and limitations under the License.
13  *
14  * Copyright (C) 2001 Alan Moore <alan_moore@gmx.net>
15  * Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
16  * Copyright (C) 2002 Don Schwartz <schwardo@users.sourceforge.net>
17  * Copyright (C) 2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
18  * Copyright (C) 2002-2004 Thomas E Enebo <enebo@acm.org>
19  * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
20  * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
21  * Copyright (C) 2004 Charles O Nutter <headius@headius.com>
22  * Copyright (C) 2006 Miguel Covarrubias <mlcovarrubias@gmail.com>
23  *
24  * Alternatively, the contents of this file may be used under the terms of
25  * either of the GNU General Public License Version 2 or later (the "GPL"),
26  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27  * in which case the provisions of the GPL or the LGPL are applicable instead
28  * of those above. If you wish to allow use of your version of this file only
29  * under the terms of either the GPL or the LGPL, and not to allow others to
30  * use your version of this file under the terms of the CPL, indicate your
31  * decision by deleting the provisions above and replace them with the notice
32  * and other provisions required by the GPL or the LGPL. If you do not delete
33  * the provisions above, a recipient may use your version of this file under
34  * the terms of any one of the CPL, the GPL or the LGPL.
35  ***** END LICENSE BLOCK *****/

36 package org.jruby;
37
38 import java.text.DecimalFormat JavaDoc;
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 /**
48  *
49  * @author jpetersen
50  */

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         // Java Doubles are 64 bit long:
67
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         // Double.MAX_EXPONENT since Java 1.6
72
floatc.defineConstant("MIN_EXP", RubyFixnum.newFixnum(runtime, -1021));
73         // Double.MAX_EXPONENT since Java 1.6
74
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 JavaDoc getJavaClass() {
134         return Double.TYPE;
135     }
136
137     /** Getter for property value.
138      * @return Value of property value.
139      */

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     /* ================
166      * Instance Methods
167      * ================
168      */

169
170     /** rb_flo_induced_from
171      *
172      */

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 JavaDoc FORMAT = new DecimalFormat JavaDoc("##############0.0##############");
185
186     /** flo_to_s
187      *
188      */

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 JavaDoc val = ""+value;
199
200         if(val.indexOf('E') != -1) {
201             String JavaDoc 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     /** flo_coerce
217      *
218      */

219     public IRubyObject coerce(IRubyObject other) {
220         // MRI doesn't type check here either
221
return getRuntime().newArray(
222                 newFloat(getRuntime(), ((RubyNumeric) other).getDoubleValue()), this);
223         }
224
225     /** flo_uminus
226      *
227      */

228     public IRubyObject uminus() {
229         return RubyFloat.newFloat(getRuntime(), -value);
230         }
231
232     /** flo_plus
233      *
234      */

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     /** flo_minus
243      *
244      */

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     /** flo_mul
253      *
254      */

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     /** flo_div
263      *
264      */

265     public IRubyObject fdiv(IRubyObject other) { // don't override Numeric#div !
266
if (other instanceof RubyNumeric) {
267             return RubyFloat.newFloat(getRuntime(), value / ((RubyNumeric) other).getDoubleValue());
268         }
269         return coerceBin("div", other);
270     }
271
272     /** flo_mod
273      *
274      */

275     public IRubyObject mod(IRubyObject other) {
276         if (other instanceof RubyNumeric) {
277             double y = ((RubyNumeric) other).getDoubleValue();
278             // Modelled after c ruby implementation (java /,% not same as ruby)
279
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     /** flo_divmod
292      *
293      */

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     /** flo_pow
315      *
316      */

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     /** flo_eq
326      *
327      */

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         // Numeric.equal
337
return super.equal(other);
338
339     }
340
341     /** flo_cmp
342      *
343      */

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     /** flo_gt
353      *
354      */

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     /** flo_ge
364      *
365      */

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     /** flo_lt
375      *
376      */

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     /** flo_le
386      *
387      */

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     /** flo_eql
397      *
398      */

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     /** flo_hash
413      *
414      */

415     public RubyFixnum hash() {
416         long l = Double.doubleToLongBits(value);
417         return getRuntime().newFixnum((long) (l ^ l >>> 32));
418             }
419             
420     /** flo_fo
421      *
422      */

423     public IRubyObject to_f() {
424         return this;
425         }
426         
427     /** flo_abs
428      *
429      */

430     public IRubyObject abs() {
431         if (value < 0) {
432             return RubyFloat.newFloat(getRuntime(), Math.abs(value));
433         }
434         return this;
435     }
436     
437     /** flo_zero_p
438      *
439      */

440     public IRubyObject zero_p() {
441         return RubyBoolean.newBoolean(getRuntime(), value == 0.0);
442         }
443
444     /** flo_truncate
445      *
446      */

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     /** loor
459      *
460      */

461     public IRubyObject floor() {
462         return dbl2num(getRuntime(), Math.floor(value));
463     }
464
465     /** flo_ceil
466      *
467      */

468     public IRubyObject ceil() {
469         return dbl2num(getRuntime(), Math.ceil(value));
470         }
471
472     /** flo_round
473      *
474      */

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     /** flo_is_nan_p
487      *
488      */

489     public IRubyObject nan_p() {
490         return RubyBoolean.newBoolean(getRuntime(), Double.isNaN(value));
491     }
492
493     /** flo_is_infinite_p
494      *
495      */

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     /** flo_is_finite_p
504      *
505      */

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 JavaDoc {
514         String JavaDoc 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 JavaDoc {
525         return RubyFloat.newFloat(input.getRuntime(), Double.parseDouble(RubyString.byteListToString(input.unmarshalString())));
526     }
527     
528 }
529
Popular Tags