source: EcnlProtoTool/trunk/mruby-1.3.0/src/numeric.c@ 331

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

prototoolに関連するプロジェクトをnewlibからmuslを使うよう変更・更新
ntshellをnewlibの下位の実装から、muslのsyscallの実装に変更・更新
以下のOSSをアップデート
・mruby-1.3.0
・musl-1.1.18
・onigmo-6.1.3
・tcc-0.9.27
以下のOSSを追加
・openssl-1.1.0e
・curl-7.57.0
・zlib-1.2.11
以下のmrbgemsを追加
・iij/mruby-digest
・iij/mruby-env
・iij/mruby-errno
・iij/mruby-iijson
・iij/mruby-ipaddr
・iij/mruby-mock
・iij/mruby-require
・iij/mruby-tls-openssl

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