source: EcnlProtoTool/trunk/mruby-1.2.0/src/numeric.c@ 270

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

mruby版ECNLプロトタイピング・ツールを追加

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-csrc
File size: 27.6 KB
Line 
1/*
2** numeric.c - Numeric, Integer, Float, Fixnum class
3**
4** See Copyright Notice in mruby.h
5*/
6
7#include <float.h>
8#include <limits.h>
9#include <math.h>
10#include <stdlib.h>
11
12#include "mruby.h"
13#include "mruby/array.h"
14#include "mruby/numeric.h"
15#include "mruby/string.h"
16
17#ifdef MRB_USE_FLOAT
18#define floor(f) floorf(f)
19#define ceil(f) ceilf(f)
20#define fmod(x,y) fmodf(x,y)
21#define MRB_FLO_TO_STR_FMT "%.7g"
22#else
23#define MRB_FLO_TO_STR_FMT "%.14g"
24#endif
25
26MRB_API mrb_float
27mrb_to_flo(mrb_state *mrb, mrb_value val)
28{
29 switch (mrb_type(val)) {
30 case MRB_TT_FIXNUM:
31 return (mrb_float)mrb_fixnum(val);
32 case MRB_TT_FLOAT:
33 break;
34 default:
35 mrb_raise(mrb, E_TYPE_ERROR, "non float value");
36 }
37 return mrb_float(val);
38}
39
40/*
41 * call-seq:
42 *
43 * num ** other -> num
44 *
45 * Raises <code>num</code> the <code>other</code> power.
46 *
47 * 2.0**3 #=> 8.0
48 */
49static mrb_value
50num_pow(mrb_state *mrb, mrb_value x)
51{
52 mrb_value y;
53 mrb_float d, yv;
54
55 mrb_get_args(mrb, "o", &y);
56 yv = mrb_to_flo(mrb, y);
57 d = pow(mrb_to_flo(mrb, x), yv);
58 if (mrb_fixnum_p(x) && mrb_fixnum_p(y) && FIXABLE(d) && yv > 0 &&
59 (d < 0 || (d > 0 && (mrb_int)d > 0)))
60 return mrb_fixnum_value((mrb_int)d);
61 return mrb_float_value(mrb, d);
62}
63
64/* 15.2.8.3.4 */
65/* 15.2.9.3.4 */
66/*
67 * call-seq:
68 * num / other -> num
69 *
70 * Performs division: the class of the resulting object depends on
71 * the class of <code>num</code> and on the magnitude of the
72 * result.
73 */
74
75mrb_value
76mrb_num_div(mrb_state *mrb, mrb_value x, mrb_value y)
77{
78 return mrb_float_value(mrb, mrb_to_flo(mrb, x) / mrb_to_flo(mrb, y));
79}
80
81/* 15.2.9.3.19(x) */
82/*
83 * call-seq:
84 * num.quo(numeric) -> real
85 *
86 * Returns most exact division.
87 */
88
89static mrb_value
90num_div(mrb_state *mrb, mrb_value x)
91{
92 mrb_float y;
93
94 mrb_get_args(mrb, "f", &y);
95 return mrb_float_value(mrb, mrb_to_flo(mrb, x) / y);
96}
97
98/********************************************************************
99 *
100 * Document-class: Float
101 *
102 * <code>Float</code> objects represent inexact real numbers using
103 * the native architecture's double-precision floating point
104 * representation.
105 */
106
107/* 15.2.9.3.16(x) */
108/*
109 * call-seq:
110 * flt.to_s -> string
111 *
112 * Returns a string containing a representation of self. As well as a
113 * fixed or exponential form of the number, the call may return
114 * "<code>NaN</code>", "<code>Infinity</code>", and
115 * "<code>-Infinity</code>".
116 */
117
118static mrb_value
119flo_to_s(mrb_state *mrb, mrb_value flt)
120{
121 if (isnan(mrb_float(flt))) {
122 return mrb_str_new_lit(mrb, "NaN");
123 }
124 return mrb_float_to_str(mrb, flt, MRB_FLO_TO_STR_FMT);
125}
126
127/* 15.2.9.3.2 */
128/*
129 * call-seq:
130 * float - other -> float
131 *
132 * Returns a new float which is the difference of <code>float</code>
133 * and <code>other</code>.
134 */
135
136static mrb_value
137flo_minus(mrb_state *mrb, mrb_value x)
138{
139 mrb_value y;
140
141 mrb_get_args(mrb, "o", &y);
142 return mrb_float_value(mrb, mrb_float(x) - mrb_to_flo(mrb, y));
143}
144
145/* 15.2.9.3.3 */
146/*
147 * call-seq:
148 * float * other -> float
149 *
150 * Returns a new float which is the product of <code>float</code>
151 * and <code>other</code>.
152 */
153
154static mrb_value
155flo_mul(mrb_state *mrb, mrb_value x)
156{
157 mrb_value y;
158
159 mrb_get_args(mrb, "o", &y);
160 return mrb_float_value(mrb, mrb_float(x) * mrb_to_flo(mrb, y));
161}
162
163static void
164flodivmod(mrb_state *mrb, mrb_float x, mrb_float y, mrb_float *divp, mrb_float *modp)
165{
166 mrb_float div;
167 mrb_float mod;
168
169 if (y == 0.0) {
170 div = INFINITY;
171 mod = NAN;
172 }
173 else {
174 mod = fmod(x, y);
175 if (isinf(x) && isfinite(y))
176 div = x;
177 else
178 div = (x - mod) / y;
179 if (y*mod < 0) {
180 mod += y;
181 div -= 1.0;
182 }
183 }
184
185 if (modp) *modp = mod;
186 if (divp) *divp = div;
187}
188
189/* 15.2.9.3.5 */
190/*
191 * call-seq:
192 * flt % other -> float
193 * flt.modulo(other) -> float
194 *
195 * Return the modulo after division of <code>flt</code> by <code>other</code>.
196 *
197 * 6543.21.modulo(137) #=> 104.21
198 * 6543.21.modulo(137.24) #=> 92.9299999999996
199 */
200
201static mrb_value
202flo_mod(mrb_state *mrb, mrb_value x)
203{
204 mrb_value y;
205 mrb_float mod;
206
207 mrb_get_args(mrb, "o", &y);
208
209 flodivmod(mrb, mrb_float(x), mrb_to_flo(mrb, y), 0, &mod);
210 return mrb_float_value(mrb, mod);
211}
212
213/* 15.2.8.3.16 */
214/*
215 * call-seq:
216 * num.eql?(numeric) -> true or false
217 *
218 * Returns <code>true</code> if <i>num</i> and <i>numeric</i> are the
219 * same type and have equal values.
220 *
221 * 1 == 1.0 #=> true
222 * 1.eql?(1.0) #=> false
223 * (1.0).eql?(1.0) #=> true
224 */
225static mrb_value
226fix_eql(mrb_state *mrb, mrb_value x)
227{
228 mrb_value y;
229
230 mrb_get_args(mrb, "o", &y);
231 if (!mrb_fixnum_p(y)) return mrb_false_value();
232 return mrb_bool_value(mrb_fixnum(x) == mrb_fixnum(y));
233}
234
235static mrb_value
236flo_eql(mrb_state *mrb, mrb_value x)
237{
238 mrb_value y;
239
240 mrb_get_args(mrb, "o", &y);
241 if (!mrb_float_p(y)) return mrb_false_value();
242 return mrb_bool_value(mrb_float(x) == (mrb_float)mrb_fixnum(y));
243}
244
245/* 15.2.9.3.7 */
246/*
247 * call-seq:
248 * flt == obj -> true or false
249 *
250 * Returns <code>true</code> only if <i>obj</i> has the same value
251 * as <i>flt</i>. Contrast this with <code>Float#eql?</code>, which
252 * requires <i>obj</i> to be a <code>Float</code>.
253 *
254 * 1.0 == 1 #=> true
255 *
256 */
257
258static mrb_value
259flo_eq(mrb_state *mrb, mrb_value x)
260{
261 mrb_value y;
262 mrb_get_args(mrb, "o", &y);
263
264 switch (mrb_type(y)) {
265 case MRB_TT_FIXNUM:
266 return mrb_bool_value(mrb_float(x) == (mrb_float)mrb_fixnum(y));
267 case MRB_TT_FLOAT:
268 return mrb_bool_value(mrb_float(x) == mrb_float(y));
269 default:
270 return mrb_false_value();
271 }
272}
273
274/* 15.2.8.3.18 */
275/*
276 * call-seq:
277 * flt.hash -> integer
278 *
279 * Returns a hash code for this float.
280 */
281static mrb_value
282flo_hash(mrb_state *mrb, mrb_value num)
283{
284 mrb_float d;
285 char *c;
286 size_t i;
287 int hash;
288
289 d = (mrb_float)mrb_fixnum(num);
290 /* normalize -0.0 to 0.0 */
291 if (d == 0) d = 0.0;
292 c = (char*)&d;
293 for (hash=0, i=0; i<sizeof(mrb_float);i++) {
294 hash = (hash * 971) ^ (unsigned char)c[i];
295 }
296 if (hash < 0) hash = -hash;
297 return mrb_fixnum_value(hash);
298}
299
300/* 15.2.9.3.13 */
301/*
302 * call-seq:
303 * flt.to_f -> self
304 *
305 * As <code>flt</code> is already a float, returns +self+.
306 */
307
308static mrb_value
309flo_to_f(mrb_state *mrb, mrb_value num)
310{
311 return num;
312}
313
314/* 15.2.9.3.11 */
315/*
316 * call-seq:
317 * flt.infinite? -> nil, -1, +1
318 *
319 * Returns <code>nil</code>, -1, or +1 depending on whether <i>flt</i>
320 * is finite, -infinity, or +infinity.
321 *
322 * (0.0).infinite? #=> nil
323 * (-1.0/0.0).infinite? #=> -1
324 * (+1.0/0.0).infinite? #=> 1
325 */
326
327static mrb_value
328flo_infinite_p(mrb_state *mrb, mrb_value num)
329{
330 mrb_float value = mrb_float(num);
331
332 if (isinf(value)) {
333 return mrb_fixnum_value(value < 0 ? -1 : 1);
334 }
335 return mrb_nil_value();
336}
337
338/* 15.2.9.3.9 */
339/*
340 * call-seq:
341 * flt.finite? -> true or false
342 *
343 * Returns <code>true</code> if <i>flt</i> is a valid IEEE floating
344 * point number (it is not infinite, and <code>nan?</code> is
345 * <code>false</code>).
346 *
347 */
348
349static mrb_value
350flo_finite_p(mrb_state *mrb, mrb_value num)
351{
352 return mrb_bool_value(isfinite(mrb_float(num)));
353}
354
355/* 15.2.9.3.10 */
356/*
357 * call-seq:
358 * flt.floor -> integer
359 *
360 * Returns the largest integer less than or equal to <i>flt</i>.
361 *
362 * 1.2.floor #=> 1
363 * 2.0.floor #=> 2
364 * (-1.2).floor #=> -2
365 * (-2.0).floor #=> -2
366 */
367
368static mrb_value
369flo_floor(mrb_state *mrb, mrb_value num)
370{
371 mrb_float f = floor(mrb_float(num));
372
373 if (!FIXABLE(f)) {
374 return mrb_float_value(mrb, f);
375 }
376 return mrb_fixnum_value((mrb_int)f);
377}
378
379/* 15.2.9.3.8 */
380/*
381 * call-seq:
382 * flt.ceil -> integer
383 *
384 * Returns the smallest <code>Integer</code> greater than or equal to
385 * <i>flt</i>.
386 *
387 * 1.2.ceil #=> 2
388 * 2.0.ceil #=> 2
389 * (-1.2).ceil #=> -1
390 * (-2.0).ceil #=> -2
391 */
392
393static mrb_value
394flo_ceil(mrb_state *mrb, mrb_value num)
395{
396 mrb_float f = ceil(mrb_float(num));
397
398 if (!FIXABLE(f)) {
399 return mrb_float_value(mrb, f);
400 }
401 return mrb_fixnum_value((mrb_int)f);
402}
403
404/* 15.2.9.3.12 */
405/*
406 * call-seq:
407 * flt.round([ndigits]) -> integer or float
408 *
409 * Rounds <i>flt</i> to a given precision in decimal digits (default 0 digits).
410 * Precision may be negative. Returns a floating point number when ndigits
411 * is more than zero.
412 *
413 * 1.4.round #=> 1
414 * 1.5.round #=> 2
415 * 1.6.round #=> 2
416 * (-1.5).round #=> -2
417 *
418 * 1.234567.round(2) #=> 1.23
419 * 1.234567.round(3) #=> 1.235
420 * 1.234567.round(4) #=> 1.2346
421 * 1.234567.round(5) #=> 1.23457
422 *
423 * 34567.89.round(-5) #=> 0
424 * 34567.89.round(-4) #=> 30000
425 * 34567.89.round(-3) #=> 35000
426 * 34567.89.round(-2) #=> 34600
427 * 34567.89.round(-1) #=> 34570
428 * 34567.89.round(0) #=> 34568
429 * 34567.89.round(1) #=> 34567.9
430 * 34567.89.round(2) #=> 34567.89
431 * 34567.89.round(3) #=> 34567.89
432 *
433 */
434
435static mrb_value
436flo_round(mrb_state *mrb, mrb_value num)
437{
438 double number, f;
439 mrb_int ndigits = 0;
440 mrb_int i;
441
442 mrb_get_args(mrb, "|i", &ndigits);
443 number = mrb_float(num);
444
445 if (isinf(number)) {
446 if (0 < ndigits) return num;
447 else mrb_raise(mrb, E_FLOATDOMAIN_ERROR, number < 0 ? "-Infinity" : "Infinity");
448 }
449 if (isnan(number)) {
450 if (0 < ndigits) return num;
451 else mrb_raise(mrb, E_FLOATDOMAIN_ERROR, "NaN");
452 }
453
454 f = 1.0;
455 i = ndigits >= 0 ? ndigits : -ndigits;
456 while (--i >= 0)
457 f = f*10.0;
458
459 if (isinf(f)) {
460 if (ndigits < 0) number = 0;
461 }
462 else {
463 double d;
464
465 if (ndigits < 0) number /= f;
466 else number *= f;
467
468 /* home-made inline implementation of round(3) */
469 if (number > 0.0) {
470 d = floor(number);
471 number = d + (number - d >= 0.5);
472 }
473 else if (number < 0.0) {
474 d = ceil(number);
475 number = d - (d - number >= 0.5);
476 }
477
478 if (ndigits < 0) number *= f;
479 else number /= f;
480 }
481
482 if (ndigits > 0) {
483 if (!isfinite(number)) return num;
484 return mrb_float_value(mrb, number);
485 }
486 return mrb_fixnum_value((mrb_int)number);
487}
488
489/* 15.2.9.3.14 */
490/* 15.2.9.3.15 */
491/*
492 * call-seq:
493 * flt.to_i -> integer
494 * flt.to_int -> integer
495 * flt.truncate -> integer
496 *
497 * Returns <i>flt</i> truncated to an <code>Integer</code>.
498 */
499
500static mrb_value
501flo_truncate(mrb_state *mrb, mrb_value num)
502{
503 mrb_float f = mrb_float(num);
504
505 if (f > 0.0) f = floor(f);
506 if (f < 0.0) f = ceil(f);
507
508 if (!FIXABLE(f)) {
509 return mrb_float_value(mrb, f);
510 }
511 return mrb_fixnum_value((mrb_int)f);
512}
513
514static mrb_value
515flo_nan_p(mrb_state *mrb, mrb_value num)
516{
517 return mrb_bool_value(isnan(mrb_float(num)));
518}
519
520/*
521 * Document-class: Integer
522 *
523 * <code>Integer</code> is the basis for the two concrete classes that
524 * hold whole numbers, <code>Bignum</code> and <code>Fixnum</code>.
525 *
526 */
527
528
529/*
530 * call-seq:
531 * int.to_i -> integer
532 * int.to_int -> integer
533 *
534 * As <i>int</i> is already an <code>Integer</code>, all these
535 * methods simply return the receiver.
536 */
537
538static mrb_value
539int_to_i(mrb_state *mrb, mrb_value num)
540{
541 return num;
542}
543
544/*tests if N*N would overflow*/
545#define SQRT_INT_MAX ((mrb_int)1<<((MRB_INT_BIT-1-MRB_FIXNUM_SHIFT)/2))
546#define FIT_SQRT_INT(n) (((n)<SQRT_INT_MAX)&&((n)>=-SQRT_INT_MAX))
547
548mrb_value
549mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y)
550{
551 mrb_int a;
552
553 a = mrb_fixnum(x);
554 if (mrb_fixnum_p(y)) {
555 mrb_float c;
556 mrb_int b;
557
558 if (a == 0) return x;
559 b = mrb_fixnum(y);
560 if (FIT_SQRT_INT(a) && FIT_SQRT_INT(b))
561 return mrb_fixnum_value(a*b);
562 c = a * b;
563 if ((a != 0 && c/a != b) || !FIXABLE(c)) {
564 return mrb_float_value(mrb, (mrb_float)a*(mrb_float)b);
565 }
566 return mrb_fixnum_value((mrb_int)c);
567 }
568 return mrb_float_value(mrb, (mrb_float)a * mrb_to_flo(mrb, y));
569}
570
571/* 15.2.8.3.3 */
572/*
573 * call-seq:
574 * fix * numeric -> numeric_result
575 *
576 * Performs multiplication: the class of the resulting object depends on
577 * the class of <code>numeric</code> and on the magnitude of the
578 * result.
579 */
580
581static mrb_value
582fix_mul(mrb_state *mrb, mrb_value x)
583{
584 mrb_value y;
585
586 mrb_get_args(mrb, "o", &y);
587 return mrb_fixnum_mul(mrb, x, y);
588}
589
590static void
591fixdivmod(mrb_state *mrb, mrb_int x, mrb_int y, mrb_int *divp, mrb_int *modp)
592{
593 mrb_int div, mod;
594
595 /* TODO: add mrb_assert(y != 0) to make sure */
596
597 if (y < 0) {
598 if (x < 0)
599 div = -x / -y;
600 else
601 div = - (x / -y);
602 }
603 else {
604 if (x < 0)
605 div = - (-x / y);
606 else
607 div = x / y;
608 }
609 mod = x - div*y;
610 if ((mod < 0 && y > 0) || (mod > 0 && y < 0)) {
611 mod += y;
612 div -= 1;
613 }
614 if (divp) *divp = div;
615 if (modp) *modp = mod;
616}
617
618/* 15.2.8.3.5 */
619/*
620 * call-seq:
621 * fix % other -> real
622 * fix.modulo(other) -> real
623 *
624 * Returns <code>fix</code> modulo <code>other</code>.
625 * See <code>numeric.divmod</code> for more information.
626 */
627
628static mrb_value
629fix_mod(mrb_state *mrb, mrb_value x)
630{
631 mrb_value y;
632 mrb_int a;
633
634 mrb_get_args(mrb, "o", &y);
635 a = mrb_fixnum(x);
636 if (mrb_fixnum_p(y)) {
637 mrb_int b, mod;
638
639 if ((b=mrb_fixnum(y)) == 0) {
640 return mrb_float_value(mrb, NAN);
641 }
642 fixdivmod(mrb, a, b, 0, &mod);
643 return mrb_fixnum_value(mod);
644 }
645 else {
646 mrb_float mod;
647
648 flodivmod(mrb, (mrb_float)a, mrb_to_flo(mrb, y), 0, &mod);
649 return mrb_float_value(mrb, mod);
650 }
651}
652
653/*
654 * call-seq:
655 * fix.divmod(numeric) -> array
656 *
657 * See <code>Numeric#divmod</code>.
658 */
659static mrb_value
660fix_divmod(mrb_state *mrb, mrb_value x)
661{
662 mrb_value y;
663
664 mrb_get_args(mrb, "o", &y);
665
666 if (mrb_fixnum_p(y)) {
667 mrb_int div, mod;
668
669 if (mrb_fixnum(y) == 0) {
670 return mrb_assoc_new(mrb, mrb_float_value(mrb, INFINITY),
671 mrb_float_value(mrb, NAN));
672 }
673 fixdivmod(mrb, mrb_fixnum(x), mrb_fixnum(y), &div, &mod);
674 return mrb_assoc_new(mrb, mrb_fixnum_value(div), mrb_fixnum_value(mod));
675 }
676 else {
677 mrb_float div, mod;
678 mrb_value a, b;
679
680 flodivmod(mrb, (mrb_float)mrb_fixnum(x), mrb_to_flo(mrb, y), &div, &mod);
681 a = mrb_float_value(mrb, (mrb_int)div);
682 b = mrb_float_value(mrb, mod);
683 return mrb_assoc_new(mrb, a, b);
684 }
685}
686
687static mrb_value
688flo_divmod(mrb_state *mrb, mrb_value x)
689{
690 mrb_value y;
691 mrb_float div, mod;
692 mrb_value a, b;
693
694 mrb_get_args(mrb, "o", &y);
695
696 flodivmod(mrb, mrb_float(x), mrb_to_flo(mrb, y), &div, &mod);
697 a = mrb_float_value(mrb, (mrb_int)div);
698 b = mrb_float_value(mrb, mod);
699 return mrb_assoc_new(mrb, a, b);
700}
701
702/* 15.2.8.3.7 */
703/*
704 * call-seq:
705 * fix == other -> true or false
706 *
707 * Return <code>true</code> if <code>fix</code> equals <code>other</code>
708 * numerically.
709 *
710 * 1 == 2 #=> false
711 * 1 == 1.0 #=> true
712 */
713
714static mrb_value
715fix_equal(mrb_state *mrb, mrb_value x)
716{
717 mrb_value y;
718
719 mrb_get_args(mrb, "o", &y);
720 switch (mrb_type(y)) {
721 case MRB_TT_FIXNUM:
722 return mrb_bool_value(mrb_fixnum(x) == mrb_fixnum(y));
723 case MRB_TT_FLOAT:
724 return mrb_bool_value((mrb_float)mrb_fixnum(x) == mrb_float(y));
725 default:
726 return mrb_false_value();
727 }
728}
729
730/* 15.2.8.3.8 */
731/*
732 * call-seq:
733 * ~fix -> integer
734 *
735 * One's complement: returns a number where each bit is flipped.
736 * ex.0---00001 (1)-> 1---11110 (-2)
737 * ex.0---00010 (2)-> 1---11101 (-3)
738 * ex.0---00100 (4)-> 1---11011 (-5)
739 */
740
741static mrb_value
742fix_rev(mrb_state *mrb, mrb_value num)
743{
744 mrb_int val = mrb_fixnum(num);
745
746 return mrb_fixnum_value(~val);
747}
748
749static mrb_value
750bit_coerce(mrb_state *mrb, mrb_value x)
751{
752 while (!mrb_fixnum_p(x)) {
753 if (mrb_float_p(x)) {
754 mrb_raise(mrb, E_TYPE_ERROR, "can't convert Float into Integer");
755 }
756 x = mrb_to_int(mrb, x);
757 }
758 return x;
759}
760
761/* 15.2.8.3.9 */
762/*
763 * call-seq:
764 * fix & integer -> integer_result
765 *
766 * Bitwise AND.
767 */
768
769static mrb_value
770fix_and(mrb_state *mrb, mrb_value x)
771{
772 mrb_value y;
773
774 mrb_get_args(mrb, "o", &y);
775
776 y = bit_coerce(mrb, y);
777 return mrb_fixnum_value(mrb_fixnum(x) & mrb_fixnum(y));
778}
779
780/* 15.2.8.3.10 */
781/*
782 * call-seq:
783 * fix | integer -> integer_result
784 *
785 * Bitwise OR.
786 */
787
788static mrb_value
789fix_or(mrb_state *mrb, mrb_value x)
790{
791 mrb_value y;
792
793 mrb_get_args(mrb, "o", &y);
794
795 y = bit_coerce(mrb, y);
796 return mrb_fixnum_value(mrb_fixnum(x) | mrb_fixnum(y));
797}
798
799/* 15.2.8.3.11 */
800/*
801 * call-seq:
802 * fix ^ integer -> integer_result
803 *
804 * Bitwise EXCLUSIVE OR.
805 */
806
807static mrb_value
808fix_xor(mrb_state *mrb, mrb_value x)
809{
810 mrb_value y;
811
812 mrb_get_args(mrb, "o", &y);
813
814 y = bit_coerce(mrb, y);
815 return mrb_fixnum_value(mrb_fixnum(x) ^ mrb_fixnum(y));
816}
817
818#define NUMERIC_SHIFT_WIDTH_MAX (MRB_INT_BIT-1)
819
820static mrb_value
821lshift(mrb_state *mrb, mrb_int val, mrb_int width)
822{
823 mrb_assert(width > 0);
824 if (width > NUMERIC_SHIFT_WIDTH_MAX) {
825 mrb_float f = (mrb_float)val;
826 while (width--) {
827 f *= 2;
828 }
829 return mrb_float_value(mrb, f);
830 }
831 return mrb_fixnum_value(val << width);
832}
833
834static mrb_value
835rshift(mrb_int val, mrb_int width)
836{
837 mrb_assert(width > 0);
838 if (width >= NUMERIC_SHIFT_WIDTH_MAX) {
839 if (val < 0) {
840 return mrb_fixnum_value(-1);
841 }
842 return mrb_fixnum_value(0);
843 }
844 return mrb_fixnum_value(val >> width);
845}
846
847static inline void
848fix_shift_get_width(mrb_state *mrb, mrb_int *width)
849{
850 mrb_value y;
851
852 mrb_get_args(mrb, "o", &y);
853 *width = mrb_fixnum(bit_coerce(mrb, y));
854}
855
856/* 15.2.8.3.12 */
857/*
858 * call-seq:
859 * fix << count -> integer or float
860 *
861 * Shifts _fix_ left _count_ positions (right if _count_ is negative).
862 */
863
864static mrb_value
865fix_lshift(mrb_state *mrb, mrb_value x)
866{
867 mrb_int width, val;
868
869 fix_shift_get_width(mrb, &width);
870
871 if (width == 0) {
872 return x;
873 }
874 val = mrb_fixnum(x);
875 if (width < 0) {
876 return rshift(val, -width);
877 }
878 return lshift(mrb, val, width);
879}
880
881/* 15.2.8.3.13 */
882/*
883 * call-seq:
884 * fix >> count -> integer or float
885 *
886 * Shifts _fix_ right _count_ positions (left if _count_ is negative).
887 */
888
889static mrb_value
890fix_rshift(mrb_state *mrb, mrb_value x)
891{
892 mrb_int width, val;
893
894 fix_shift_get_width(mrb, &width);
895
896 if (width == 0) {
897 return x;
898 }
899 val = mrb_fixnum(x);
900 if (width < 0) {
901 return lshift(mrb, val, -width);
902 }
903 return rshift(val, width);
904}
905
906/* 15.2.8.3.23 */
907/*
908 * call-seq:
909 * fix.to_f -> float
910 *
911 * Converts <i>fix</i> to a <code>Float</code>.
912 *
913 */
914
915static mrb_value
916fix_to_f(mrb_state *mrb, mrb_value num)
917{
918 return mrb_float_value(mrb, (mrb_float)mrb_fixnum(num));
919}
920
921/*
922 * Document-class: FloatDomainError
923 *
924 * Raised when attempting to convert special float values
925 * (in particular infinite or NaN)
926 * to numerical classes which don't support them.
927 *
928 * Float::INFINITY.to_r
929 *
930 * <em>raises the exception:</em>
931 *
932 * FloatDomainError: Infinity
933 */
934/* ------------------------------------------------------------------------*/
935MRB_API mrb_value
936mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x)
937{
938 mrb_int z;
939
940 if (!mrb_float_p(x)) {
941 mrb_raise(mrb, E_TYPE_ERROR, "non float value");
942 z = 0; /* not reached. just suppress warnings. */
943 }
944 else {
945 mrb_float d = mrb_float(x);
946
947 if (isinf(d)) {
948 mrb_raise(mrb, E_FLOATDOMAIN_ERROR, d < 0 ? "-Infinity" : "Infinity");
949 }
950 if (isnan(d)) {
951 mrb_raise(mrb, E_FLOATDOMAIN_ERROR, "NaN");
952 }
953 z = (mrb_int)d;
954 }
955 return mrb_fixnum_value(z);
956}
957
958mrb_value
959mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y)
960{
961 mrb_int a;
962
963 a = mrb_fixnum(x);
964 if (mrb_fixnum_p(y)) {
965 mrb_int b, c;
966
967 if (a == 0) return y;
968 b = mrb_fixnum(y);
969 if (mrb_int_add_overflow(a, b, &c)) {
970 return mrb_float_value(mrb, (mrb_float)a + (mrb_float)b);
971 }
972 return mrb_fixnum_value(c);
973 }
974 return mrb_float_value(mrb, (mrb_float)a + mrb_to_flo(mrb, y));
975}
976
977/* 15.2.8.3.1 */
978/*
979 * call-seq:
980 * fix + numeric -> numeric_result
981 *
982 * Performs addition: the class of the resulting object depends on
983 * the class of <code>numeric</code> and on the magnitude of the
984 * result.
985 */
986static mrb_value
987fix_plus(mrb_state *mrb, mrb_value self)
988{
989 mrb_value other;
990
991 mrb_get_args(mrb, "o", &other);
992 return mrb_fixnum_plus(mrb, self, other);
993}
994
995mrb_value
996mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y)
997{
998 mrb_int a;
999
1000 a = mrb_fixnum(x);
1001 if (mrb_fixnum_p(y)) {
1002 mrb_int b, c;
1003
1004 b = mrb_fixnum(y);
1005 if (mrb_int_sub_overflow(a, b, &c)) {
1006 return mrb_float_value(mrb, (mrb_float)a - (mrb_float)b);
1007 }
1008 return mrb_fixnum_value(c);
1009 }
1010 return mrb_float_value(mrb, (mrb_float)a - mrb_to_flo(mrb, y));
1011}
1012
1013/* 15.2.8.3.2 */
1014/* 15.2.8.3.16 */
1015/*
1016 * call-seq:
1017 * fix - numeric -> numeric_result
1018 *
1019 * Performs subtraction: the class of the resulting object depends on
1020 * the class of <code>numeric</code> and on the magnitude of the
1021 * result.
1022 */
1023static mrb_value
1024fix_minus(mrb_state *mrb, mrb_value self)
1025{
1026 mrb_value other;
1027
1028 mrb_get_args(mrb, "o", &other);
1029 return mrb_fixnum_minus(mrb, self, other);
1030}
1031
1032
1033MRB_API mrb_value
1034mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, int base)
1035{
1036 char buf[MRB_INT_BIT+1];
1037 char *b = buf + sizeof buf;
1038 mrb_int val = mrb_fixnum(x);
1039
1040 if (base < 2 || 36 < base) {
1041 mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %S", mrb_fixnum_value(base));
1042 }
1043
1044 if (val == 0) {
1045 *--b = '0';
1046 }
1047 else if (val < 0) {
1048 do {
1049 *--b = mrb_digitmap[-(val % base)];
1050 } while (val /= base);
1051 *--b = '-';
1052 }
1053 else {
1054 do {
1055 *--b = mrb_digitmap[(int)(val % base)];
1056 } while (val /= base);
1057 }
1058
1059 return mrb_str_new(mrb, b, buf + sizeof(buf) - b);
1060}
1061
1062/* 15.2.8.3.25 */
1063/*
1064 * call-seq:
1065 * fix.to_s(base=10) -> string
1066 *
1067 * Returns a string containing the representation of <i>fix</i> radix
1068 * <i>base</i> (between 2 and 36).
1069 *
1070 * 12345.to_s #=> "12345"
1071 * 12345.to_s(2) #=> "11000000111001"
1072 * 12345.to_s(8) #=> "30071"
1073 * 12345.to_s(10) #=> "12345"
1074 * 12345.to_s(16) #=> "3039"
1075 * 12345.to_s(36) #=> "9ix"
1076 *
1077 */
1078static mrb_value
1079fix_to_s(mrb_state *mrb, mrb_value self)
1080{
1081 mrb_int base = 10;
1082
1083 mrb_get_args(mrb, "|i", &base);
1084 return mrb_fixnum_to_str(mrb, self, base);
1085}
1086
1087/* 15.2.9.3.6 */
1088/*
1089 * call-seq:
1090 * self.f <=> other.f => -1, 0, +1
1091 * < => -1
1092 * = => 0
1093 * > => +1
1094 * Comparison---Returns -1, 0, or +1 depending on whether <i>fix</i> is
1095 * less than, equal to, or greater than <i>numeric</i>. This is the
1096 * basis for the tests in <code>Comparable</code>.
1097 */
1098static mrb_value
1099num_cmp(mrb_state *mrb, mrb_value self)
1100{
1101 mrb_value other;
1102 mrb_float x, y;
1103
1104 mrb_get_args(mrb, "o", &other);
1105
1106 x = mrb_to_flo(mrb, self);
1107 switch (mrb_type(other)) {
1108 case MRB_TT_FIXNUM:
1109 y = (mrb_float)mrb_fixnum(other);
1110 break;
1111 case MRB_TT_FLOAT:
1112 y = mrb_float(other);
1113 break;
1114 default:
1115 return mrb_nil_value();
1116 }
1117 if (x > y)
1118 return mrb_fixnum_value(1);
1119 else {
1120 if (x < y)
1121 return mrb_fixnum_value(-1);
1122 return mrb_fixnum_value(0);
1123 }
1124}
1125
1126/* 15.2.9.3.1 */
1127/*
1128 * call-seq:
1129 * float + other -> float
1130 *
1131 * Returns a new float which is the sum of <code>float</code>
1132 * and <code>other</code>.
1133 */
1134static mrb_value
1135flo_plus(mrb_state *mrb, mrb_value x)
1136{
1137 mrb_value y;
1138
1139 mrb_get_args(mrb, "o", &y);
1140 return mrb_float_value(mrb, mrb_float(x) + mrb_to_flo(mrb, y));
1141}
1142
1143/* ------------------------------------------------------------------------*/
1144void
1145mrb_init_numeric(mrb_state *mrb)
1146{
1147 struct RClass *numeric, *integer, *fixnum, *fl;
1148
1149 /* Numeric Class */
1150 numeric = mrb_define_class(mrb, "Numeric", mrb->object_class); /* 15.2.7 */
1151
1152 mrb_define_method(mrb, numeric, "**", num_pow, MRB_ARGS_REQ(1));
1153 mrb_define_method(mrb, numeric, "/", num_div, MRB_ARGS_REQ(1)); /* 15.2.8.3.4 */
1154 mrb_define_method(mrb, numeric, "quo", num_div, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */
1155 mrb_define_method(mrb, numeric, "<=>", num_cmp, MRB_ARGS_REQ(1)); /* 15.2.9.3.6 */
1156
1157 /* Integer Class */
1158 integer = mrb_define_class(mrb, "Integer", numeric); /* 15.2.8 */
1159 mrb_undef_class_method(mrb, integer, "new");
1160 mrb_define_method(mrb, integer, "to_i", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.24 */
1161 mrb_define_method(mrb, integer, "to_int", int_to_i, MRB_ARGS_NONE());
1162
1163 /* Fixnum Class */
1164 mrb->fixnum_class = fixnum = mrb_define_class(mrb, "Fixnum", integer);
1165 mrb_define_method(mrb, fixnum, "+", fix_plus, MRB_ARGS_REQ(1)); /* 15.2.8.3.1 */
1166 mrb_define_method(mrb, fixnum, "-", fix_minus, MRB_ARGS_REQ(1)); /* 15.2.8.3.2 */
1167 mrb_define_method(mrb, fixnum, "*", fix_mul, MRB_ARGS_REQ(1)); /* 15.2.8.3.3 */
1168 mrb_define_method(mrb, fixnum, "%", fix_mod, MRB_ARGS_REQ(1)); /* 15.2.8.3.5 */
1169 mrb_define_method(mrb, fixnum, "==", fix_equal, MRB_ARGS_REQ(1)); /* 15.2.8.3.7 */
1170 mrb_define_method(mrb, fixnum, "~", fix_rev, MRB_ARGS_NONE()); /* 15.2.8.3.8 */
1171 mrb_define_method(mrb, fixnum, "&", fix_and, MRB_ARGS_REQ(1)); /* 15.2.8.3.9 */
1172 mrb_define_method(mrb, fixnum, "|", fix_or, MRB_ARGS_REQ(1)); /* 15.2.8.3.10 */
1173 mrb_define_method(mrb, fixnum, "^", fix_xor, MRB_ARGS_REQ(1)); /* 15.2.8.3.11 */
1174 mrb_define_method(mrb, fixnum, "<<", fix_lshift, MRB_ARGS_REQ(1)); /* 15.2.8.3.12 */
1175 mrb_define_method(mrb, fixnum, ">>", fix_rshift, MRB_ARGS_REQ(1)); /* 15.2.8.3.13 */
1176 mrb_define_method(mrb, fixnum, "eql?", fix_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */
1177 mrb_define_method(mrb, fixnum, "hash", flo_hash, MRB_ARGS_NONE()); /* 15.2.8.3.18 */
1178 mrb_define_method(mrb, fixnum, "to_f", fix_to_f, MRB_ARGS_NONE()); /* 15.2.8.3.23 */
1179 mrb_define_method(mrb, fixnum, "to_s", fix_to_s, MRB_ARGS_NONE()); /* 15.2.8.3.25 */
1180 mrb_define_method(mrb, fixnum, "inspect", fix_to_s, MRB_ARGS_NONE());
1181 mrb_define_method(mrb, fixnum, "divmod", fix_divmod, MRB_ARGS_REQ(1)); /* 15.2.8.3.30 (x) */
1182
1183 /* Float Class */
1184 mrb->float_class = fl = mrb_define_class(mrb, "Float", numeric); /* 15.2.9 */
1185 mrb_undef_class_method(mrb, fl, "new");
1186 mrb_define_method(mrb, fl, "+", flo_plus, MRB_ARGS_REQ(1)); /* 15.2.9.3.1 */
1187 mrb_define_method(mrb, fl, "-", flo_minus, MRB_ARGS_REQ(1)); /* 15.2.9.3.2 */
1188 mrb_define_method(mrb, fl, "*", flo_mul, MRB_ARGS_REQ(1)); /* 15.2.9.3.3 */
1189 mrb_define_method(mrb, fl, "%", flo_mod, MRB_ARGS_REQ(1)); /* 15.2.9.3.5 */
1190 mrb_define_method(mrb, fl, "==", flo_eq, MRB_ARGS_REQ(1)); /* 15.2.9.3.7 */
1191 mrb_define_method(mrb, fl, "ceil", flo_ceil, MRB_ARGS_NONE()); /* 15.2.9.3.8 */
1192 mrb_define_method(mrb, fl, "finite?", flo_finite_p, MRB_ARGS_NONE()); /* 15.2.9.3.9 */
1193 mrb_define_method(mrb, fl, "floor", flo_floor, MRB_ARGS_NONE()); /* 15.2.9.3.10 */
1194 mrb_define_method(mrb, fl, "infinite?", flo_infinite_p, MRB_ARGS_NONE()); /* 15.2.9.3.11 */
1195 mrb_define_method(mrb, fl, "round", flo_round, MRB_ARGS_OPT(1)); /* 15.2.9.3.12 */
1196 mrb_define_method(mrb, fl, "to_f", flo_to_f, MRB_ARGS_NONE()); /* 15.2.9.3.13 */
1197 mrb_define_method(mrb, fl, "to_i", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.14 */
1198 mrb_define_method(mrb, fl, "to_int", flo_truncate, MRB_ARGS_NONE());
1199 mrb_define_method(mrb, fl, "truncate", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.15 */
1200 mrb_define_method(mrb, fl, "divmod", flo_divmod, MRB_ARGS_REQ(1));
1201 mrb_define_method(mrb, fl, "eql?", flo_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */
1202
1203 mrb_define_method(mrb, fl, "to_s", flo_to_s, MRB_ARGS_NONE()); /* 15.2.9.3.16(x) */
1204 mrb_define_method(mrb, fl, "inspect", flo_to_s, MRB_ARGS_NONE());
1205 mrb_define_method(mrb, fl, "nan?", flo_nan_p, MRB_ARGS_NONE());
1206
1207#ifdef INFINITY
1208 mrb_define_const(mrb, fl, "INFINITY", mrb_float_value(mrb, INFINITY));
1209#endif
1210#ifdef NAN
1211 mrb_define_const(mrb, fl, "NAN", mrb_float_value(mrb, NAN));
1212#endif
1213}
Note: See TracBrowser for help on using the repository browser.