source: EcnlProtoTool/trunk/mruby-2.1.1/src/numeric.c@ 439

Last change on this file since 439 was 439, checked in by coas-nagasima, 4 years ago

mrubyを2.1.1に更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 38.7 KB
Line 
1/*
2** numeric.c - Numeric, Integer, Float, Fixnum class
3**
4** See Copyright Notice in mruby.h
5*/
6
7#ifndef MRB_WITHOUT_FLOAT
8#include <float.h>
9#include <math.h>
10#endif
11#include <limits.h>
12#include <stdlib.h>
13#include <string.h>
14
15#include <mruby.h>
16#include <mruby/array.h>
17#include <mruby/numeric.h>
18#include <mruby/string.h>
19#include <mruby/class.h>
20
21#ifndef MRB_WITHOUT_FLOAT
22#ifdef MRB_USE_FLOAT
23#define trunc(f) truncf(f)
24#define floor(f) floorf(f)
25#define ceil(f) ceilf(f)
26#define fmod(x,y) fmodf(x,y)
27#define FLO_TO_STR_PREC 8
28#else
29#define FLO_TO_STR_PREC 16
30#endif
31#endif
32
33#ifndef MRB_WITHOUT_FLOAT
34MRB_API mrb_float
35mrb_to_flo(mrb_state *mrb, mrb_value val)
36{
37 switch (mrb_type(val)) {
38 case MRB_TT_FIXNUM:
39 return (mrb_float)mrb_fixnum(val);
40 case MRB_TT_FLOAT:
41 break;
42 default:
43 mrb_raise(mrb, E_TYPE_ERROR, "non float value");
44 }
45 return mrb_float(val);
46}
47
48MRB_API mrb_value
49mrb_int_value(mrb_state *mrb, mrb_float f)
50{
51 if (FIXABLE_FLOAT(f)) {
52 return mrb_fixnum_value((mrb_int)f);
53 }
54 return mrb_float_value(mrb, f);
55}
56#endif
57
58/*
59 * call-seq:
60 *
61 * num ** other -> num
62 *
63 * Raises <code>num</code> the <code>other</code> power.
64 *
65 * 2.0**3 #=> 8.0
66 */
67static mrb_value
68integral_pow(mrb_state *mrb, mrb_value x)
69{
70 mrb_value y;
71#ifndef MRB_WITHOUT_FLOAT
72 mrb_float d;
73#endif
74
75 mrb_get_args(mrb, "o", &y);
76 if (mrb_fixnum_p(x) && mrb_fixnum_p(y)) {
77 /* try ipow() */
78 mrb_int base = mrb_fixnum(x);
79 mrb_int exp = mrb_fixnum(y);
80 mrb_int result = 1;
81
82 if (exp < 0)
83#ifdef MRB_WITHOUT_FLOAT
84 return mrb_fixnum_value(0);
85#else
86 goto float_pow;
87#endif
88 for (;;) {
89 if (exp & 1) {
90 if (mrb_int_mul_overflow(result, base, &result)) {
91#ifndef MRB_WITHOUT_FLOAT
92 goto float_pow;
93#endif
94 }
95 }
96 exp >>= 1;
97 if (exp == 0) break;
98 if (mrb_int_mul_overflow(base, base, &base)) {
99#ifndef MRB_WITHOUT_FLOAT
100 goto float_pow;
101#endif
102 }
103 }
104 return mrb_fixnum_value(result);
105 }
106#ifdef MRB_WITHOUT_FLOAT
107 mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
108#else
109 float_pow:
110 d = pow(mrb_to_flo(mrb, x), mrb_to_flo(mrb, y));
111 return mrb_float_value(mrb, d);
112#endif
113}
114
115static mrb_value
116integral_idiv(mrb_state *mrb, mrb_value x)
117{
118#ifdef MRB_WITHOUT_FLOAT
119 mrb_value y;
120
121 mrb_get_args(mrb, "o", &y);
122 if (!mrb_fixnum_p(y)) {
123 mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
124 }
125 return mrb_fixnum_value(mrb_fixnum(x) / mrb_fixnum(y));
126#else
127 mrb_float y;
128
129 mrb_get_args(mrb, "f", &y);
130 return mrb_int_value(mrb, mrb_to_flo(mrb, x) / y);
131#endif
132}
133
134/* 15.2.8.3.4 */
135/* 15.2.9.3.4 */
136/*
137 * call-seq:
138 * num / other -> num
139 *
140 * Performs division: the class of the resulting object depends on
141 * the class of <code>num</code> and on the magnitude of the
142 * result.
143 */
144
145/* 15.2.9.3.19(x) */
146/*
147 * call-seq:
148 * num.quo(numeric) -> real
149 *
150 * Returns most exact division.
151 */
152
153static mrb_value
154integral_div(mrb_state *mrb, mrb_value x)
155{
156#ifdef MRB_WITHOUT_FLOAT
157 mrb_value y;
158
159 mrb_get_args(mrb, "o", &y);
160 if (!mrb_fixnum_p(y)) {
161 mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
162 }
163 return mrb_fixnum_value(mrb_fixnum(x) / mrb_fixnum(y));
164#else
165 mrb_float y;
166
167 mrb_get_args(mrb, "f", &y);
168 return mrb_float_value(mrb, mrb_to_flo(mrb, x) / y);
169#endif
170}
171
172static mrb_value
173integral_coerce_step_counter(mrb_state *mrb, mrb_value self)
174{
175 mrb_value num, step;
176
177 mrb_get_args(mrb, "oo", &num, &step);
178
179#ifndef MRB_WITHOUT_FLOAT
180 if (mrb_float_p(self) || mrb_float_p(num) || mrb_float_p(step)) {
181 return mrb_Float(mrb, self);
182 }
183#endif
184
185 return self;
186}
187
188#ifndef MRB_WITHOUT_FLOAT
189/********************************************************************
190 *
191 * Document-class: Float
192 *
193 * <code>Float</code> objects represent inexact real numbers using
194 * the native architecture's double-precision floating point
195 * representation.
196 */
197
198/* 15.2.9.3.16(x) */
199/*
200 * call-seq:
201 * flt.to_s -> string
202 *
203 * Returns a string containing a representation of self. As well as a
204 * fixed or exponential form of the number, the call may return
205 * "<code>NaN</code>", "<code>Infinity</code>", and
206 * "<code>-Infinity</code>".
207 */
208
209static mrb_value
210flo_to_s(mrb_state *mrb, mrb_value flt)
211{
212 mrb_float f = mrb_float(flt);
213
214 if (isinf(f)) {
215 return f < 0 ? mrb_str_new_lit(mrb, "-Infinity")
216 : mrb_str_new_lit(mrb, "Infinity");
217 }
218 else if (isnan(f)) {
219 return mrb_str_new_lit(mrb, "NaN");
220 }
221 else {
222 char fmt[] = "%." MRB_STRINGIZE(FLO_TO_STR_PREC) "g";
223 mrb_value str = mrb_float_to_str(mrb, flt, fmt);
224 mrb_int len;
225 char *begp, *p, *endp;
226
227 insert_dot_zero:
228 begp = RSTRING_PTR(str);
229 len = RSTRING_LEN(str);
230 for (p = begp, endp = p + len; p < endp; ++p) {
231 if (*p == '.') {
232 return str;
233 }
234 else if (*p == 'e') {
235 ptrdiff_t e_pos = p - begp;
236 mrb_str_cat(mrb, str, ".0", 2);
237 p = RSTRING_PTR(str) + e_pos;
238 memmove(p + 2, p, len - e_pos);
239 memcpy(p, ".0", 2);
240 return str;
241 }
242 }
243
244 if (FLO_TO_STR_PREC + (begp[0] == '-') <= len) {
245 --fmt[sizeof(fmt) - 3]; /* %.16g(%.8g) -> %.15g(%.7g) */
246 str = mrb_float_to_str(mrb, flt, fmt);
247 goto insert_dot_zero;
248 }
249
250 return str;
251 }
252}
253
254/* 15.2.9.3.2 */
255/*
256 * call-seq:
257 * float - other -> float
258 *
259 * Returns a new float which is the difference of <code>float</code>
260 * and <code>other</code>.
261 */
262
263static mrb_value
264flo_minus(mrb_state *mrb, mrb_value x)
265{
266 mrb_value y;
267
268 mrb_get_args(mrb, "o", &y);
269 return mrb_float_value(mrb, mrb_float(x) - mrb_to_flo(mrb, y));
270}
271
272/* 15.2.9.3.3 */
273/*
274 * call-seq:
275 * float * other -> float
276 *
277 * Returns a new float which is the product of <code>float</code>
278 * and <code>other</code>.
279 */
280
281static mrb_value
282flo_mul(mrb_state *mrb, mrb_value x)
283{
284 mrb_value y;
285
286 mrb_get_args(mrb, "o", &y);
287 return mrb_float_value(mrb, mrb_float(x) * mrb_to_flo(mrb, y));
288}
289
290static void
291flodivmod(mrb_state *mrb, double x, double y, mrb_float *divp, mrb_float *modp)
292{
293 double div, mod;
294
295 if (isnan(y)) {
296 /* y is NaN so all results are NaN */
297 div = mod = y;
298 goto exit;
299 }
300 if (y == 0.0) {
301 if (x == 0) div = NAN;
302 else if (x > 0.0) div = INFINITY;
303 else div = -INFINITY; /* x < 0.0 */
304 mod = NAN;
305 goto exit;
306 }
307 if ((x == 0.0) || (isinf(y) && !isinf(x))) {
308 mod = x;
309 }
310 else {
311 mod = fmod(x, y);
312 }
313 if (isinf(x) && !isinf(y)) {
314 div = x;
315 }
316 else {
317 div = (x - mod) / y;
318 if (modp && divp) div = round(div);
319 }
320 if (div == 0) div = 0.0;
321 if (mod == 0) mod = 0.0;
322 if (y*mod < 0) {
323 mod += y;
324 div -= 1.0;
325 }
326 exit:
327 if (modp) *modp = mod;
328 if (divp) *divp = div;
329}
330
331/* 15.2.9.3.5 */
332/*
333 * call-seq:
334 * flt % other -> float
335 * flt.modulo(other) -> float
336 *
337 * Return the modulo after division of <code>flt</code> by <code>other</code>.
338 *
339 * 6543.21.modulo(137) #=> 104.21
340 * 6543.21.modulo(137.24) #=> 92.9299999999996
341 */
342
343static mrb_value
344flo_mod(mrb_state *mrb, mrb_value x)
345{
346 mrb_value y;
347 mrb_float mod;
348
349 mrb_get_args(mrb, "o", &y);
350
351 flodivmod(mrb, mrb_float(x), mrb_to_flo(mrb, y), 0, &mod);
352 return mrb_float_value(mrb, mod);
353}
354#endif
355
356/* 15.2.8.3.16 */
357/*
358 * call-seq:
359 * num.eql?(numeric) -> true or false
360 *
361 * Returns <code>true</code> if <i>num</i> and <i>numeric</i> are the
362 * same type and have equal values.
363 *
364 * 1 == 1.0 #=> true
365 * 1.eql?(1.0) #=> false
366 * (1.0).eql?(1.0) #=> true
367 */
368static mrb_value
369fix_eql(mrb_state *mrb, mrb_value x)
370{
371 mrb_value y;
372
373 mrb_get_args(mrb, "o", &y);
374 if (!mrb_fixnum_p(y)) return mrb_false_value();
375 return mrb_bool_value(mrb_fixnum(x) == mrb_fixnum(y));
376}
377
378#ifndef MRB_WITHOUT_FLOAT
379static mrb_value
380flo_eql(mrb_state *mrb, mrb_value x)
381{
382 mrb_value y;
383
384 mrb_get_args(mrb, "o", &y);
385 if (!mrb_float_p(y)) return mrb_false_value();
386 return mrb_bool_value(mrb_float(x) == mrb_float(y));
387}
388
389/* 15.2.9.3.7 */
390/*
391 * call-seq:
392 * flt == obj -> true or false
393 *
394 * Returns <code>true</code> only if <i>obj</i> has the same value
395 * as <i>flt</i>. Contrast this with <code>Float#eql?</code>, which
396 * requires <i>obj</i> to be a <code>Float</code>.
397 *
398 * 1.0 == 1 #=> true
399 *
400 */
401
402static mrb_value
403flo_eq(mrb_state *mrb, mrb_value x)
404{
405 mrb_value y;
406 mrb_get_args(mrb, "o", &y);
407
408 switch (mrb_type(y)) {
409 case MRB_TT_FIXNUM:
410 return mrb_bool_value(mrb_float(x) == (mrb_float)mrb_fixnum(y));
411 case MRB_TT_FLOAT:
412 return mrb_bool_value(mrb_float(x) == mrb_float(y));
413 default:
414 return mrb_false_value();
415 }
416}
417
418static int64_t
419value_int64(mrb_state *mrb, mrb_value x)
420{
421 switch (mrb_type(x)) {
422 case MRB_TT_FIXNUM:
423 return (int64_t)mrb_fixnum(x);
424 break;
425 case MRB_TT_FLOAT:
426 return (int64_t)mrb_float(x);
427 default:
428 mrb_raise(mrb, E_TYPE_ERROR, "cannot convert to Integer");
429 break;
430 }
431 /* not reached */
432 return 0;
433}
434
435static mrb_value
436int64_value(mrb_state *mrb, int64_t v)
437{
438 if (TYPED_FIXABLE(v,int64_t)) {
439 return mrb_fixnum_value((mrb_int)v);
440 }
441 return mrb_float_value(mrb, (mrb_float)v);
442}
443
444static mrb_value
445flo_rev(mrb_state *mrb, mrb_value x)
446{
447 int64_t v1;
448 v1 = (int64_t)mrb_float(x);
449 return int64_value(mrb, ~v1);
450}
451
452static mrb_value
453flo_and(mrb_state *mrb, mrb_value x)
454{
455 mrb_value y;
456 int64_t v1, v2;
457 mrb_get_args(mrb, "o", &y);
458
459 v1 = (int64_t)mrb_float(x);
460 v2 = value_int64(mrb, y);
461 return int64_value(mrb, v1 & v2);
462}
463
464static mrb_value
465flo_or(mrb_state *mrb, mrb_value x)
466{
467 mrb_value y;
468 int64_t v1, v2;
469 mrb_get_args(mrb, "o", &y);
470
471 v1 = (int64_t)mrb_float(x);
472 v2 = value_int64(mrb, y);
473 return int64_value(mrb, v1 | v2);
474}
475
476static mrb_value
477flo_xor(mrb_state *mrb, mrb_value x)
478{
479 mrb_value y;
480 int64_t v1, v2;
481 mrb_get_args(mrb, "o", &y);
482
483 v1 = (int64_t)mrb_float(x);
484 v2 = value_int64(mrb, y);
485 return int64_value(mrb, v1 ^ v2);
486}
487
488static mrb_value
489flo_shift(mrb_state *mrb, mrb_value x, mrb_int width)
490{
491 mrb_float val;
492
493 if (width == 0) {
494 return x;
495 }
496 val = mrb_float(x);
497 if (width < 0) {
498 while (width++) {
499 val /= 2;
500 if (val < 1.0) {
501 val = 0;
502 break;
503 }
504 }
505#if defined(_ISOC99_SOURCE)
506 val = trunc(val);
507#else
508 if (val > 0){
509 val = floor(val);
510 } else {
511 val = ceil(val);
512 }
513#endif
514 if (val == 0 && mrb_float(x) < 0) {
515 return mrb_fixnum_value(-1);
516 }
517 }
518 else {
519 while (width--) {
520 val *= 2;
521 }
522 }
523 return mrb_int_value(mrb, val);
524}
525
526static mrb_value
527flo_rshift(mrb_state *mrb, mrb_value x)
528{
529 mrb_int width;
530
531 mrb_get_args(mrb, "i", &width);
532 return flo_shift(mrb, x, -width);
533}
534
535static mrb_value
536flo_lshift(mrb_state *mrb, mrb_value x)
537{
538 mrb_int width;
539
540 mrb_get_args(mrb, "i", &width);
541 return flo_shift(mrb, x, width);
542}
543
544/* 15.2.9.3.13 */
545/*
546 * call-seq:
547 * flt.to_f -> self
548 *
549 * As <code>flt</code> is already a float, returns +self+.
550 */
551
552static mrb_value
553flo_to_f(mrb_state *mrb, mrb_value num)
554{
555 return num;
556}
557
558/* 15.2.9.3.11 */
559/*
560 * call-seq:
561 * flt.infinite? -> nil, -1, +1
562 *
563 * Returns <code>nil</code>, -1, or +1 depending on whether <i>flt</i>
564 * is finite, -infinity, or +infinity.
565 *
566 * (0.0).infinite? #=> nil
567 * (-1.0/0.0).infinite? #=> -1
568 * (+1.0/0.0).infinite? #=> 1
569 */
570
571static mrb_value
572flo_infinite_p(mrb_state *mrb, mrb_value num)
573{
574 mrb_float value = mrb_float(num);
575
576 if (isinf(value)) {
577 return mrb_fixnum_value(value < 0 ? -1 : 1);
578 }
579 return mrb_nil_value();
580}
581
582/* 15.2.9.3.9 */
583/*
584 * call-seq:
585 * flt.finite? -> true or false
586 *
587 * Returns <code>true</code> if <i>flt</i> is a valid IEEE floating
588 * point number (it is not infinite, and <code>nan?</code> is
589 * <code>false</code>).
590 *
591 */
592
593static mrb_value
594flo_finite_p(mrb_state *mrb, mrb_value num)
595{
596 return mrb_bool_value(isfinite(mrb_float(num)));
597}
598
599void
600mrb_check_num_exact(mrb_state *mrb, mrb_float num)
601{
602 if (isinf(num)) {
603 mrb_raise(mrb, E_FLOATDOMAIN_ERROR, num < 0 ? "-Infinity" : "Infinity");
604 }
605 if (isnan(num)) {
606 mrb_raise(mrb, E_FLOATDOMAIN_ERROR, "NaN");
607 }
608}
609
610/* 15.2.9.3.10 */
611/*
612 * call-seq:
613 * flt.floor -> integer
614 *
615 * Returns the largest integer less than or equal to <i>flt</i>.
616 *
617 * 1.2.floor #=> 1
618 * 2.0.floor #=> 2
619 * (-1.2).floor #=> -2
620 * (-2.0).floor #=> -2
621 */
622
623static mrb_value
624flo_floor(mrb_state *mrb, mrb_value num)
625{
626 mrb_float f = floor(mrb_float(num));
627
628 mrb_check_num_exact(mrb, f);
629 return mrb_int_value(mrb, f);
630}
631
632/* 15.2.9.3.8 */
633/*
634 * call-seq:
635 * flt.ceil -> integer
636 *
637 * Returns the smallest <code>Integer</code> greater than or equal to
638 * <i>flt</i>.
639 *
640 * 1.2.ceil #=> 2
641 * 2.0.ceil #=> 2
642 * (-1.2).ceil #=> -1
643 * (-2.0).ceil #=> -2
644 */
645
646static mrb_value
647flo_ceil(mrb_state *mrb, mrb_value num)
648{
649 mrb_float f = ceil(mrb_float(num));
650
651 mrb_check_num_exact(mrb, f);
652 return mrb_int_value(mrb, f);
653}
654
655/* 15.2.9.3.12 */
656/*
657 * call-seq:
658 * flt.round([ndigits]) -> integer or float
659 *
660 * Rounds <i>flt</i> to a given precision in decimal digits (default 0 digits).
661 * Precision may be negative. Returns a floating point number when ndigits
662 * is more than zero.
663 *
664 * 1.4.round #=> 1
665 * 1.5.round #=> 2
666 * 1.6.round #=> 2
667 * (-1.5).round #=> -2
668 *
669 * 1.234567.round(2) #=> 1.23
670 * 1.234567.round(3) #=> 1.235
671 * 1.234567.round(4) #=> 1.2346
672 * 1.234567.round(5) #=> 1.23457
673 *
674 * 34567.89.round(-5) #=> 0
675 * 34567.89.round(-4) #=> 30000
676 * 34567.89.round(-3) #=> 35000
677 * 34567.89.round(-2) #=> 34600
678 * 34567.89.round(-1) #=> 34570
679 * 34567.89.round(0) #=> 34568
680 * 34567.89.round(1) #=> 34567.9
681 * 34567.89.round(2) #=> 34567.89
682 * 34567.89.round(3) #=> 34567.89
683 *
684 */
685
686static mrb_value
687flo_round(mrb_state *mrb, mrb_value num)
688{
689 double number, f;
690 mrb_int ndigits = 0;
691 mrb_int i;
692
693 mrb_get_args(mrb, "|i", &ndigits);
694 number = mrb_float(num);
695
696 if (0 < ndigits && (isinf(number) || isnan(number))) {
697 return num;
698 }
699 mrb_check_num_exact(mrb, number);
700
701 f = 1.0;
702 i = ndigits >= 0 ? ndigits : -ndigits;
703 if (ndigits > DBL_DIG+2) return num;
704 while (--i >= 0)
705 f = f*10.0;
706
707 if (isinf(f)) {
708 if (ndigits < 0) number = 0;
709 }
710 else {
711 double d;
712
713 if (ndigits < 0) number /= f;
714 else number *= f;
715
716 /* home-made inline implementation of round(3) */
717 if (number > 0.0) {
718 d = floor(number);
719 number = d + (number - d >= 0.5);
720 }
721 else if (number < 0.0) {
722 d = ceil(number);
723 number = d - (d - number >= 0.5);
724 }
725
726 if (ndigits < 0) number *= f;
727 else number /= f;
728 }
729
730 if (ndigits > 0) {
731 if (!isfinite(number)) return num;
732 return mrb_float_value(mrb, number);
733 }
734 return mrb_int_value(mrb, number);
735}
736
737/* 15.2.9.3.14 */
738/* 15.2.9.3.15 */
739/*
740 * call-seq:
741 * flt.to_i -> integer
742 * flt.truncate -> integer
743 *
744 * Returns <i>flt</i> truncated to an <code>Integer</code>.
745 */
746
747static mrb_value
748flo_truncate(mrb_state *mrb, mrb_value num)
749{
750 mrb_float f = mrb_float(num);
751
752 if (f > 0.0) f = floor(f);
753 if (f < 0.0) f = ceil(f);
754
755 mrb_check_num_exact(mrb, f);
756 return mrb_int_value(mrb, f);
757}
758
759static mrb_value
760flo_nan_p(mrb_state *mrb, mrb_value num)
761{
762 return mrb_bool_value(isnan(mrb_float(num)));
763}
764#endif
765
766/*
767 * Document-class: Integer
768 *
769 * <code>Integer</code> is the basis for the two concrete classes that
770 * hold whole numbers, <code>Bignum</code> and <code>Fixnum</code>.
771 *
772 */
773
774
775/*
776 * call-seq:
777 * int.to_i -> integer
778 *
779 * As <i>int</i> is already an <code>Integer</code>, all these
780 * methods simply return the receiver.
781 */
782
783static mrb_value
784int_to_i(mrb_state *mrb, mrb_value num)
785{
786 return num;
787}
788
789static mrb_value
790fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y)
791{
792 mrb_int a;
793
794 a = mrb_fixnum(x);
795 if (mrb_fixnum_p(y)) {
796 mrb_int b, c;
797
798 if (a == 0) return x;
799 b = mrb_fixnum(y);
800 if (mrb_int_mul_overflow(a, b, &c)) {
801#ifndef MRB_WITHOUT_FLOAT
802 return mrb_float_value(mrb, (mrb_float)a * (mrb_float)b);
803#endif
804 }
805 return mrb_fixnum_value(c);
806 }
807#ifdef MRB_WITHOUT_FLOAT
808 mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
809#else
810 return mrb_float_value(mrb, (mrb_float)a * mrb_to_flo(mrb, y));
811#endif
812}
813
814MRB_API mrb_value
815mrb_num_mul(mrb_state *mrb, mrb_value x, mrb_value y)
816{
817 if (mrb_fixnum_p(x)) {
818 return fixnum_mul(mrb, x, y);
819 }
820#ifndef MRB_WITHOUT_FLOAT
821 if (mrb_float_p(x)) {
822 return mrb_float_value(mrb, mrb_float(x) * mrb_to_flo(mrb, y));
823 }
824#endif
825 mrb_raise(mrb, E_TYPE_ERROR, "no number multiply");
826 return mrb_nil_value(); /* not reached */
827}
828
829/* 15.2.8.3.3 */
830/*
831 * call-seq:
832 * fix * numeric -> numeric_result
833 *
834 * Performs multiplication: the class of the resulting object depends on
835 * the class of <code>numeric</code> and on the magnitude of the
836 * result.
837 */
838
839static mrb_value
840fix_mul(mrb_state *mrb, mrb_value x)
841{
842 mrb_value y;
843
844 mrb_get_args(mrb, "o", &y);
845 return fixnum_mul(mrb, x, y);
846}
847
848static void
849fixdivmod(mrb_state *mrb, mrb_int x, mrb_int y, mrb_int *divp, mrb_int *modp)
850{
851 mrb_int div, mod;
852
853 /* TODO: add mrb_assert(y != 0) to make sure */
854
855 if (y < 0) {
856 if (x < 0)
857 div = -x / -y;
858 else
859 div = - (x / -y);
860 }
861 else {
862 if (x < 0)
863 div = - (-x / y);
864 else
865 div = x / y;
866 }
867 mod = x - div*y;
868 if ((mod < 0 && y > 0) || (mod > 0 && y < 0)) {
869 mod += y;
870 div -= 1;
871 }
872 if (divp) *divp = div;
873 if (modp) *modp = mod;
874}
875
876/* 15.2.8.3.5 */
877/*
878 * call-seq:
879 * fix % other -> real
880 * fix.modulo(other) -> real
881 *
882 * Returns <code>fix</code> modulo <code>other</code>.
883 * See <code>numeric.divmod</code> for more information.
884 */
885
886static mrb_value
887fix_mod(mrb_state *mrb, mrb_value x)
888{
889 mrb_value y;
890 mrb_int a, b;
891
892 mrb_get_args(mrb, "o", &y);
893 a = mrb_fixnum(x);
894 if (mrb_fixnum_p(y) && a != MRB_INT_MIN && (b=mrb_fixnum(y)) != MRB_INT_MIN) {
895 mrb_int mod;
896
897 if (b == 0) {
898#ifdef MRB_WITHOUT_FLOAT
899 /* ZeroDivisionError */
900 return mrb_fixnum_value(0);
901#else
902 if (a > 0) return mrb_float_value(mrb, INFINITY);
903 if (a < 0) return mrb_float_value(mrb, INFINITY);
904 return mrb_float_value(mrb, NAN);
905#endif
906 }
907 fixdivmod(mrb, a, b, NULL, &mod);
908 return mrb_fixnum_value(mod);
909 }
910#ifdef MRB_WITHOUT_FLOAT
911 mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
912#else
913 else {
914 mrb_float mod;
915
916 flodivmod(mrb, (mrb_float)a, mrb_to_flo(mrb, y), NULL, &mod);
917 return mrb_float_value(mrb, mod);
918 }
919#endif
920}
921
922/*
923 * call-seq:
924 * fix.divmod(numeric) -> array
925 *
926 * See <code>Numeric#divmod</code>.
927 */
928static mrb_value
929fix_divmod(mrb_state *mrb, mrb_value x)
930{
931 mrb_value y;
932
933 mrb_get_args(mrb, "o", &y);
934
935 if (mrb_fixnum_p(y)) {
936 mrb_int div, mod;
937
938 if (mrb_fixnum(y) == 0) {
939#ifdef MRB_WITHOUT_FLOAT
940 return mrb_assoc_new(mrb, mrb_fixnum_value(0), mrb_fixnum_value(0));
941#else
942 return mrb_assoc_new(mrb, ((mrb_fixnum(x) == 0) ?
943 mrb_float_value(mrb, NAN):
944 mrb_float_value(mrb, INFINITY)),
945 mrb_float_value(mrb, NAN));
946#endif
947 }
948 fixdivmod(mrb, mrb_fixnum(x), mrb_fixnum(y), &div, &mod);
949 return mrb_assoc_new(mrb, mrb_fixnum_value(div), mrb_fixnum_value(mod));
950 }
951#ifdef MRB_WITHOUT_FLOAT
952 mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
953#else
954 else {
955 mrb_float div, mod;
956 mrb_value a, b;
957
958 flodivmod(mrb, (mrb_float)mrb_fixnum(x), mrb_to_flo(mrb, y), &div, &mod);
959 a = mrb_int_value(mrb, div);
960 b = mrb_float_value(mrb, mod);
961 return mrb_assoc_new(mrb, a, b);
962 }
963#endif
964}
965
966#ifndef MRB_WITHOUT_FLOAT
967static mrb_value
968flo_divmod(mrb_state *mrb, mrb_value x)
969{
970 mrb_value y;
971 mrb_float div, mod;
972 mrb_value a, b;
973
974 mrb_get_args(mrb, "o", &y);
975
976 flodivmod(mrb, mrb_float(x), mrb_to_flo(mrb, y), &div, &mod);
977 a = mrb_int_value(mrb, div);
978 b = mrb_float_value(mrb, mod);
979 return mrb_assoc_new(mrb, a, b);
980}
981#endif
982
983/* 15.2.8.3.7 */
984/*
985 * call-seq:
986 * fix == other -> true or false
987 *
988 * Return <code>true</code> if <code>fix</code> equals <code>other</code>
989 * numerically.
990 *
991 * 1 == 2 #=> false
992 * 1 == 1.0 #=> true
993 */
994
995static mrb_value
996fix_equal(mrb_state *mrb, mrb_value x)
997{
998 mrb_value y;
999
1000 mrb_get_args(mrb, "o", &y);
1001 switch (mrb_type(y)) {
1002 case MRB_TT_FIXNUM:
1003 return mrb_bool_value(mrb_fixnum(x) == mrb_fixnum(y));
1004#ifndef MRB_WITHOUT_FLOAT
1005 case MRB_TT_FLOAT:
1006 return mrb_bool_value((mrb_float)mrb_fixnum(x) == mrb_float(y));
1007#endif
1008 default:
1009 return mrb_false_value();
1010 }
1011}
1012
1013/* 15.2.8.3.8 */
1014/*
1015 * call-seq:
1016 * ~fix -> integer
1017 *
1018 * One's complement: returns a number where each bit is flipped.
1019 * ex.0---00001 (1)-> 1---11110 (-2)
1020 * ex.0---00010 (2)-> 1---11101 (-3)
1021 * ex.0---00100 (4)-> 1---11011 (-5)
1022 */
1023
1024static mrb_value
1025fix_rev(mrb_state *mrb, mrb_value num)
1026{
1027 mrb_int val = mrb_fixnum(num);
1028
1029 return mrb_fixnum_value(~val);
1030}
1031
1032#ifdef MRB_WITHOUT_FLOAT
1033#define bit_op(x,y,op1,op2) do {\
1034 return mrb_fixnum_value(mrb_fixnum(x) op2 mrb_fixnum(y));\
1035} while(0)
1036#else
1037static mrb_value flo_and(mrb_state *mrb, mrb_value x);
1038static mrb_value flo_or(mrb_state *mrb, mrb_value x);
1039static mrb_value flo_xor(mrb_state *mrb, mrb_value x);
1040#define bit_op(x,y,op1,op2) do {\
1041 if (mrb_fixnum_p(y)) return mrb_fixnum_value(mrb_fixnum(x) op2 mrb_fixnum(y));\
1042 return flo_ ## op1(mrb, mrb_float_value(mrb, (mrb_float)mrb_fixnum(x)));\
1043} while(0)
1044#endif
1045
1046/* 15.2.8.3.9 */
1047/*
1048 * call-seq:
1049 * fix & integer -> integer_result
1050 *
1051 * Bitwise AND.
1052 */
1053
1054static mrb_value
1055fix_and(mrb_state *mrb, mrb_value x)
1056{
1057 mrb_value y;
1058
1059 mrb_get_args(mrb, "o", &y);
1060 bit_op(x, y, and, &);
1061}
1062
1063/* 15.2.8.3.10 */
1064/*
1065 * call-seq:
1066 * fix | integer -> integer_result
1067 *
1068 * Bitwise OR.
1069 */
1070
1071static mrb_value
1072fix_or(mrb_state *mrb, mrb_value x)
1073{
1074 mrb_value y;
1075
1076 mrb_get_args(mrb, "o", &y);
1077 bit_op(x, y, or, |);
1078}
1079
1080/* 15.2.8.3.11 */
1081/*
1082 * call-seq:
1083 * fix ^ integer -> integer_result
1084 *
1085 * Bitwise EXCLUSIVE OR.
1086 */
1087
1088static mrb_value
1089fix_xor(mrb_state *mrb, mrb_value x)
1090{
1091 mrb_value y;
1092
1093 mrb_get_args(mrb, "o", &y);
1094 bit_op(x, y, or, ^);
1095}
1096
1097#define NUMERIC_SHIFT_WIDTH_MAX (MRB_INT_BIT-1)
1098
1099static mrb_value
1100lshift(mrb_state *mrb, mrb_int val, mrb_int width)
1101{
1102 if (width < 0) { /* mrb_int overflow */
1103#ifdef MRB_WITHOUT_FLOAT
1104 return mrb_fixnum_value(0);
1105#else
1106 return mrb_float_value(mrb, INFINITY);
1107#endif
1108 }
1109 if (val > 0) {
1110 if ((width > NUMERIC_SHIFT_WIDTH_MAX) ||
1111 (val > (MRB_INT_MAX >> width))) {
1112#ifdef MRB_WITHOUT_FLOAT
1113 return mrb_fixnum_value(-1);
1114#else
1115 goto bit_overflow;
1116#endif
1117 }
1118 return mrb_fixnum_value(val << width);
1119 }
1120 else {
1121 if ((width > NUMERIC_SHIFT_WIDTH_MAX) ||
1122 (val <= (MRB_INT_MIN >> width))) {
1123#ifdef MRB_WITHOUT_FLOAT
1124 return mrb_fixnum_value(0);
1125#else
1126 goto bit_overflow;
1127#endif
1128 }
1129 return mrb_fixnum_value(val * ((mrb_int)1 << width));
1130 }
1131
1132#ifndef MRB_WITHOUT_FLOAT
1133bit_overflow:
1134 {
1135 mrb_float f = (mrb_float)val;
1136 while (width--) {
1137 f *= 2;
1138 }
1139 return mrb_float_value(mrb, f);
1140 }
1141#endif
1142}
1143
1144static mrb_value
1145rshift(mrb_int val, mrb_int width)
1146{
1147 if (width < 0) { /* mrb_int overflow */
1148 return mrb_fixnum_value(0);
1149 }
1150 if (width >= NUMERIC_SHIFT_WIDTH_MAX) {
1151 if (val < 0) {
1152 return mrb_fixnum_value(-1);
1153 }
1154 return mrb_fixnum_value(0);
1155 }
1156 return mrb_fixnum_value(val >> width);
1157}
1158
1159/* 15.2.8.3.12 */
1160/*
1161 * call-seq:
1162 * fix << count -> integer or float
1163 *
1164 * Shifts _fix_ left _count_ positions (right if _count_ is negative).
1165 */
1166
1167static mrb_value
1168fix_lshift(mrb_state *mrb, mrb_value x)
1169{
1170 mrb_int width, val;
1171
1172 mrb_get_args(mrb, "i", &width);
1173 if (width == 0) {
1174 return x;
1175 }
1176 val = mrb_fixnum(x);
1177 if (val == 0) return x;
1178 if (width < 0) {
1179 return rshift(val, -width);
1180 }
1181 return lshift(mrb, val, width);
1182}
1183
1184/* 15.2.8.3.13 */
1185/*
1186 * call-seq:
1187 * fix >> count -> integer or float
1188 *
1189 * Shifts _fix_ right _count_ positions (left if _count_ is negative).
1190 */
1191
1192static mrb_value
1193fix_rshift(mrb_state *mrb, mrb_value x)
1194{
1195 mrb_int width, val;
1196
1197 mrb_get_args(mrb, "i", &width);
1198 if (width == 0) {
1199 return x;
1200 }
1201 val = mrb_fixnum(x);
1202 if (val == 0) return x;
1203 if (width < 0) {
1204 return lshift(mrb, val, -width);
1205 }
1206 return rshift(val, width);
1207}
1208
1209/* 15.2.8.3.23 */
1210/*
1211 * call-seq:
1212 * fix.to_f -> float
1213 *
1214 * Converts <i>fix</i> to a <code>Float</code>.
1215 *
1216 */
1217
1218#ifndef MRB_WITHOUT_FLOAT
1219static mrb_value
1220fix_to_f(mrb_state *mrb, mrb_value num)
1221{
1222 return mrb_float_value(mrb, (mrb_float)mrb_fixnum(num));
1223}
1224
1225/*
1226 * Document-class: FloatDomainError
1227 *
1228 * Raised when attempting to convert special float values
1229 * (in particular infinite or NaN)
1230 * to numerical classes which don't support them.
1231 *
1232 * Float::INFINITY.to_i
1233 *
1234 * <em>raises the exception:</em>
1235 *
1236 * FloatDomainError: Infinity
1237 */
1238/* ------------------------------------------------------------------------*/
1239MRB_API mrb_value
1240mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x)
1241{
1242 mrb_int z = 0;
1243
1244 if (!mrb_float_p(x)) {
1245 mrb_raise(mrb, E_TYPE_ERROR, "non float value");
1246 z = 0; /* not reached. just suppress warnings. */
1247 }
1248 else {
1249 mrb_float d = mrb_float(x);
1250
1251 mrb_check_num_exact(mrb, d);
1252 if (FIXABLE_FLOAT(d)) {
1253 z = (mrb_int)d;
1254 }
1255 else {
1256 mrb_raisef(mrb, E_RANGE_ERROR, "number (%v) too big for integer", x);
1257 }
1258 }
1259 return mrb_fixnum_value(z);
1260}
1261#endif
1262
1263static mrb_value
1264fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y)
1265{
1266 mrb_int a;
1267
1268 a = mrb_fixnum(x);
1269 if (mrb_fixnum_p(y)) {
1270 mrb_int b, c;
1271
1272 if (a == 0) return y;
1273 b = mrb_fixnum(y);
1274 if (mrb_int_add_overflow(a, b, &c)) {
1275#ifndef MRB_WITHOUT_FLOAT
1276 return mrb_float_value(mrb, (mrb_float)a + (mrb_float)b);
1277#endif
1278 }
1279 return mrb_fixnum_value(c);
1280 }
1281#ifdef MRB_WITHOUT_FLOAT
1282 mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
1283#else
1284 return mrb_float_value(mrb, (mrb_float)a + mrb_to_flo(mrb, y));
1285#endif
1286}
1287
1288MRB_API mrb_value
1289mrb_num_plus(mrb_state *mrb, mrb_value x, mrb_value y)
1290{
1291 if (mrb_fixnum_p(x)) {
1292 return fixnum_plus(mrb, x, y);
1293 }
1294#ifndef MRB_WITHOUT_FLOAT
1295 if (mrb_float_p(x)) {
1296 return mrb_float_value(mrb, mrb_float(x) + mrb_to_flo(mrb, y));
1297 }
1298#endif
1299 mrb_raise(mrb, E_TYPE_ERROR, "no number addition");
1300 return mrb_nil_value(); /* not reached */
1301}
1302
1303/* 15.2.8.3.1 */
1304/*
1305 * call-seq:
1306 * fix + numeric -> numeric_result
1307 *
1308 * Performs addition: the class of the resulting object depends on
1309 * the class of <code>numeric</code> and on the magnitude of the
1310 * result.
1311 */
1312static mrb_value
1313fix_plus(mrb_state *mrb, mrb_value self)
1314{
1315 mrb_value other;
1316
1317 mrb_get_args(mrb, "o", &other);
1318 return fixnum_plus(mrb, self, other);
1319}
1320
1321static mrb_value
1322fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y)
1323{
1324 mrb_int a;
1325
1326 a = mrb_fixnum(x);
1327 if (mrb_fixnum_p(y)) {
1328 mrb_int b, c;
1329
1330 b = mrb_fixnum(y);
1331 if (mrb_int_sub_overflow(a, b, &c)) {
1332#ifndef MRB_WITHOUT_FLOAT
1333 return mrb_float_value(mrb, (mrb_float)a - (mrb_float)b);
1334#endif
1335 }
1336 return mrb_fixnum_value(c);
1337 }
1338#ifdef MRB_WITHOUT_FLOAT
1339 mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
1340#else
1341 return mrb_float_value(mrb, (mrb_float)a - mrb_to_flo(mrb, y));
1342#endif
1343}
1344
1345MRB_API mrb_value
1346mrb_num_minus(mrb_state *mrb, mrb_value x, mrb_value y)
1347{
1348 if (mrb_fixnum_p(x)) {
1349 return fixnum_minus(mrb, x, y);
1350 }
1351#ifndef MRB_WITHOUT_FLOAT
1352 if (mrb_float_p(x)) {
1353 return mrb_float_value(mrb, mrb_float(x) - mrb_to_flo(mrb, y));
1354 }
1355#endif
1356 mrb_raise(mrb, E_TYPE_ERROR, "no number subtraction");
1357 return mrb_nil_value(); /* not reached */
1358}
1359
1360/* 15.2.8.3.2 */
1361/* 15.2.8.3.16 */
1362/*
1363 * call-seq:
1364 * fix - numeric -> numeric_result
1365 *
1366 * Performs subtraction: the class of the resulting object depends on
1367 * the class of <code>numeric</code> and on the magnitude of the
1368 * result.
1369 */
1370static mrb_value
1371fix_minus(mrb_state *mrb, mrb_value self)
1372{
1373 mrb_value other;
1374
1375 mrb_get_args(mrb, "o", &other);
1376 return fixnum_minus(mrb, self, other);
1377}
1378
1379
1380MRB_API mrb_value
1381mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, mrb_int base)
1382{
1383 char buf[MRB_INT_BIT+1];
1384 char *b = buf + sizeof buf;
1385 mrb_int val = mrb_fixnum(x);
1386
1387 if (base < 2 || 36 < base) {
1388 mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %i", base);
1389 }
1390
1391 if (val == 0) {
1392 *--b = '0';
1393 }
1394 else if (val < 0) {
1395 do {
1396 *--b = mrb_digitmap[-(val % base)];
1397 } while (val /= base);
1398 *--b = '-';
1399 }
1400 else {
1401 do {
1402 *--b = mrb_digitmap[(int)(val % base)];
1403 } while (val /= base);
1404 }
1405
1406 return mrb_str_new(mrb, b, buf + sizeof(buf) - b);
1407}
1408
1409/* 15.2.8.3.25 */
1410/*
1411 * call-seq:
1412 * fix.to_s(base=10) -> string
1413 *
1414 * Returns a string containing the representation of <i>fix</i> radix
1415 * <i>base</i> (between 2 and 36).
1416 *
1417 * 12345.to_s #=> "12345"
1418 * 12345.to_s(2) #=> "11000000111001"
1419 * 12345.to_s(8) #=> "30071"
1420 * 12345.to_s(10) #=> "12345"
1421 * 12345.to_s(16) #=> "3039"
1422 * 12345.to_s(36) #=> "9ix"
1423 *
1424 */
1425static mrb_value
1426fix_to_s(mrb_state *mrb, mrb_value self)
1427{
1428 mrb_int base = 10;
1429
1430 mrb_get_args(mrb, "|i", &base);
1431 return mrb_fixnum_to_str(mrb, self, base);
1432}
1433
1434/* compare two numbers: (1:0:-1; -2 for error) */
1435static mrb_int
1436cmpnum(mrb_state *mrb, mrb_value v1, mrb_value v2)
1437{
1438#ifdef MRB_WITHOUT_FLOAT
1439 mrb_int x, y;
1440#else
1441 mrb_float x, y;
1442#endif
1443
1444#ifdef MRB_WITHOUT_FLOAT
1445 x = mrb_fixnum(v1);
1446#else
1447 x = mrb_to_flo(mrb, v1);
1448#endif
1449 switch (mrb_type(v2)) {
1450 case MRB_TT_FIXNUM:
1451#ifdef MRB_WITHOUT_FLOAT
1452 y = mrb_fixnum(v2);
1453#else
1454 y = (mrb_float)mrb_fixnum(v2);
1455#endif
1456 break;
1457#ifndef MRB_WITHOUT_FLOAT
1458 case MRB_TT_FLOAT:
1459 y = mrb_float(v2);
1460 break;
1461#endif
1462 default:
1463 return -2;
1464 }
1465 if (x > y)
1466 return 1;
1467 else {
1468 if (x < y)
1469 return -1;
1470 return 0;
1471 }
1472}
1473
1474/* 15.2.9.3.6 */
1475/*
1476 * call-seq:
1477 * self.f <=> other.f => -1, 0, +1
1478 * < => -1
1479 * = => 0
1480 * > => +1
1481 * Comparison---Returns -1, 0, or +1 depending on whether <i>fix</i> is
1482 * less than, equal to, or greater than <i>numeric</i>. This is the
1483 * basis for the tests in <code>Comparable</code>.
1484 */
1485static mrb_value
1486integral_cmp(mrb_state *mrb, mrb_value self)
1487{
1488 mrb_value other;
1489 mrb_int n;
1490
1491 mrb_get_args(mrb, "o", &other);
1492 n = cmpnum(mrb, self, other);
1493 if (n == -2) return mrb_nil_value();
1494 return mrb_fixnum_value(n);
1495}
1496
1497static mrb_noreturn void
1498cmperr(mrb_state *mrb, mrb_value v1, mrb_value v2)
1499{
1500 mrb_raisef(mrb, E_ARGUMENT_ERROR, "comparison of %t with %t failed", v1, v2);
1501}
1502
1503static mrb_value
1504integral_lt(mrb_state *mrb, mrb_value self)
1505{
1506 mrb_value other;
1507 mrb_int n;
1508
1509 mrb_get_args(mrb, "o", &other);
1510 n = cmpnum(mrb, self, other);
1511 if (n == -2) cmperr(mrb, self, other);
1512 if (n < 0) return mrb_true_value();
1513 return mrb_false_value();
1514}
1515
1516static mrb_value
1517integral_le(mrb_state *mrb, mrb_value self)
1518{
1519 mrb_value other;
1520 mrb_int n;
1521
1522 mrb_get_args(mrb, "o", &other);
1523 n = cmpnum(mrb, self, other);
1524 if (n == -2) cmperr(mrb, self, other);
1525 if (n <= 0) return mrb_true_value();
1526 return mrb_false_value();
1527}
1528
1529static mrb_value
1530integral_gt(mrb_state *mrb, mrb_value self)
1531{
1532 mrb_value other;
1533 mrb_int n;
1534
1535 mrb_get_args(mrb, "o", &other);
1536 n = cmpnum(mrb, self, other);
1537 if (n == -2) cmperr(mrb, self, other);
1538 if (n > 0) return mrb_true_value();
1539 return mrb_false_value();
1540}
1541
1542static mrb_value
1543integral_ge(mrb_state *mrb, mrb_value self)
1544{
1545 mrb_value other;
1546 mrb_int n;
1547
1548 mrb_get_args(mrb, "o", &other);
1549 n = cmpnum(mrb, self, other);
1550 if (n == -2) cmperr(mrb, self, other);
1551 if (n >= 0) return mrb_true_value();
1552 return mrb_false_value();
1553}
1554
1555MRB_API mrb_int
1556mrb_cmp(mrb_state *mrb, mrb_value obj1, mrb_value obj2)
1557{
1558 mrb_value v;
1559
1560 switch (mrb_type(obj1)) {
1561 case MRB_TT_FIXNUM:
1562 case MRB_TT_FLOAT:
1563 return cmpnum(mrb, obj1, obj2);
1564 case MRB_TT_STRING:
1565 if (!mrb_string_p(obj2))
1566 return -2;
1567 return mrb_str_cmp(mrb, obj1, obj2);
1568 default:
1569 v = mrb_funcall(mrb, obj1, "<=>", 1, obj2);
1570 if (mrb_nil_p(v) || !mrb_fixnum_p(v))
1571 return -2;
1572 return mrb_fixnum(v);
1573 }
1574}
1575
1576static mrb_value
1577num_finite_p(mrb_state *mrb, mrb_value self)
1578{
1579 return mrb_true_value();
1580}
1581
1582static mrb_value
1583num_infinite_p(mrb_state *mrb, mrb_value self)
1584{
1585 return mrb_false_value();
1586}
1587
1588/* 15.2.9.3.1 */
1589/*
1590 * call-seq:
1591 * float + other -> float
1592 *
1593 * Returns a new float which is the sum of <code>float</code>
1594 * and <code>other</code>.
1595 */
1596#ifndef MRB_WITHOUT_FLOAT
1597static mrb_value
1598flo_plus(mrb_state *mrb, mrb_value x)
1599{
1600 mrb_value y;
1601
1602 mrb_get_args(mrb, "o", &y);
1603 return mrb_float_value(mrb, mrb_float(x) + mrb_to_flo(mrb, y));
1604}
1605#endif
1606
1607/* ------------------------------------------------------------------------*/
1608void
1609mrb_init_numeric(mrb_state *mrb)
1610{
1611 struct RClass *numeric, *integer, *fixnum, *integral;
1612#ifndef MRB_WITHOUT_FLOAT
1613 struct RClass *fl;
1614#endif
1615
1616 integral = mrb_define_module(mrb, "Integral");
1617 mrb_define_method(mrb, integral,"**", integral_pow, MRB_ARGS_REQ(1));
1618 mrb_define_method(mrb, integral,"/", integral_div, MRB_ARGS_REQ(1)); /* 15.2.{8,9}.3.6 */
1619 mrb_define_method(mrb, integral,"quo", integral_div, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */
1620 mrb_define_method(mrb, integral,"div", integral_idiv, MRB_ARGS_REQ(1));
1621 mrb_define_method(mrb, integral,"<=>", integral_cmp, MRB_ARGS_REQ(1)); /* 15.2.{8,9}.3.1 */
1622 mrb_define_method(mrb, integral,"<", integral_lt, MRB_ARGS_REQ(1));
1623 mrb_define_method(mrb, integral,"<=", integral_le, MRB_ARGS_REQ(1));
1624 mrb_define_method(mrb, integral,">", integral_gt, MRB_ARGS_REQ(1));
1625 mrb_define_method(mrb, integral,">=", integral_ge, MRB_ARGS_REQ(1));
1626 mrb_define_method(mrb, integral,"__coerce_step_counter", integral_coerce_step_counter, MRB_ARGS_REQ(2));
1627
1628 /* Numeric Class */
1629 numeric = mrb_define_class(mrb, "Numeric", mrb->object_class); /* 15.2.7 */
1630 mrb_define_method(mrb, numeric, "finite?", num_finite_p, MRB_ARGS_NONE());
1631 mrb_define_method(mrb, numeric, "infinite?",num_infinite_p, MRB_ARGS_NONE());
1632
1633 /* Integer Class */
1634 integer = mrb_define_class(mrb, "Integer", numeric); /* 15.2.8 */
1635 MRB_SET_INSTANCE_TT(integer, MRB_TT_FIXNUM);
1636 mrb_undef_class_method(mrb, integer, "new");
1637 mrb_define_method(mrb, integer, "to_i", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.24 */
1638 mrb_define_method(mrb, integer, "to_int", int_to_i, MRB_ARGS_NONE());
1639#ifndef MRB_WITHOUT_FLOAT
1640 mrb_define_method(mrb, integer, "ceil", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.8 (x) */
1641 mrb_define_method(mrb, integer, "floor", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.10 (x) */
1642 mrb_define_method(mrb, integer, "round", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.12 (x) */
1643 mrb_define_method(mrb, integer, "truncate", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.15 (x) */
1644#endif
1645
1646 /* Fixnum Class */
1647 mrb->fixnum_class = fixnum = mrb_define_class(mrb, "Fixnum", integer);
1648 mrb_define_method(mrb, fixnum, "+", fix_plus, MRB_ARGS_REQ(1)); /* 15.2.8.3.1 */
1649 mrb_define_method(mrb, fixnum, "-", fix_minus, MRB_ARGS_REQ(1)); /* 15.2.8.3.2 */
1650 mrb_define_method(mrb, fixnum, "*", fix_mul, MRB_ARGS_REQ(1)); /* 15.2.8.3.3 */
1651 mrb_define_method(mrb, fixnum, "%", fix_mod, MRB_ARGS_REQ(1)); /* 15.2.8.3.5 */
1652 mrb_define_method(mrb, fixnum, "==", fix_equal, MRB_ARGS_REQ(1)); /* 15.2.8.3.7 */
1653 mrb_define_method(mrb, fixnum, "~", fix_rev, MRB_ARGS_NONE()); /* 15.2.8.3.8 */
1654 mrb_define_method(mrb, fixnum, "&", fix_and, MRB_ARGS_REQ(1)); /* 15.2.8.3.9 */
1655 mrb_define_method(mrb, fixnum, "|", fix_or, MRB_ARGS_REQ(1)); /* 15.2.8.3.10 */
1656 mrb_define_method(mrb, fixnum, "^", fix_xor, MRB_ARGS_REQ(1)); /* 15.2.8.3.11 */
1657 mrb_define_method(mrb, fixnum, "<<", fix_lshift, MRB_ARGS_REQ(1)); /* 15.2.8.3.12 */
1658 mrb_define_method(mrb, fixnum, ">>", fix_rshift, MRB_ARGS_REQ(1)); /* 15.2.8.3.13 */
1659 mrb_define_method(mrb, fixnum, "eql?", fix_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */
1660#ifndef MRB_WITHOUT_FLOAT
1661 mrb_define_method(mrb, fixnum, "to_f", fix_to_f, MRB_ARGS_NONE()); /* 15.2.8.3.23 */
1662#endif
1663 mrb_define_method(mrb, fixnum, "to_s", fix_to_s, MRB_ARGS_OPT(1)); /* 15.2.8.3.25 */
1664 mrb_define_method(mrb, fixnum, "inspect", fix_to_s, MRB_ARGS_OPT(1));
1665 mrb_define_method(mrb, fixnum, "divmod", fix_divmod, MRB_ARGS_REQ(1)); /* 15.2.8.3.30 (x) */
1666
1667#ifndef MRB_WITHOUT_FLOAT
1668 /* Float Class */
1669 mrb->float_class = fl = mrb_define_class(mrb, "Float", numeric); /* 15.2.9 */
1670 MRB_SET_INSTANCE_TT(fl, MRB_TT_FLOAT);
1671 mrb_undef_class_method(mrb, fl, "new");
1672 mrb_define_method(mrb, fl, "+", flo_plus, MRB_ARGS_REQ(1)); /* 15.2.9.3.1 */
1673 mrb_define_method(mrb, fl, "-", flo_minus, MRB_ARGS_REQ(1)); /* 15.2.9.3.2 */
1674 mrb_define_method(mrb, fl, "*", flo_mul, MRB_ARGS_REQ(1)); /* 15.2.9.3.3 */
1675 mrb_define_method(mrb, fl, "%", flo_mod, MRB_ARGS_REQ(1)); /* 15.2.9.3.5 */
1676 mrb_define_method(mrb, fl, "==", flo_eq, MRB_ARGS_REQ(1)); /* 15.2.9.3.7 */
1677 mrb_define_method(mrb, fl, "~", flo_rev, MRB_ARGS_NONE());
1678 mrb_define_method(mrb, fl, "&", flo_and, MRB_ARGS_REQ(1));
1679 mrb_define_method(mrb, fl, "|", flo_or, MRB_ARGS_REQ(1));
1680 mrb_define_method(mrb, fl, "^", flo_xor, MRB_ARGS_REQ(1));
1681 mrb_define_method(mrb, fl, ">>", flo_rshift, MRB_ARGS_REQ(1));
1682 mrb_define_method(mrb, fl, "<<", flo_lshift, MRB_ARGS_REQ(1));
1683 mrb_define_method(mrb, fl, "ceil", flo_ceil, MRB_ARGS_NONE()); /* 15.2.9.3.8 */
1684 mrb_define_method(mrb, fl, "finite?", flo_finite_p, MRB_ARGS_NONE()); /* 15.2.9.3.9 */
1685 mrb_define_method(mrb, fl, "floor", flo_floor, MRB_ARGS_NONE()); /* 15.2.9.3.10 */
1686 mrb_define_method(mrb, fl, "infinite?", flo_infinite_p, MRB_ARGS_NONE()); /* 15.2.9.3.11 */
1687 mrb_define_method(mrb, fl, "round", flo_round, MRB_ARGS_OPT(1)); /* 15.2.9.3.12 */
1688 mrb_define_method(mrb, fl, "to_f", flo_to_f, MRB_ARGS_NONE()); /* 15.2.9.3.13 */
1689 mrb_define_method(mrb, fl, "to_i", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.14 */
1690 mrb_define_method(mrb, fl, "to_int", flo_truncate, MRB_ARGS_NONE());
1691 mrb_define_method(mrb, fl, "truncate", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.15 */
1692 mrb_define_method(mrb, fl, "divmod", flo_divmod, MRB_ARGS_REQ(1));
1693 mrb_define_method(mrb, fl, "eql?", flo_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */
1694
1695 mrb_define_method(mrb, fl, "to_s", flo_to_s, MRB_ARGS_NONE()); /* 15.2.9.3.16(x) */
1696 mrb_define_method(mrb, fl, "inspect", flo_to_s, MRB_ARGS_NONE());
1697 mrb_define_method(mrb, fl, "nan?", flo_nan_p, MRB_ARGS_NONE());
1698
1699#ifdef INFINITY
1700 mrb_define_const(mrb, fl, "INFINITY", mrb_float_value(mrb, INFINITY));
1701#endif
1702#ifdef NAN
1703 mrb_define_const(mrb, fl, "NAN", mrb_float_value(mrb, NAN));
1704#endif
1705
1706 mrb_include_module(mrb, fl, integral);
1707#endif
1708}
Note: See TracBrowser for help on using the repository browser.