Develop and Download Open Source Software

Browse CVS Repository

Contents of /netruby/netruby/Numeric.cs

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.1.1.1 - (show annotations) (download) (vendor branch)
Mon Apr 8 13:28:24 2002 UTC (22 years ago) by arton
Branch: MAIN, vendor
CVS Tags: start, HEAD
Changes since 1.1: +0 -0 lines
initial version 0.8

1 /*
2 Copyright(C) 2001-2002 arton
3
4 Permission is granted for use, copying, modification, distribution,
5 and distribution of modified versions of this work as long as the
6 above copyright notice is included.
7 */
8
9 using System;
10 using System.Collections;
11 using System.Reflection;
12 using System.Security;
13
14 namespace arton.NETRuby
15 {
16 public class RChar : RBasic
17 {
18 internal RChar(NetRuby rb, char c) :
19 base(rb, rb.cObject)
20 {
21 cVal = c;
22 }
23 char cVal;
24 public char Char
25 {
26 get { return cVal; }
27 }
28 }
29 public abstract class RNumeric : RBasic, ICloneable
30 {
31 internal RNumeric(NetRuby rb, RMetaObject meta) :
32 base(rb, meta)
33 {
34 }
35 public override bool Eql(object o)
36 {
37 if (GetType() != ruby.InstanceOf(o).GetType())
38 return false;
39 return Equals(o);
40 }
41 public abstract long ToLong();
42
43 private RNumeric Instanciate(object o)
44 {
45 if (o is int)
46 return new RFixnum(ruby, (int)o);
47 if (o is long)
48 return new RBignum(ruby, (long)o);
49 if (o is double)
50 return new RFloat(ruby, (double)o);
51 return (RNumeric)o;
52 }
53 public virtual RArray Coerce(object o)
54 {
55 if (ruby.ClassOf(o) == Class)
56 return RArray.AssocNew(ruby, Instanciate(o), this);
57 return RArray.AssocNew(ruby, RFloat.Float(ruby, o), ToFloat());
58 }
59
60 protected void DoCoerce(object o, out RNumeric x, out RNumeric y)
61 {
62 x = y = null;
63 try
64 {
65 RArray a = (RArray)ruby.Funcall(o, "coerce", this);
66 if (a == null || a.Count != 2)
67 throw new eTypeError("coerce must return [x, y]");
68 x = (RNumeric)a[0];
69 y = (RNumeric)a[1];
70 }
71 catch
72 {
73 throw new eTypeError(String.Format("{0} can't be coerced into {1}",
74 IsSpecialConstType(o) ?
75 ruby.Inspect(o) : ruby.ClassOf(o).Name,
76 ruby.ClassOf(this).Name));
77 }
78 }
79 public object CoerceBin(object o)
80 {
81 RNumeric x;
82 RNumeric y;
83 DoCoerce(o, out x, out y);
84 return ruby.FuncallRetry(x, y);
85 }
86
87 public virtual object Clone()
88 {
89 return this;
90 }
91
92 public abstract RNumeric Plus(object o);
93 public abstract RNumeric Minus(object o);
94 public abstract RNumeric Multiply(object o);
95 public abstract RNumeric Divide(object o);
96 public abstract RNumeric Modulo(object o);
97 public abstract RNumeric Remainder(object o);
98
99 public abstract RArray DivMod(object o);
100 public abstract bool Gt(object o);
101 public abstract bool GE(object o);
102 public abstract bool Lt(object o);
103 public abstract bool LE(object o);
104 static public object num_coerce(RBasic r, params object[] args)
105 {
106 return ((RNumeric)r).Coerce(args[0]);
107 }
108 static public object num_plus(RBasic r, params object[] args)
109 {
110 return ((RNumeric)r).Plus(args[0]);
111 }
112 static public object num_minus(RBasic r, params object[] args)
113 {
114 return ((RNumeric)r).Minus(args[0]);
115 }
116 static public object num_mul(RBasic r, params object[] args)
117 {
118 return ((RNumeric)r).Multiply(args[0]);
119 }
120 static public object num_div(RBasic r, params object[] args)
121 {
122 return ((RNumeric)r).Divide(args[0]);
123 }
124 static public object num_mod(RBasic r, params object[] args)
125 {
126 return ((RNumeric)r).Modulo(args[0]);
127 }
128 static public object num_remainder(RBasic r, params object[] args)
129 {
130 return ((RNumeric)r).Remainder(args[0]);
131 }
132 static public object num_divmod(RBasic r, params object[] args)
133 {
134 return ((RNumeric)r).DivMod(args[0]);
135 }
136 static public object num_equal(RBasic r, params object[] args)
137 {
138 return r.Equals(args[0]);
139 }
140 static public object num_gt(RBasic r, params object[] args)
141 {
142 return ((RNumeric)r).Gt(args[0]);
143 }
144 static public object num_ge(RBasic r, params object[] args)
145 {
146 return ((RNumeric)r).GE(args[0]);
147 }
148 static public object num_lt(RBasic r, params object[] args)
149 {
150 return ((RNumeric)r).Lt(args[0]);
151 }
152 static public object num_le(RBasic r, params object[] args)
153 {
154 return ((RNumeric)r).LE(args[0]);
155 }
156 static public object num_uplus(RBasic r, params object[] args)
157 {
158 return r;
159 }
160 static public object num_to_i(RBasic r, params object[] args)
161 {
162 return r.ToInteger();
163 }
164 static public object num_uminus(RBasic r, params object[] args)
165 {
166 RNumeric x;
167 RNumeric y;
168 ((RNumeric)r).ruby.oFixZero.DoCoerce(r, out x, out y);
169 return r.ruby.Funcall(x, (uint)'-', y);
170 }
171 static public object num_cmp(RBasic r, params object[] args)
172 {
173 try
174 {
175 IComparable c = (IComparable)r;
176 return c.CompareTo(args[0]);
177 }
178 catch
179 {
180 return ((RNumeric)r).CoerceBin(args[0]);
181 }
182 }
183
184 static internal void Init(NetRuby ruby)
185 {
186 RClass num = ruby.DefineClass("Numeric", ruby.cObject);
187 ruby.cNumeric = num;
188 num.DefineMethod("coerce", new RMethod(num_coerce), 1);
189
190 num.DefineMethod("to_i", new RMethod(num_to_i), 0);
191 num.DefineMethod("truncate", new RMethod(num_to_i), 0);
192
193 num.DefineMethod("+@", new RMethod(num_uplus), 0);
194 num.DefineMethod("-@", new RMethod(num_uminus), 0);
195 num.DefineMethod("===", new RMethod(num_equal), 1);
196
197 num.DefineMethod("+", new RMethod(num_plus), 1);
198 num.DefineMethod("-", new RMethod(num_minus), 1);
199 num.DefineMethod("*", new RMethod(num_mul), 1);
200 num.DefineMethod("/", new RMethod(num_div), 1);
201 num.DefineMethod("%", new RMethod(num_mod), 1);
202 num.DefineMethod("modulo", new RMethod(num_mod), 1);
203 num.DefineMethod("divmod", new RMethod(num_divmod), 1);
204 num.DefineMethod("remainder", new RMethod(num_remainder), 1);
205
206 num.DefineMethod("<=>", new RMethod(num_cmp), 1);
207 num.DefineMethod(">", new RMethod(num_gt), 1);
208 num.DefineMethod(">=", new RMethod(num_ge), 1);
209 num.DefineMethod("<", new RMethod(num_lt), 1);
210 num.DefineMethod("<=", new RMethod(num_le), 1);
211 }
212 }
213
214 public class RFloat : RNumeric, IComparable
215 {
216 internal RFloat(NetRuby rb)
217 : base (rb, rb.cFloat)
218 {
219 }
220 public RFloat(NetRuby rb, double d)
221 : base(rb, rb.cFloat)
222 {
223 dVal = d;
224 }
225
226 // as rb_Float
227 static public RFloat Float(NetRuby rb, object o)
228 {
229 if (o == null || o == rb.oNil)
230 return new RFloat(rb, 0.0);
231 if (o is int)
232 return new RFloat(rb, (double)(int)o);
233 if (o is long)
234 return new RFloat(rb, (double)(long)o);
235 if (o is double)
236 return new RFloat(rb, (double)o);
237 if (o is RFloat)
238 return (RFloat)o;
239 if (o is RBignum)
240 return new RFloat(rb, ((RBignum)o).Big2Dbl());
241 string s = null;
242 if (o is string)
243 s = (string)o;
244 else if (o is RString)
245 s = ((RString)o).ToString();
246 if (s != null)
247 {
248 s = s.Trim().Replace("_", "");
249 try
250 {
251 return new RFloat(rb, Convert.ToDouble(s));
252 }
253 catch
254 {
255 throw new eArgError("Invalid valud for Float: \"" + s + "\"");
256 }
257 }
258 return (RFloat)rb.ConvertType(o, typeof(RFloat), "Float", "to_f");
259 }
260
261 internal RFloat SetData(double d)
262 {
263 dVal = d;
264 return this;
265 }
266 public double Double
267 {
268 get { return dVal; }
269 }
270
271 static internal RInteger ToInteger(NetRuby ruby, double d)
272 {
273 if (d <= Int32.MaxValue && d >= Int32.MinValue)
274 {
275 return new RFixnum(ruby, (int)d);
276 }
277 else if (d <= Int64.MaxValue && d >= Int64.MinValue)
278 {
279 return new RBignum(ruby, (long)d);
280 }
281 return RBignum.Dbl2Big(ruby, d);
282 }
283
284 public override RInteger ToInteger()
285 {
286 double d = dVal;
287 if (d > 0.0) d = Math.Floor(d);
288 else if (d < 0.0) d = Math.Ceiling(d);
289 return ToInteger(ruby, d);
290 }
291
292 public override string ToString()
293 {
294 string s = dVal.ToString();
295 return (s.IndexOf('.') < 0) ? s + ".0" : s;
296 }
297
298 public override long ToLong()
299 {
300 if (dVal <= (double)Int64.MaxValue
301 && dVal >= (double)Int64.MinValue)
302 {
303 return Convert.ToInt64(dVal);
304 }
305 throw new eRangeError(String.Format("float {0} out of range of integer", dVal));
306 }
307 public override RFloat ToFloat()
308 {
309 return this;
310 }
311 public int CompareTo(object o)
312 {
313 double y;
314 if (convd(o, out y) == false)
315 throw new ArgumentException("object is not a Float");
316 if (dVal == y) return 0;
317 if (dVal > y) return 1;
318 if (dVal < y) return -1;
319 throw new eFloatDomainError("comparing NaN");
320 }
321 private bool convd(object o, out double y)
322 {
323 if (o is int)
324 y = (int)o;
325 else if (o is long)
326 y = (long)o;
327 else if (o is RFixnum)
328 y = ((RFixnum)o).ToLong();
329 else if (o is double)
330 y = (double)o;
331 else if (o is RFloat)
332 y = ((RFloat)o).dVal;
333 else if (o is RBignum)
334 y = ((RBignum)o).Big2Dbl();
335 else
336 {
337 y = 0.0;
338 return false;
339 }
340 return true;
341 }
342 public override bool Gt(object o)
343 {
344 double y;
345 if (convd(o, out y) == false)
346 return (bool)CoerceBin(o);
347 return (dVal > y);
348 }
349 public override bool GE(object o)
350 {
351 double y;
352 if (convd(o, out y) == false)
353 return (bool)CoerceBin(o);
354 return dVal >= y;
355 }
356 public override bool Lt(object o)
357 {
358 double y;
359 if (convd(o, out y) == false)
360 return (bool)CoerceBin(o);
361 return dVal < y;
362 }
363 public override bool LE(object o)
364 {
365 double y;
366 if (convd(o, out y) == false)
367 return (bool)CoerceBin(o);
368 return dVal <= y;
369 }
370
371 public override bool Equals(object o)
372 {
373 if (o is double)
374 return (dVal == (double)o);
375 if (o is float)
376 return (dVal == (float)o);
377 if (o is RFloat)
378 return (dVal == ((RFloat)o).dVal);
379 return false;
380 }
381 public override int GetHashCode() // for voiding CS0659 warning.
382 {
383 return base.GetHashCode();
384 }
385
386 double dVal;
387
388 public RInteger Round {
389 get {
390 double f = dVal;
391 if (f > 0.0) f = Math.Floor(f + 0.5);
392 if (f < 0.0) f = Math.Ceiling(f - 0.5);
393 return ToInteger(ruby, f);
394 }
395 }
396 public RInteger Ceil {
397 get { return ToInteger(ruby, Math.Ceiling(dVal)); }
398 }
399 public RInteger Floor {
400 get { return ToInteger(ruby, Math.Floor(dVal)); }
401 }
402 public bool IsNaN {
403 get { return Double.IsNaN(dVal); }
404 }
405 public bool IsInfinite {
406 get { return Double.IsInfinity(dVal); }
407 }
408 public bool IsFinite {
409 get { return !Double.IsInfinity(dVal); }
410 }
411
412 public override RNumeric Plus(object o)
413 {
414 if (o is int)
415 return new RFloat(ruby, dVal + (int)o);
416 if (o is long)
417 return new RFloat(ruby, dVal + (long)o);
418 if (o is RFixnum)
419 return new RFloat(ruby, dVal + ((RFixnum)o).ToLong());
420 if (o is double)
421 return new RFloat(ruby, dVal + (double)o);
422 if (o is RFloat)
423 return new RFloat(ruby, dVal + ((RFloat)o).dVal);
424 if (o is RBignum)
425 return new RFloat(ruby, dVal + ((RBignum)o).Big2Dbl());
426 return (RNumeric)CoerceBin(o);
427 }
428 public override RNumeric Minus(object o)
429 {
430 if (o is int)
431 return new RFloat(ruby, dVal - (int)o);
432 if (o is long)
433 return new RFloat(ruby, dVal - (long)o);
434 if (o is RFixnum)
435 return new RFloat(ruby, dVal - ((RFixnum)o).ToLong());
436 if (o is double)
437 return new RFloat(ruby, dVal - (double)o);
438 if (o is RFloat)
439 return new RFloat(ruby, dVal - ((RFloat)o).dVal);
440 if (o is RBignum)
441 return new RFloat(ruby, dVal - ((RBignum)o).Big2Dbl());
442 return (RNumeric)CoerceBin(o);
443 }
444 public override RNumeric Multiply(object o)
445 {
446 if (o is int)
447 return new RFloat(ruby, dVal * (int)o);
448 if (o is long)
449 return new RFloat(ruby, dVal * (long)o);
450 if (o is RFixnum)
451 return new RFloat(ruby, dVal * ((RFixnum)o).ToLong());
452 if (o is double)
453 return new RFloat(ruby, dVal * (double)o);
454 if (o is RFloat)
455 return new RFloat(ruby, dVal * ((RFloat)o).dVal);
456 if (o is RBignum)
457 return new RFloat(ruby, dVal * ((RBignum)o).Big2Dbl());
458 return (RNumeric)CoerceBin(o);
459 }
460 public override RNumeric Divide(object o)
461 {
462 double y;
463 if (o is int)
464 y = (int)o;
465 else if (o is long)
466 y = (long)o;
467 else if (o is RFixnum)
468 y = ((RFixnum)o).ToLong();
469 else if (o is double)
470 y = (double)o;
471 else if (o is RFloat)
472 y = ((RFloat)o).dVal;
473 else if (o is RBignum)
474 y = ((RBignum)o).Big2Dbl();
475 else
476 return (RNumeric)CoerceBin(o);
477 if (y == 0.0)
478 throw new DivideByZeroException("divided by 0");
479 return new RFloat(ruby, dVal / y);
480 }
481 public override RNumeric Remainder(object o)
482 {
483 double y;
484 if (o is int)
485 y = (int)o;
486 else if (o is long)
487 y = (long)o;
488 else if (o is RFixnum)
489 y = ((RFixnum)o).ToLong();
490 else if (o is double)
491 y = (double)o;
492 else if (o is RFloat)
493 y = ((RFloat)o).dVal;
494 else if (o is RBignum)
495 y = ((RBignum)o).Big2Dbl();
496 else
497 return (RNumeric)CoerceBin(o);
498 if (y == 0.0)
499 throw new DivideByZeroException("divided by 0");
500 return new RFloat(ruby, dVal % y);
501 }
502 public override RNumeric Modulo(object o)
503 {
504 double y;
505 if (o is int)
506 y = (int)o;
507 else if (o is long)
508 y = (long)o;
509 else if (o is RFixnum)
510 y = ((RFixnum)o).ToLong();
511 else if (o is double)
512 y = (double)o;
513 else if (o is RFloat)
514 y = ((RFloat)o).dVal;
515 else if (o is RBignum)
516 y = ((RBignum)o).Big2Dbl();
517 else
518 return (RNumeric)CoerceBin(o);
519 if (y == 0.0)
520 throw new DivideByZeroException("divided by 0");
521 double z = dVal % y;
522 if (z != 0.0)
523 {
524 if (dVal < 0.0 && y > 0.0 || dVal > 0.0 && y < 0.0)
525 z = z + y;
526 }
527 return new RFloat(ruby, z);
528 }
529 public override RArray DivMod(object o)
530 {
531 double y;
532 if (o is int)
533 y = (int)o;
534 else if (o is long)
535 y = (long)o;
536 else if (o is RFixnum)
537 y = ((RFixnum)o).ToLong();
538 else if (o is double)
539 y = (double)o;
540 else if (o is RFloat)
541 y = ((RFloat)o).dVal;
542 else if (o is RBignum)
543 y = ((RBignum)o).Big2Dbl();
544 else
545 return (RArray)CoerceBin(o);
546 if (y == 0.0)
547 throw new DivideByZeroException("divided by 0");
548 return RArray.AssocNew(ruby, new RFloat(ruby, dVal / y), Modulo(y));
549 }
550 static internal new void Init(NetRuby rb)
551 {
552 BindingFlags bf = BindingFlags.InvokeMethod
553 | BindingFlags.Static | BindingFlags.Public
554 | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy
555 | BindingFlags.Instance;
556 RClass flo = rb.DefineClass("Float", rb.cNumeric);
557 rb.cFloat = flo;
558 rb.oFloat = new RFloat(rb, 0.0);
559 Type obj = typeof(RFloat);
560
561 rb.ClassOf(flo).UndefMethod("new");
562
563 flo.DefineMethod("floor", obj.GetMethod("get_Floor", bf));
564 flo.DefineMethod("ceil", obj.GetMethod("get_Ceil", bf));
565 flo.DefineMethod("round", obj.GetMethod("get_Round", bf));
566 flo.DefineMethod("nan?", obj.GetMethod("get_IsNaN", bf));
567 flo.DefineMethod("infinite?", obj.GetMethod("get_IsInfinite", bf));
568 flo.DefineMethod("finite?", obj.GetMethod("get_IsFinite", bf));
569 }
570 }
571
572 public abstract class RInteger : RNumeric
573 {
574 internal RInteger(NetRuby rb, RMetaObject sp)
575 : base (rb, sp)
576 {
577 }
578
579 protected const uint BITSPERDIG = 32;
580 protected const ulong BIGRAD = (ulong)1 << (int)BITSPERDIG;
581 protected const uint DIGSPERLONG = 1;
582 protected static ulong BIGUP(ulong x)
583 {
584 return (x << (int)BITSPERDIG);
585 }
586 protected static uint BIGDN(ulong x)
587 {
588 return (uint)(x >> (int)BITSPERDIG);
589 }
590 protected static int BIGDN(long x)
591 {
592 return (int)(x >> (int)BITSPERDIG);
593 }
594 protected static uint BIGDN(uint x)
595 {
596 return (x >> (int)BITSPERDIG);
597 }
598 protected static uint BIGLO(uint x)
599 {
600 return (x & (uint)(BIGRAD - 1));
601 }
602 protected static uint BIGLO(long x)
603 {
604 return (uint)(x & (uint)(BIGRAD - 1));
605 }
606 protected static uint BIGLO(ulong x)
607 {
608 return (uint)(x & (BIGRAD - 1));
609 }
610
611 public abstract RInteger Normalize { get; }
612
613 public static int ToInt(NetRuby ruby, object o)
614 {
615 long l = ToLong(ruby, o);
616 if (l < Int32.MinValue || l > Int32.MaxValue)
617 throw new eRangeError(String.Format("integer {0} too big to convert to `int'",
618 l));
619 return (int)l;
620 }
621 public static long ToLong(NetRuby ruby, object o)
622 {
623 if (o == null)
624 {
625 throw new eTypeError("no implicit conversion from nil");
626 }
627 if (o is int) return (long)(int)o;
628 if (o is uint) return (long)(uint)o;
629 if (o is long) return (long)o;
630 if (o is RNumeric)
631 return ((RNumeric)o).ToLong();
632 if (o is string || o is RString)
633 throw new eTypeError("no implicit conversion from string");
634 if (o is bool || o is RBool)
635 throw new eTypeError("no implicit conversion from boolean");
636 RFixnum f = (RFixnum)ruby.ConvertType(o, typeof(RFixnum), "Integer", "to_int");
637 return (long)f.ToLong();
638 }
639
640 public static object StringToInteger(NetRuby ruby, string astr, int radix)
641 {
642 RBignum z = null;
643 bool badcheck = (radix == 0) ? true : false;
644 string str = astr.Trim().ToUpper().Replace("_", "");
645 bool sign = true;
646 int idx = 0;
647 if (astr.Length == 1)
648 {
649 return Convert.ToInt32(str);
650 }
651 if (str[0] == '+')
652 {
653 idx++;
654 }
655 else if (str[0] == '-')
656 {
657 idx++;
658 sign = false;
659 }
660 if (str[idx] == '+' || str[idx] == '-')
661 {
662 if (badcheck) goto bad;
663 return 0;
664 }
665 if (radix == 0)
666 {
667 if (str[idx] == '0' && (idx + 1) < str.Length)
668 {
669 char c = str[idx + 1];
670 if (c == 'X')
671 {
672 radix = 16;
673 }
674 else if (c == 'B')
675 {
676 radix = 2;
677 }
678 else
679 {
680 radix = 8;
681 }
682 }
683 else
684 {
685 radix = 10;
686 }
687 }
688 int len = str.Length;
689 if (radix == 8)
690 {
691 while (idx < str.Length && str[idx] == '0') idx++;
692 if (idx == str.Length) return 0;
693 str = str.Substring(idx);
694 len = 3 * str.Length;
695 }
696 else
697 {
698 if (radix == 16 && str[idx] == '0' && str[idx + 1] == 'X')
699 idx += 2;
700 else if (radix == 2 && str[idx] == '0' && str[idx + 1] == 'B')
701 idx += 2;
702 while (idx < str.Length && str[idx] == '0') idx++;
703 if (idx == str.Length)
704 {
705 if (badcheck) goto bad;
706 return 0;
707 }
708 str = str.Substring(idx);
709 len = 4 * str.Length;
710 }
711 uint x;
712 if (len <= 32)
713 {
714 try
715 {
716 x = Convert.ToUInt32(str, radix);
717 if (x > (uint)Int32.MaxValue)
718 {
719 return new RBignum(ruby, x, sign);
720 }
721 else
722 {
723 int xx = (int)x;
724 return (sign) ? xx : -xx;
725 }
726 }
727 catch (OverflowException)
728 {
729 ;
730 }
731 catch
732 {
733 goto bad;
734 }
735 }
736
737 len = (int)(len / BITSPERDIG) + 1;
738 uint[] zds = new uint[len];
739 int blen = 1;
740 for (idx = 0; idx < str.Length; idx++)
741 {
742 char c = str[idx];
743 switch (c)
744 {
745 case '8':
746 case '9':
747 if (radix == 8)
748 {
749 c = (char)radix;
750 break;
751 }
752 goto case '0';
753 case '7': case '6': case '5': case '4':
754 case '3': case '2': case '1': case '0':
755 c = (char)(c - '0');
756 break;
757 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
758 if (radix != 16) c = (char)radix;
759 else c = (char)(c - 'A' + 10);
760 break;
761 default:
762 c = (char)radix;
763 break;
764 }
765 if (c >= radix) break;
766 int i = 0;
767 ulong num = c;
768 for (;;)
769 {
770 while (i < blen)
771 {
772 num += (ulong)zds[i] * (ulong)radix;
773 zds[i++] = BIGLO(num);
774 num = BIGDN(num);
775 }
776 if (num != 0)
777 {
778 blen++;
779 continue;
780 }
781 break;
782 }
783 }
784 z = new RBignum(ruby, zds, sign);
785 return z;
786
787 bad:
788 throw new eArgError("Invalid value for Integer: \"" + astr + "\"");
789 }
790
791 public virtual RInteger UpTo(object o)
792 {
793 object[] up = new object[] { 1 };
794 object[] to = new object[] { o };
795 RInteger r = this;
796 for (;;)
797 {
798 if (RTest(ruby.Funcall(r, (uint)'>', to))) break;
799 ruby.Yield(r);
800 r = (RInteger)ruby.Funcall(r, (uint)'+', up);
801 }
802 return this;
803 }
804 public virtual RInteger DownTo(object o)
805 {
806 object[] down = new object[] { 1 };
807 object[] to = new object[] { o };
808 RInteger r = this;
809 for (;;)
810 {
811 if (RTest(ruby.Funcall(r, (uint)'<', to))) break;
812 ruby.Yield(r);
813 r = (RInteger)ruby.Funcall(r, (uint)'-', down);
814 }
815 return this;
816 }
817 public virtual RInteger Step(object to, object step)
818 {
819 RInteger i = this;
820 object[] tox = new object[] { to };
821 long l = ToLong(ruby, step);
822 uint cmp;
823 if (l == 0)
824 {
825 throw new eArgError("step cannot be 0");
826 }
827 object stepx = new object[] { l };
828 if (RTest(ruby.Funcall(step, '>', new object[] {0})))
829 {
830 cmp = (uint)'>';
831 }
832 else
833 {
834 cmp = (uint)'<';
835 }
836 for (;;)
837 {
838 if (RTest(ruby.Funcall(i, cmp, tox))) break;
839 ruby.Yield(i);
840 i = (RInteger)ruby.Funcall(i, (uint)'+', stepx);
841 }
842 return this;
843 }
844 internal static object int_upto(RBasic r, params object[] args)
845 {
846 return ((RInteger)r).UpTo(args[0]);
847 }
848 internal static object int_downto(RBasic r, params object[] args)
849 {
850 return ((RInteger)r).DownTo(args[0]);
851 }
852 internal static object int_step(RBasic r, params object[] args)
853 {
854 return ((RInteger)r).Step(args[0], args[1]);
855 }
856
857 internal static new void Init(NetRuby rb)
858 {
859 RClass it = rb.DefineClass("Integer", rb.cNumeric);
860 rb.cInteger = it;
861 rb.ClassOf(it).UndefMethod("new");
862
863 it.DefineMethod("upto", new RMethod(int_upto), 1);
864 it.DefineMethod("downto", new RMethod(int_downto), 1);
865 it.DefineMethod("step", new RMethod(int_step), 2);
866
867 it.DefineMethod("to_int", new RMethod(num_to_i), 0);
868 it.DefineMethod("floor", new RMethod(num_to_i), 0);
869 it.DefineMethod("ceil", new RMethod(num_to_i), 0);
870 it.DefineMethod("round", new RMethod(num_to_i), 0);
871
872 }
873 }
874
875 public class RFixnum : RInteger, IComparable, ICloneable
876 {
877 internal RFixnum(NetRuby rb)
878 : base (rb, rb.cFixnum)
879 {
880 iVal = 0;
881 }
882 internal RFixnum(NetRuby rb, int i)
883 : base (rb, rb.cFixnum)
884 {
885 iVal = i;
886 }
887 public override object Clone()
888 {
889 return MemberwiseClone();
890 }
891 internal RFixnum SetData(int n)
892 {
893 iVal = n;
894 return this;
895 }
896 internal int GetData()
897 {
898 return iVal;
899 }
900 public override RInteger Normalize
901 {
902 get { return this; }
903 }
904
905 public int CompareTo(object o)
906 {
907 int y;
908 if (o is int)
909 y = (int)o;
910 else if (o is RFixnum)
911 y = ((RFixnum)o).iVal;
912 else
913 {
914 throw new ArgumentException("object is not a Integer");
915 }
916 if (iVal == y) return 0;
917 if (iVal > y) return 1;
918 return -1;
919 }
920 public override bool Equals(object o)
921 {
922 if (o is int)
923 return iVal == (int)o;
924 if (o is long)
925 return iVal == (long)o;
926 if (o is double)
927 return iVal == (double)o;
928 if (o is float)
929 return iVal == (float)o;
930 if (o is RFloat)
931 return iVal == ((RFloat)o).Double;
932 if (o is RFixnum)
933 return ((RFixnum)o).Equals(iVal);
934 return ruby.Equal(o, this);
935 }
936 public override int GetHashCode() // for voiding CS0659 warning.
937 {
938 return base.GetHashCode();
939 }
940 public override string ToString()
941 {
942 return iVal.ToString();
943 }
944 public override RInteger ToInteger()
945 {
946 return (RInteger)Clone();
947 }
948 public int ToInt()
949 {
950 return iVal;
951 }
952 public override long ToLong()
953 {
954 return (long)iVal;
955 }
956 public override RChar ToChar()
957 {
958 return new RChar(ruby, (char)iVal);
959 }
960 public override RFloat ToFloat()
961 {
962 return new RFloat(ruby, Convert.ToDouble(iVal));
963 }
964 public override int id
965 {
966 get {
967 int n = iVal;
968 n &= 0x7fffffff;
969 return (n << 1) | 1;
970 }
971 }
972 int iVal;
973
974 private bool convi(object o, out int y)
975 {
976 if (o is int)
977 y = (int)o;
978 else if (o is RFixnum)
979 y = ((RFixnum)o).iVal;
980 else
981 {
982 y = 0;
983 return false;
984 }
985 return true;
986 }
987 public override bool Gt(object o)
988 {
989 int y;
990 if (convi(o, out y) == false)
991 return (bool)CoerceBin(o);
992 return (iVal > y);
993 }
994 public override bool GE(object o)
995 {
996 int y;
997 if (convi(o, out y) == false)
998 return (bool)CoerceBin(o);
999 return (iVal >= y);
1000 }
1001 public override bool Lt(object o)
1002 {
1003 int y;
1004 if (convi(o, out y) == false)
1005 return (bool)CoerceBin(o);
1006 return (iVal < y);
1007 }
1008 public override bool LE(object o)
1009 {
1010 int y;
1011 if (convi(o, out y) == false)
1012 return (bool)CoerceBin(o);
1013 return (iVal <= y);
1014 }
1015 public override RNumeric Plus(object o)
1016 {
1017 long l;
1018 if (o is int)
1019 l = (int)o;
1020 else if (o is RFixnum)
1021 l = ((RFixnum)o).iVal;
1022 else
1023 {
1024 if (o is double)
1025 return new RFloat(ruby, (double)o + iVal);
1026 if (o is RFloat)
1027 return new RFloat(ruby, ((RFloat)o).Double + iVal);
1028 return (RNumeric)CoerceBin(o);
1029 }
1030 l += (long)iVal;
1031 if (l > Int32.MaxValue || l < Int32.MinValue)
1032 {
1033 return new RBignum(ruby, l);
1034 }
1035 return new RFixnum(ruby, (int)l);
1036 }
1037 public override RNumeric Minus(object o)
1038 {
1039 long l;
1040 if (o is int)
1041 l = (int)o;
1042 else if (o is RFixnum)
1043 l = ((RFixnum)o).iVal;
1044 else
1045 {
1046 if (o is long)
1047 return new RBignum(ruby, (long)iVal - (long)o);
1048 if (o is double)
1049 return new RFloat(ruby, (double)iVal - (double)o);
1050 if (o is RFloat)
1051 return new RFloat(ruby, (double)iVal - ((RFloat)o).Double);
1052 return (RNumeric)CoerceBin(o);
1053 }
1054 l = (long)iVal - l;
1055 if (l > Int32.MaxValue || l < Int32.MinValue)
1056 {
1057 return new RBignum(ruby, l);
1058 }
1059 return new RFixnum(ruby, (int)l);
1060 }
1061 public override RNumeric Multiply(object o)
1062 {
1063 long l;
1064 if (o is int)
1065 l = (int)o;
1066 else if (o is RFixnum)
1067 l = ((RFixnum)o).iVal;
1068 else
1069 {
1070 if (o is double)
1071 return new RFloat(ruby, (double)iVal * (double)o);
1072 if (o is RFloat)
1073 return new RFloat(ruby, (double)iVal * ((RFloat)o).Double);
1074 return (RNumeric)CoerceBin(o);
1075 }
1076 l *= iVal;
1077 if (l > Int32.MaxValue || l < Int32.MinValue)
1078 {
1079 return new RBignum(ruby, l);
1080 }
1081 return new RFixnum(ruby, (int)l);
1082 }
1083 public override RNumeric Divide(object o)
1084 {
1085 int y;
1086 if (o is int) y = (int)o;
1087 else if (o is RFixnum) y = (int)((RFixnum)o).iVal;
1088 else
1089 {
1090 if (o is long)
1091 {
1092 long l = (long)o;
1093 if (l == 0) throw new DivideByZeroException("divided by 0");
1094 return new RBignum(ruby, (long)iVal % l);
1095 }
1096 if (o is double)
1097 {
1098 double d = (double)o;
1099 if (d == 0.0) throw new DivideByZeroException("divided by 0");
1100 return new RFloat(ruby, (double)iVal % d);
1101 }
1102 if (o is RFloat)
1103 {
1104 double d = ((RFloat)o).Double;
1105 if (d == 0.0) throw new DivideByZeroException("divided by 0");
1106 return new RFloat(ruby, (double)iVal % d);
1107 }
1108 return (RNumeric)CoerceBin(o);
1109 }
1110 if (y == 0) throw new DivideByZeroException("divided by 0");
1111 int mod;
1112 int div = divmod(y, out mod);
1113 return new RFixnum(ruby, div);
1114 }
1115 public override RNumeric Remainder(object o)
1116 {
1117 int y;
1118 if (o is int) y = (int)o;
1119 else if (o is RFixnum) y = (int)((RFixnum)o).iVal;
1120 else
1121 {
1122 if (o is long)
1123 {
1124 long l = (long)o;
1125 if (l == 0) throw new DivideByZeroException("divided by 0");
1126 return new RBignum(ruby, (long)iVal % l);
1127 }
1128 if (o is double)
1129 {
1130 double d = (double)o;
1131 if (d == 0.0) throw new DivideByZeroException("divided by 0");
1132 return new RFloat(ruby, (double)iVal % d);
1133 }
1134 if (o is RFloat)
1135 {
1136 double d = ((RFloat)o).Double;
1137 if (d == 0.0) throw new DivideByZeroException("divided by 0");
1138 return new RFloat(ruby, (double)iVal % d);
1139 }
1140 return (RNumeric)CoerceBin(o);
1141 }
1142 if (y == 0) throw new DivideByZeroException("divided by 0");
1143 return new RFixnum(ruby, iVal % y);
1144 }
1145 public override RNumeric Modulo(object o)
1146 {
1147 int y;
1148 if (o is int) y = (int)o;
1149 else if (o is RFixnum) y = (int)((RFixnum)o).iVal;
1150 else
1151 {
1152 return (RNumeric)CoerceBin(o);
1153 }
1154 int mod;
1155 int d = divmod(y, out mod);
1156 return new RFixnum(ruby, mod);
1157 }
1158 private int divmod(int y, out int mod)
1159 {
1160 int div;
1161 mod = 0;
1162 if (y == 0)
1163 throw new DivideByZeroException("divided by 0");
1164 if (y < 0)
1165 {
1166 if (iVal < 0)
1167 div = -iVal / -y;
1168 else
1169 div = -(iVal / -y);
1170 }
1171 else
1172 {
1173 if (iVal < 0)
1174 div = -(-iVal / y);
1175 else
1176 div = iVal / y;
1177 }
1178 mod = iVal - div * y;
1179 if (mod < 0 && y > 0 || mod > 0 && y < 0)
1180 {
1181 mod += y;
1182 div -= 1;
1183 }
1184 return div;
1185 }
1186 public override RArray DivMod(object o)
1187 {
1188 int y;
1189 if (o is int) y = (int)o;
1190 else if (o is RFixnum) y = (int)((RFixnum)o).iVal;
1191 else
1192 {
1193 return (RArray)CoerceBin(o);
1194 }
1195 int mod;
1196 int d = divmod(y, out mod);
1197 return RArray.AssocNew(ruby, new RFixnum(ruby, d), new RFixnum(ruby, mod));
1198 }
1199
1200 static internal object fix_equal(RBasic r, params object[] args)
1201 {
1202 return ((RFixnum)r).Equals(args[0]);
1203 }
1204
1205 static internal new void Init(NetRuby rb)
1206 {
1207 RClass fix = rb.DefineClass("Fixnum", rb.cInteger);
1208 rb.cFixnum = fix;
1209 RFixnum o = new RFixnum(rb);
1210 rb.oFixnum = o;
1211 rb.oFixZero = new RFixnum(rb, 0);
1212 fix.DefineMethod("to_f", new RMethod(o.ruby_to_f), 0);
1213
1214 fix.DefineMethod("to_c", new RMethod(o.ruby_to_c), 0);
1215
1216 fix.DefineMethod("==", new RMethod(fix_equal), 1);
1217 }
1218 }
1219 }

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26