KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jruby > RubyBignum


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 Benoit Cerrina <b.cerrina@wanadoo.fr>
17  * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
18  * Copyright (C) 2002-2004 Thomas E Enebo <enebo@acm.org>
19  * Copyright (C) 2004-2005 Charles O Nutter <headius@headius.com>
20  * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
21  *
22  * Alternatively, the contents of this file may be used under the terms of
23  * either of the GNU General Public License Version 2 or later (the "GPL"),
24  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
25  * in which case the provisions of the GPL or the LGPL are applicable instead
26  * of those above. If you wish to allow use of your version of this file only
27  * under the terms of either the GPL or the LGPL, and not to allow others to
28  * use your version of this file under the terms of the CPL, indicate your
29  * decision by deleting the provisions above and replace them with the notice
30  * and other provisions required by the GPL or the LGPL. If you do not delete
31  * the provisions above, a recipient may use your version of this file under
32  * the terms of any one of the CPL, the GPL or the LGPL.
33  ***** END LICENSE BLOCK *****/

34 package org.jruby;
35
36 import java.io.IOException JavaDoc;
37 import java.math.BigDecimal JavaDoc;
38 import java.math.BigInteger JavaDoc;
39 import org.jruby.runtime.Arity;
40 import org.jruby.runtime.Block;
41 import org.jruby.runtime.CallType;
42 import org.jruby.runtime.CallbackFactory;
43 import org.jruby.runtime.ClassIndex;
44 import org.jruby.runtime.ObjectAllocator;
45 import org.jruby.runtime.ThreadContext;
46 import org.jruby.runtime.builtin.IRubyObject;
47 import org.jruby.runtime.marshal.MarshalStream;
48 import org.jruby.runtime.marshal.UnmarshalStream;
49
50 /**
51  *
52  * @author jpetersen
53  */

54 public class RubyBignum extends RubyInteger {
55     public static RubyClass createBignumClass(Ruby runtime) {
56         RubyClass bignum = runtime.defineClass("Bignum", runtime.getClass("Integer"),
57                 ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);
58         bignum.index = ClassIndex.BIGNUM;
59         CallbackFactory callbackFactory = runtime.callbackFactory(RubyBignum.class);
60
61         bignum.defineFastMethod("to_s", callbackFactory.getFastOptMethod("to_s"));
62         bignum.defineFastMethod("coerce", callbackFactory.getFastMethod("coerce", RubyKernel.IRUBY_OBJECT));
63         bignum.defineFastMethod("-@", callbackFactory.getFastMethod("uminus"));
64         bignum.defineFastMethod("+", callbackFactory.getFastMethod("plus", RubyKernel.IRUBY_OBJECT));
65         bignum.defineFastMethod("-", callbackFactory.getFastMethod("minus", RubyKernel.IRUBY_OBJECT));
66         bignum.defineFastMethod("*", callbackFactory.getFastMethod("mul", RubyKernel.IRUBY_OBJECT));
67         bignum.defineFastMethod("/", callbackFactory.getFastMethod("div", RubyKernel.IRUBY_OBJECT));
68         bignum.defineFastMethod("%", callbackFactory.getFastMethod("mod", RubyKernel.IRUBY_OBJECT));
69         bignum.defineFastMethod("div", callbackFactory.getFastMethod("div", RubyKernel.IRUBY_OBJECT));
70         bignum.defineFastMethod("divmod", callbackFactory.getFastMethod("divmod", RubyKernel.IRUBY_OBJECT));
71         bignum.defineFastMethod("modulo", callbackFactory.getFastMethod("mod", RubyKernel.IRUBY_OBJECT));
72         bignum.defineFastMethod("remainder", callbackFactory.getFastMethod("remainder", RubyKernel.IRUBY_OBJECT));
73         bignum.defineFastMethod("quo", callbackFactory.getFastMethod("quo", RubyKernel.IRUBY_OBJECT));
74         bignum.defineFastMethod("**", callbackFactory.getFastMethod("pow", RubyKernel.IRUBY_OBJECT));
75         bignum.defineFastMethod("&", callbackFactory.getFastMethod("and", RubyKernel.IRUBY_OBJECT));
76         bignum.defineFastMethod("|", callbackFactory.getFastMethod("or", RubyKernel.IRUBY_OBJECT));
77         bignum.defineFastMethod("^", callbackFactory.getFastMethod("xor", RubyKernel.IRUBY_OBJECT));
78         bignum.defineFastMethod("~", callbackFactory.getFastMethod("neg"));
79         bignum.defineFastMethod("<<", callbackFactory.getFastMethod("lshift", RubyKernel.IRUBY_OBJECT));
80         bignum.defineFastMethod(">>", callbackFactory.getFastMethod("rshift", RubyKernel.IRUBY_OBJECT));
81         bignum.defineFastMethod("[]", callbackFactory.getFastMethod("aref", RubyKernel.IRUBY_OBJECT));
82
83         bignum.defineFastMethod("<=>", callbackFactory.getFastMethod("cmp", RubyKernel.IRUBY_OBJECT));
84         bignum.defineFastMethod("==", callbackFactory.getFastMethod("equal", RubyKernel.IRUBY_OBJECT));
85         bignum.defineFastMethod("eql?", callbackFactory.getFastMethod("eql_p", RubyKernel.IRUBY_OBJECT));
86         bignum.defineFastMethod("hash", callbackFactory.getFastMethod("hash"));
87         bignum.defineFastMethod("to_f", callbackFactory.getFastMethod("to_f"));
88         bignum.defineFastMethod("abs", callbackFactory.getFastMethod("abs"));
89         bignum.defineFastMethod("size", callbackFactory.getFastMethod("size"));
90
91         return bignum;
92     }
93
94     private static final int BIT_SIZE = 64;
95     private static final long MAX = (1L << (BIT_SIZE - 1)) - 1;
96     private static final BigInteger JavaDoc LONG_MAX = BigInteger.valueOf(MAX);
97     private static final BigInteger JavaDoc LONG_MIN = BigInteger.valueOf(-MAX - 1);
98     
99     public static final byte OP_PLUS_SWITCHVALUE = 1;
100     public static final byte OP_MINUS_SWITCHVALUE = 2;
101     public static final byte OP_LT_SWITCHVALUE = 3;
102
103     private final BigInteger JavaDoc value;
104
105     public RubyBignum(Ruby runtime, BigInteger JavaDoc value) {
106         super(runtime, runtime.getClass("Bignum"));
107         this.value = value;
108     }
109     
110     public IRubyObject callMethod(ThreadContext context, RubyModule rubyclass, byte switchvalue, String JavaDoc name,
111             IRubyObject[] args, CallType callType, Block block) {
112         switch (switchvalue) {
113             case OP_PLUS_SWITCHVALUE:
114                 Arity.singleArgument().checkArity(context.getRuntime(), args);
115                 return plus(args[0]);
116             case OP_MINUS_SWITCHVALUE:
117                 Arity.singleArgument().checkArity(context.getRuntime(), args);
118                 return minus(args[0]);
119             case 0:
120             default:
121                 return super.callMethod(context, rubyclass, name, args, callType, block);
122         }
123     }
124     
125     public int getNativeTypeIndex() {
126         return ClassIndex.BIGNUM;
127     }
128
129     public static RubyBignum newBignum(Ruby runtime, long value) {
130         return newBignum(runtime, BigInteger.valueOf(value));
131     }
132
133     public static RubyBignum newBignum(Ruby runtime, double value) {
134         return newBignum(runtime, new BigDecimal JavaDoc(value).toBigInteger());
135         }
136
137     public static RubyBignum newBignum(Ruby runtime, BigInteger JavaDoc value) {
138         return new RubyBignum(runtime, value);
139     }
140
141     public double getDoubleValue() {
142         return big2dbl(this);
143     }
144
145     public long getLongValue() {
146         return big2long(this);
147     }
148
149     /** Getter for property value.
150      * @return Value of property value.
151      */

152     public BigInteger JavaDoc getValue() {
153         return value;
154     }
155
156     /* ================
157      * Utility Methods
158      * ================
159      */

160
161     /* If the value will fit in a Fixnum, return one of those. */
162     /** rb_big_norm
163      *
164      */

165     public static RubyInteger bignorm(Ruby runtime, BigInteger JavaDoc bi) {
166         if (bi.compareTo(LONG_MIN) < 0 || bi.compareTo(LONG_MAX) > 0) {
167             return newBignum(runtime, bi);
168         }
169         return runtime.newFixnum(bi.longValue());
170     }
171
172     /** rb_big2long
173      *
174      */

175     public static long big2long(RubyBignum value) {
176         BigInteger JavaDoc big = value.getValue();
177
178         if (big.compareTo(LONG_MIN) < 0 || big.compareTo(LONG_MAX) > 0) {
179             throw value.getRuntime().newRangeError("bignum too big to convert into `long'");
180     }
181         return big.longValue();
182         }
183
184     /** rb_big2dbl
185      *
186      */

187     public static double big2dbl(RubyBignum value) {
188         BigInteger JavaDoc big = value.getValue();
189         double dbl = big.doubleValue();
190         if (dbl == Double.NEGATIVE_INFINITY || dbl == Double.POSITIVE_INFINITY) {
191             value.getRuntime().getWarnings().warn("Bignum out of Float range");
192     }
193         return dbl;
194     }
195
196     /** rb_int2big
197      *
198      */

199     public static BigInteger JavaDoc fix2big(RubyFixnum arg) {
200         return BigInteger.valueOf(arg.getLongValue());
201     }
202
203     /* ================
204      * Instance Methods
205      * ================
206      */

207
208     /** rb_big_to_s
209      *
210      */

211     public IRubyObject to_s(IRubyObject[] args) {
212         checkArgumentCount(args, 0, 1);
213
214         int base = args.length == 0 ? 10 : num2int(args[0]);
215         if (base < 2 || base > 36) {
216             throw getRuntime().newArgumentError("illegal radix " + base);
217     }
218         return getRuntime().newString(getValue().toString(base));
219     }
220
221     /** rb_big_coerce
222      *
223      */

224     public IRubyObject coerce(IRubyObject other) {
225         if (other instanceof RubyFixnum) {
226             return getRuntime().newArray(newBignum(getRuntime(), ((RubyFixnum) other).getLongValue()), this);
227         } else if (other instanceof RubyBignum) {
228             return getRuntime().newArray(newBignum(getRuntime(), ((RubyBignum) other).getValue()), this);
229     }
230
231         throw getRuntime().newTypeError("Can't coerce " + other.getMetaClass().getName() + " to Bignum");
232     }
233
234     /** rb_big_uminus
235      *
236      */

237     public IRubyObject uminus() {
238         return bignorm(getRuntime(), value.negate());
239     }
240
241     /** rb_big_plus
242      *
243      */

244     public IRubyObject plus(IRubyObject other) {
245         if (other instanceof RubyFixnum) {
246             return bignorm(getRuntime(), value.add(fix2big(((RubyFixnum) other))));
247         }
248         if (other instanceof RubyBignum) {
249             return bignorm(getRuntime(), value.add(((RubyBignum) other).value));
250         } else if (other instanceof RubyFloat) {
251             return RubyFloat.newFloat(getRuntime(), big2dbl(this) + ((RubyFloat) other).getDoubleValue());
252     }
253         return coerceBin("+", other);
254     }
255
256     /** rb_big_minus
257      *
258      */

259     public IRubyObject minus(IRubyObject other) {
260         if (other instanceof RubyFixnum) {
261             return bignorm(getRuntime(), value.subtract(fix2big(((RubyFixnum) other))));
262     }
263         if (other instanceof RubyBignum) {
264             return bignorm(getRuntime(), value.subtract(((RubyBignum) other).value));
265         } else if (other instanceof RubyFloat) {
266             return RubyFloat.newFloat(getRuntime(), big2dbl(this) - ((RubyFloat) other).getDoubleValue());
267     }
268         return coerceBin("-", other);
269     }
270
271     /** rb_big_mul
272      *
273      */

274     public IRubyObject mul(IRubyObject other) {
275         if (other instanceof RubyFixnum) {
276             return bignorm(getRuntime(), value.multiply(fix2big(((RubyFixnum) other))));
277         }
278         if (other instanceof RubyBignum) {
279             return bignorm(getRuntime(), value.multiply(((RubyBignum) other).value));
280         } else if (other instanceof RubyFloat) {
281             return RubyFloat.newFloat(getRuntime(), big2dbl(this) * ((RubyFloat) other).getDoubleValue());
282         }
283         return coerceBin("*", other);
284     }
285
286     /** rb_big_div
287      *
288      */

289     public IRubyObject div(IRubyObject other) {
290         final BigInteger JavaDoc otherValue;
291         if (other instanceof RubyFixnum) {
292             otherValue = fix2big((RubyFixnum) other);
293         } else if (other instanceof RubyBignum) {
294             otherValue = ((RubyBignum) other).value;
295         } else if (other instanceof RubyFloat) {
296             return RubyFloat.newFloat(getRuntime(), big2dbl(this) / ((RubyFloat) other).getDoubleValue());
297         } else {
298             return coerceBin("/", other);
299         }
300
301         if (otherValue.equals(BigInteger.ZERO)) {
302             throw getRuntime().newZeroDivisionError();
303         }
304
305         BigInteger JavaDoc[] results = value.divideAndRemainder(otherValue);
306
307         if (results[0].signum() == -1 && results[1].signum() != 0) {
308             return bignorm(getRuntime(), results[0].subtract(BigInteger.ONE));
309         }
310         return bignorm(getRuntime(), results[0]);
311     }
312
313     /** rb_big_divmod
314      *
315      */

316     public IRubyObject divmod(IRubyObject other) {
317         final BigInteger JavaDoc otherValue;
318         if (other instanceof RubyFixnum) {
319             otherValue = fix2big((RubyFixnum) other);
320         } else if (other instanceof RubyBignum) {
321             otherValue = ((RubyBignum) other).value;
322         } else {
323             return coerceBin("divmod", other);
324         }
325
326         if (otherValue.equals(BigInteger.ZERO)) {
327             throw getRuntime().newZeroDivisionError();
328         }
329
330         BigInteger JavaDoc[] results = value.divideAndRemainder(otherValue);
331
332         if (results[0].signum() == -1 && results[1].signum() != 0) {
333             return bignorm(getRuntime(), results[0].subtract(BigInteger.ONE));
334         }
335         final Ruby runtime = getRuntime();
336         return RubyArray.newArray(getRuntime(), bignorm(runtime, results[0]), bignorm(runtime, results[1]));
337     }
338
339     /** rb_big_modulo
340      *
341      */

342     public IRubyObject mod(IRubyObject other) {
343         final BigInteger JavaDoc otherValue;
344         if (other instanceof RubyFixnum) {
345             otherValue = fix2big((RubyFixnum) other);
346         } else if (other instanceof RubyBignum) {
347             otherValue = ((RubyBignum) other).value;
348         } else {
349             return coerceBin("%", other);
350         }
351         if (otherValue.equals(BigInteger.ZERO)) {
352             throw getRuntime().newZeroDivisionError();
353         }
354         BigInteger JavaDoc result = value.mod(otherValue.abs());
355         if (otherValue.signum() == -1) {
356             result = otherValue.add(result);
357         }
358         return bignorm(getRuntime(), result);
359
360             }
361
362     /** rb_big_remainder
363      *
364      */

365     public IRubyObject remainder(IRubyObject other) {
366         final BigInteger JavaDoc otherValue;
367         if (other instanceof RubyFixnum) {
368             otherValue = fix2big(((RubyFixnum) other));
369         } else if (other instanceof RubyBignum) {
370             otherValue = ((RubyBignum) other).value;
371         } else {
372             return coerceBin("remainder", other);
373         }
374         if (otherValue.equals(BigInteger.ZERO)) {
375             throw getRuntime().newZeroDivisionError();
376     }
377         return bignorm(getRuntime(), value.remainder(otherValue));
378     }
379
380     /** rb_big_quo
381
382      *
383      */

384     public IRubyObject quo(IRubyObject other) {
385         if (other instanceof RubyNumeric) {
386             return RubyFloat.newFloat(getRuntime(), big2dbl(this) / ((RubyNumeric) other).getDoubleValue());
387         } else {
388             return coerceBin("quo", other);
389         }
390     }
391
392     /** rb_big_pow
393      *
394      */

395     public IRubyObject pow(IRubyObject other) {
396         double d;
397         if (other instanceof RubyFixnum) {
398             RubyFixnum fix = (RubyFixnum) other;
399             long fixValue = fix.getLongValue();
400             // MRI issuses warning here on (RBIGNUM(x)->len * SIZEOF_BDIGITS * yy > 1024*1024)
401
if (((value.bitLength() + 7) / 8) * 4 * Math.abs(fixValue) > 1024 * 1024) {
402                 getRuntime().getWarnings().warn("in a**b, b may be too big");
403         }
404             if (fixValue >= 0) {
405                 return bignorm(getRuntime(), value.pow((int) fixValue)); // num2int is also implemented
406
} else {
407                 return RubyFloat.newFloat(getRuntime(), Math.pow(big2dbl(this), (double)fixValue));
408             }
409         } else if (other instanceof RubyBignum) {
410             getRuntime().getWarnings().warn("in a**b, b may be too big");
411             d = ((RubyBignum) other).getDoubleValue();
412         } else if (other instanceof RubyFloat) {
413             d = ((RubyFloat) other).getDoubleValue();
414         } else {
415             return coerceBin("**", other);
416
417     }
418         return RubyFloat.newFloat(getRuntime(), Math.pow(big2dbl(this), d));
419     }
420
421     /** rb_big_and
422      *
423      */

424     public IRubyObject and(IRubyObject other) {
425         other = other.convertToInteger();
426         if (other instanceof RubyBignum) {
427             return bignorm(getRuntime(), value.and(((RubyBignum) other).value));
428         } else if(other instanceof RubyFixnum) {
429             return bignorm(getRuntime(), value.and(fix2big((RubyFixnum)other)));
430         }
431         return coerceBin("&", other);
432     }
433
434     /** rb_big_or
435      *
436      */

437     public IRubyObject or(IRubyObject other) {
438         other = other.convertToInteger();
439         if (other instanceof RubyBignum) {
440             return bignorm(getRuntime(), value.or(((RubyBignum) other).value));
441         }
442         if (other instanceof RubyFixnum) { // no bignorm here needed
443
return bignorm(getRuntime(), value.or(fix2big((RubyFixnum)other)));
444         }
445         return coerceBin("|", other);
446     }
447
448     /** rb_big_xor
449      *
450      */

451     public IRubyObject xor(IRubyObject other) {
452         other = other.convertToInteger();
453         if (other instanceof RubyBignum) {
454             return bignorm(getRuntime(), value.xor(((RubyBignum) other).value));
455         }
456         if (other instanceof RubyFixnum) {
457             return bignorm(getRuntime(), value.xor(BigInteger.valueOf(((RubyFixnum) other).getLongValue())));
458     }
459
460         return coerceBin("^", other);
461     }
462
463     /** rb_big_neg
464      *
465      */

466     public IRubyObject neg() {
467         return RubyBignum.newBignum(getRuntime(), value.not());
468         }
469
470     /** rb_big_lshift
471      *
472      */

473     public IRubyObject lshift(IRubyObject other) {
474         int width = num2int(other);
475         if (width < 0) {
476             return rshift(RubyFixnum.newFixnum(getRuntime(), -width));
477         }
478         
479         return bignorm(getRuntime(), value.shiftLeft(width));
480     }
481
482     /** rb_big_rshift
483      *
484      */

485     public IRubyObject rshift(IRubyObject other) {
486         int width = num2int(other);
487
488         if (width < 0) {
489             return lshift(RubyFixnum.newFixnum(getRuntime(), -width));
490         }
491         return bignorm(getRuntime(), value.shiftRight(width));
492     }
493
494     /** rb_big_aref
495      *
496      */

497     public RubyFixnum aref(IRubyObject other) {
498         if (other instanceof RubyBignum) {
499             if (((RubyBignum) other).value.signum() >= 0 || value.signum() == -1) {
500                 return RubyFixnum.zero(getRuntime());
501             }
502             return RubyFixnum.one(getRuntime());
503         }
504         int position = num2int(other);
505         if (position < 0) {
506             return RubyFixnum.zero(getRuntime());
507         }
508         
509         return value.testBit(num2int(other)) ? RubyFixnum.one(getRuntime()) : RubyFixnum.zero(getRuntime());
510     }
511
512     /** rb_big_cmp
513      *
514      */

515     public IRubyObject cmp(IRubyObject other) {
516         final BigInteger JavaDoc otherValue;
517         if (other instanceof RubyFixnum) {
518             otherValue = fix2big((RubyFixnum) other);
519         } else if (other instanceof RubyBignum) {
520             otherValue = ((RubyBignum) other).value;
521         } else if (other instanceof RubyFloat) {
522             return dbl_cmp(getRuntime(), big2dbl(this), ((RubyFloat) other).getDoubleValue());
523         } else {
524             return coerceCmp("<=>", other);
525         }
526
527         // wow, the only time we can use the java protocol ;)
528
return RubyFixnum.newFixnum(getRuntime(), value.compareTo(otherValue));
529     }
530
531     /** rb_big_eq
532      *
533      */

534     public IRubyObject equal(IRubyObject other) {
535         final BigInteger JavaDoc otherValue;
536         if (other instanceof RubyFixnum) {
537             otherValue = fix2big((RubyFixnum) other);
538         } else if (other instanceof RubyBignum) {
539             otherValue = ((RubyBignum) other).value;
540         } else if (other instanceof RubyFloat) {
541             double a = ((RubyFloat) other).getDoubleValue();
542             if (Double.isNaN(a)) {
543                 return getRuntime().getFalse();
544             }
545             return RubyBoolean.newBoolean(getRuntime(), a == big2dbl(this));
546         } else {
547             return super.equal(other);
548         }
549         return RubyBoolean.newBoolean(getRuntime(), value.compareTo(otherValue) == 0);
550     }
551
552     /** rb_big_eql
553      *
554      */

555     public IRubyObject eql_p(IRubyObject other) {
556         if (other instanceof RubyBignum) {
557             return RubyBoolean.newBoolean(getRuntime(), value.compareTo(((RubyBignum)other).value) == 0);
558         }
559         return getRuntime().getFalse();
560     }
561
562     /** rb_big_hash
563      *
564      */

565     public RubyFixnum hash() {
566         return getRuntime().newFixnum(value.hashCode());
567         }
568
569     /** rb_big_to_f
570      *
571      */

572     public IRubyObject to_f() {
573         return RubyFloat.newFloat(getRuntime(), getDoubleValue());
574     }
575
576     /** rb_big_abs
577      *
578      */

579     public IRubyObject abs() {
580         return RubyBignum.newBignum(getRuntime(), value.abs());
581     }
582
583     /** rb_big_size
584      *
585      */

586     public RubyFixnum size() {
587         return getRuntime().newFixnum((value.bitLength() + 7) / 8);
588     }
589
590     public static void marshalTo(RubyBignum bignum, MarshalStream output) throws IOException JavaDoc {
591         output.write(bignum.value.signum() >= 0 ? '+' : '-');
592         
593         BigInteger JavaDoc absValue = bignum.value.abs();
594         
595         byte[] digits = absValue.toByteArray();
596         
597         boolean oddLengthNonzeroStart = (digits.length % 2 != 0 && digits[0] != 0);
598         int shortLength = digits.length / 2;
599         if (oddLengthNonzeroStart) {
600             shortLength++;
601         }
602         output.writeInt(shortLength);
603         
604         for (int i = 1; i <= shortLength * 2 && i <= digits.length; i++) {
605             output.write(digits[digits.length - i]);
606         }
607         
608         if (oddLengthNonzeroStart) {
609             // Pad with a 0
610
output.write(0);
611         }
612     }
613
614     public static RubyBignum unmarshalFrom(UnmarshalStream input) throws IOException JavaDoc {
615         boolean positive = input.readUnsignedByte() == '+';
616         int shortLength = input.unmarshalInt();
617
618         // BigInteger required a sign byte in incoming array
619
byte[] digits = new byte[shortLength * 2 + 1];
620
621         for (int i = digits.length - 1; i >= 1; i--) {
622             digits[i] = input.readSignedByte();
623         }
624
625         BigInteger JavaDoc value = new BigInteger JavaDoc(digits);
626         if (!positive) {
627             value = value.negate();
628         }
629
630         RubyBignum result = newBignum(input.getRuntime(), value);
631         input.registerLinkTarget(result);
632         return result;
633     }
634 }
635
Popular Tags