summaryrefslogtreecommitdiffhomepage
path: root/src/numeric.c
diff options
context:
space:
mode:
authorPaolo Bosetti <[email protected]>2012-08-06 15:02:03 +0200
committerPaolo Bosetti <[email protected]>2012-08-06 15:02:56 +0200
commitaa0d2f91447c49363059f2e95cb9023f65a6fbef (patch)
tree2cfa325956e62648f2161564adfdf6dddc45b737 /src/numeric.c
parentfd097b8aff7b91bd105fc1daec5a4050a947b763 (diff)
parent193c98ae540d43d082795fd77ea81a4f6f7fd0f6 (diff)
downloadmruby-aa0d2f91447c49363059f2e95cb9023f65a6fbef.tar.gz
mruby-aa0d2f91447c49363059f2e95cb9023f65a6fbef.zip
Updated Xcode project build settings in conformity with 10.8/Xcode 4.4
Diffstat (limited to 'src/numeric.c')
-rw-r--r--src/numeric.c305
1 files changed, 161 insertions, 144 deletions
diff --git a/src/numeric.c b/src/numeric.c
index e1f711478..8280921c7 100644
--- a/src/numeric.c
+++ b/src/numeric.c
@@ -8,13 +8,10 @@
#include "mruby/numeric.h"
#include "mruby/string.h"
#include "mruby/array.h"
-#include <string.h>
-#include "mruby/class.h"
-#include "mruby/variable.h"
-#include <ctype.h>
#include <math.h>
#include <stdio.h>
+#include <assert.h>
#if defined(__FreeBSD__) && __FreeBSD__ < 4
#include <floatingpoint.h>
@@ -28,7 +25,7 @@
#include <ieeefp.h>
#endif
-#define SIGNED_VALUE intptr_t
+#define RSHIFT(x,y) ((x)>>(int)(y))
#ifdef MRB_USE_FLOAT
#define floor(f) floorf(f)
@@ -118,6 +115,12 @@ num_pow(mrb_state *mrb, mrb_value x)
* result.
*/
+mrb_value
+mrb_num_div(mrb_state *mrb, mrb_value x, mrb_value y)
+{
+ return mrb_float_value(mrb_to_flo(mrb, x) / mrb_to_flo(mrb, y));
+}
+
/* 15.2.9.3.19(x) */
/*
* call-seq:
@@ -180,29 +183,25 @@ static mrb_value
flo_to_s(mrb_state *mrb, mrb_value flt)
{
char buf[32];
+ int n;
mrb_float value = mrb_float(flt);
- char *p, *e;
- if (isinf(value))
- return mrb_str_new2(mrb, value < 0 ? "-Infinity" : "Infinity");
- else if(isnan(value))
- return mrb_str_new2(mrb, "NaN");
+ if (isinf(value)) {
+ static const char s[2][5] = { "-inf", "inf" };
+ static const int n[] = { 4, 3 };
+ int idx;
+ idx = (value < 0) ? 0 : 1;
+ return mrb_str_new(mrb, s[idx], n[idx]);
+ } else if(isnan(value))
+ return mrb_str_new(mrb, "NaN", 3);
- sprintf(buf, "%#.15g", value); /* ensure to print decimal point */
- if (!(e = strchr(buf, 'e'))) {
- e = buf + strlen(buf);
- }
- if (!ISDIGIT(e[-1])) { /* reformat if ended with decimal point (ex 111111111111111.) */
- sprintf(buf, "%#.14e", value);
- if (!(e = strchr(buf, 'e'))) {
- e = buf + strlen(buf);
- }
- }
- p = e;
- while (p[-1]=='0' && ISDIGIT(p[-2]))
- p--;
- memmove(p, e, strlen(e)+1);
- return mrb_str_new2(mrb, buf);
+#ifdef MRB_USE_FLOAT
+ n = sprintf(buf, "%.7g", value);
+#else
+ n = sprintf(buf, "%.14g", value);
+#endif
+ assert(n >= 0);
+ return mrb_str_new(mrb, buf, n);
}
/* 15.2.9.3.2 */
@@ -404,7 +403,7 @@ flo_to_f(mrb_state *mrb, mrb_value num)
*/
static mrb_value
-flo_is_infinite_p(mrb_state *mrb, mrb_value num)
+flo_infinite_p(mrb_state *mrb, mrb_value num)
{
mrb_float value = mrb_float(num);
@@ -426,7 +425,7 @@ flo_is_infinite_p(mrb_state *mrb, mrb_value num)
*/
static mrb_value
-flo_is_finite_p(mrb_state *mrb, mrb_value num)
+flo_finite_p(mrb_state *mrb, mrb_value num)
{
mrb_float value = mrb_float(num);
@@ -516,21 +515,13 @@ flo_ceil(mrb_state *mrb, mrb_value num)
*/
static mrb_value
-flo_round(mrb_state *mrb, /*int argc, mrb_value *argv,*/ mrb_value num)
+flo_round(mrb_state *mrb, mrb_value num)
{
- mrb_value nd;
- mrb_float number, f;
+ double number, f;
int ndigits = 0, i;
- mrb_value *argv;
- int argc;
-
- mrb_get_args(mrb, "*", &argv, &argc);
- if (argc == 1) {
- nd = argv[0];
- ndigits = mrb_fixnum(nd);
- }
- number = mrb_float(num);
+ mrb_get_args(mrb, "|i", &ndigits);
+ number = mrb_float(num);
f = 1.0;
i = abs(ndigits);
while (--i >= 0)
@@ -540,7 +531,7 @@ flo_round(mrb_state *mrb, /*int argc, mrb_value *argv,*/ mrb_value num)
if (ndigits < 0) number = 0;
}
else {
- mrb_float d;
+ double d;
if (ndigits < 0) number /= f;
else number *= f;
@@ -558,7 +549,6 @@ flo_round(mrb_state *mrb, /*int argc, mrb_value *argv,*/ mrb_value num)
if (ndigits < 0) number *= f;
else number /= f;
}
-
if (ndigits > 0) return mrb_float_value(number);
return mrb_fixnum_value((mrb_int)number);
}
@@ -691,9 +681,31 @@ int_succ(mrb_state *mrb, mrb_value num)
return mrb_funcall(mrb, num, "+", 1, mrb_fixnum_value(1));
}
-#define SQRT_LONG_MAX ((SIGNED_VALUE)1<<((sizeof(mrb_int)*CHAR_BIT-1)/2))
+#define SQRT_INT_MAX ((mrb_int)1<<((sizeof(mrb_int)*CHAR_BIT-1)/2))
/*tests if N*N would overflow*/
-#define FIT_SQRT_LONG(n) (((n)<SQRT_LONG_MAX)&&((n)>=-SQRT_LONG_MAX))
+#define FIT_SQRT_INT(n) (((n)<SQRT_INT_MAX)&&((n)>=-SQRT_INT_MAX))
+
+mrb_value
+mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y)
+{
+ mrb_int a;
+
+ a = mrb_fixnum(x);
+ if (a == 0) return x;
+ if (FIXNUM_P(y)) {
+ mrb_int b, c;
+
+ b = mrb_fixnum(y);
+ if (FIT_SQRT_INT(a) && FIT_SQRT_INT(b))
+ return mrb_fixnum_value(a*b);
+ c = a * b;
+ if (c/a != b) {
+ return mrb_float_value((mrb_float)a*(mrb_float)b);
+ }
+ return mrb_fixnum_value(c);;
+ }
+ return mrb_float_value((mrb_float)a * mrb_to_flo(mrb, y));
+}
/* 15.2.8.3.3 */
/*
@@ -709,27 +721,8 @@ static mrb_value
fix_mul(mrb_state *mrb, mrb_value x)
{
mrb_value y;
- mrb_int a;
mrb_get_args(mrb, "o", &y);
-
- a = mrb_fixnum(x);
- if (FIXNUM_P(y)) {
- mrb_int b, c;
- mrb_value r;
-
- b = mrb_fixnum(y);
- if (FIT_SQRT_LONG(a) && FIT_SQRT_LONG(b))
- return mrb_fixnum_value(a*b);
- c = a * b;
- r = mrb_fixnum_value(c);
-
- if (a == 0) return x;
- if (mrb_fixnum(r) != c || c/a != b) {
- r = mrb_float_value((mrb_float)a*(mrb_float)b);
- }
- return r;
- }
- return mrb_float_value((mrb_float)a * mrb_to_flo(mrb, y));
+ return mrb_fixnum_mul(mrb, x, y);
}
static void
@@ -772,12 +765,11 @@ static mrb_value
fix_mod(mrb_state *mrb, mrb_value x)
{
mrb_value y;
- mrb_int a;
+ mrb_int a, b;
mrb_get_args(mrb, "o", &y);
-
a = mrb_fixnum(x);
- if (FIXNUM_P(y)) {
+ if (FIXNUM_P(y) && (b=mrb_fixnum(y)) != 0) {
mrb_int mod;
fixdivmod(mrb, a, mrb_fixnum(y), 0, &mod);
@@ -942,8 +934,28 @@ fix_xor(mrb_state *mrb, mrb_value x)
return mrb_fixnum_value(val);
}
-static mrb_value fix_lshift(mrb_state *mrb, mrb_int, unsigned long);
-static mrb_value fix_rshift(mrb_int, unsigned long);
+static mrb_value
+lshift(mrb_state *mrb, mrb_int val, unsigned long width)
+{
+ if (width > (sizeof(mrb_int)*CHAR_BIT-1)
+ || ((unsigned long)abs(val))>>(sizeof(mrb_int)*CHAR_BIT-1-width) > 0) {
+ mrb_raise(mrb, E_RANGE_ERROR, "width(%d) > (%d:sizeof(mrb_int)*CHAR_BIT-1)", width,
+ sizeof(mrb_int)*CHAR_BIT-1);
+ }
+ val = val << width;
+ return mrb_fixnum_value(val);
+}
+
+static mrb_value
+rshift(mrb_int val, unsigned long i)
+{
+ if (i >= sizeof(mrb_int)*CHAR_BIT-1) {
+ if (val < 0) return mrb_fixnum_value(-1);
+ return mrb_fixnum_value(0);
+ }
+ val = RSHIFT(val, i);
+ return mrb_fixnum_value(val);
+}
/* 15.2.8.3.12 */
/*
@@ -954,7 +966,7 @@ static mrb_value fix_rshift(mrb_int, unsigned long);
*/
static mrb_value
-mrb_fix_lshift(mrb_state *mrb, mrb_value x)
+fix_lshift(mrb_state *mrb, mrb_value x)
{
mrb_value y;
mrb_int val, width;
@@ -964,20 +976,8 @@ mrb_fix_lshift(mrb_state *mrb, mrb_value x)
y = bit_coerce(mrb, y);
width = mrb_fixnum(y);
if (width < 0)
- return fix_rshift(val, (unsigned long)-width);
- return fix_lshift(mrb, val, width);
-}
-
-static mrb_value
-fix_lshift(mrb_state *mrb, mrb_int val, unsigned long width)
-{
- if (width > (sizeof(mrb_int)*CHAR_BIT-1)
- || ((unsigned long)abs(val))>>(sizeof(mrb_int)*CHAR_BIT-1-width) > 0) {
- mrb_raise(mrb, E_RANGE_ERROR, "width(%d) > (%d:sizeof(mrb_int)*CHAR_BIT-1)", width,
- sizeof(mrb_int)*CHAR_BIT-1);
- }
- val = val << width;
- return mrb_fixnum_value(val);
+ return rshift(val, (unsigned long)-width);
+ return lshift(mrb, val, width);
}
/* 15.2.8.3.13 */
@@ -989,7 +989,7 @@ fix_lshift(mrb_state *mrb, mrb_int val, unsigned long width)
*/
static mrb_value
-mrb_fix_rshift(mrb_state *mrb, mrb_value x)
+fix_rshift(mrb_state *mrb, mrb_value x)
{
mrb_value y;
mrb_int i, val;
@@ -1000,19 +1000,8 @@ mrb_fix_rshift(mrb_state *mrb, mrb_value x)
i = mrb_fixnum(y);
if (i == 0) return x;
if (i < 0)
- return fix_lshift(mrb, val, (unsigned long)-i);
- return fix_rshift(val, i);
-}
-
-static mrb_value
-fix_rshift(mrb_int val, unsigned long i)
-{
- if (i >= sizeof(mrb_int)*CHAR_BIT-1) {
- if (val < 0) return mrb_fixnum_value(-1);
- return mrb_fixnum_value(0);
- }
- val = RSHIFT(val, i);
- return mrb_fixnum_value(val);
+ return lshift(mrb, val, (unsigned long)-i);
+ return rshift(val, i);
}
/* 15.2.8.3.23 */
@@ -1066,7 +1055,28 @@ flt2big(mrb_state *mrb, mrb_float d)
mrb_value
mrb_flt2big(mrb_state *mrb, mrb_float d)
{
- return mrb_fixnum_value(flt2big(mrb, d));
+ return mrb_fixnum_value(flt2big(mrb, d));
+}
+
+mrb_value
+mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y)
+{
+ mrb_int a;
+
+ a = mrb_fixnum(x);
+ if (a == 0) return y;
+ if (FIXNUM_P(y)) {
+ mrb_int b, c;
+
+ b = mrb_fixnum(y);
+ c = a + b;
+ if (((a < 0) ^ (b < 0)) == 0 && (a < 0) != (c < 0)) {
+ /* integer overflow */
+ return mrb_float_value((mrb_float)a + (mrb_float)b);
+ }
+ return mrb_fixnum_value(c);
+ }
+ return mrb_float_value((mrb_float)a + mrb_to_flo(mrb, y));
}
/* 15.2.8.3.1 */
@@ -1079,15 +1089,32 @@ mrb_flt2big(mrb_state *mrb, mrb_float d)
* result.
*/
static mrb_value
-mrb_fixnum_plus(mrb_state *mrb, mrb_value self)
+fix_plus(mrb_state *mrb, mrb_value self)
{
- mrb_int x, y;
+ mrb_value other;
+
+ mrb_get_args(mrb, "o", &other);
+ return mrb_fixnum_plus(mrb, self, other);
+}
- x = mrb_fixnum(self);
- mrb_get_args(mrb, "i", &y);
+mrb_value
+mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y)
+{
+ mrb_int a;
+
+ a = mrb_fixnum(x);
+ if (FIXNUM_P(y)) {
+ mrb_int b, c;
- DEBUG(printf("%d + %d = %d\n", x, y, x+y));
- return mrb_fixnum_value(x + y);
+ b = mrb_fixnum(y);
+ c = a - b;
+ if (((a < 0) ^ (b < 0)) != 0 && (a < 0) != (c < 0)) {
+ /* integer overflow */
+ return mrb_float_value((mrb_float)a - (mrb_float)b);
+ }
+ return mrb_fixnum_value(c);
+ }
+ return mrb_float_value((mrb_float)a - mrb_to_flo(mrb, y));
}
/* 15.2.8.3.2 */
@@ -1101,15 +1128,12 @@ mrb_fixnum_plus(mrb_state *mrb, mrb_value self)
* result.
*/
static mrb_value
-mrb_fixnum_minus(mrb_state *mrb, mrb_value self)
+fix_minus(mrb_state *mrb, mrb_value self)
{
- mrb_int x, y;
-
- x = mrb_fixnum(self);
- mrb_get_args(mrb, "i", &y);
+ mrb_value other;
- DEBUG(printf("%d - %d = %d\n", x, y, x-y));
- return mrb_fixnum_value(x - y);
+ mrb_get_args(mrb, "o", &other);
+ return mrb_fixnum_minus(mrb, self, other);
}
/* 15.2.8.3.29 (x) */
@@ -1132,16 +1156,23 @@ mrb_fix2str(mrb_state *mrb, mrb_value x, int base)
mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid radix %d", base);
}
if (val == 0) {
- return mrb_str_new2(mrb, "0");
+ return mrb_str_new(mrb, "0", 1);
}
if (val < 0) {
val = -val;
neg = 1;
}
*--b = '\0';
- do {
- *--b = mrb_digitmap[(int)(val % base)];
- } while (val /= base);
+ if (neg && val < 0) {
+ do {
+ *--b = mrb_digitmap[abs(val % base)];
+ } while (val /= base);
+ }
+ else {
+ do {
+ *--b = mrb_digitmap[(int)(val % base)];
+ } while (val /= base);
+ }
if (neg) {
*--b = '-';
}
@@ -1149,19 +1180,6 @@ mrb_fix2str(mrb_state *mrb, mrb_value x, int base)
return mrb_str_new2(mrb, b);
}
-mrb_value
-mrb_fix_to_s(mrb_state *mrb, mrb_value self, int argc, mrb_value *argv)
-{
- int base;
-
- if (argc == 0) base = 10;
- else {
- mrb_get_args(mrb, "i", &base);
- }
-
- return mrb_fix2str(mrb, self, base);
-}
-
/* 15.2.8.3.25 */
/*
* call-seq:
@@ -1179,13 +1197,12 @@ mrb_fix_to_s(mrb_state *mrb, mrb_value self, int argc, mrb_value *argv)
*
*/
static mrb_value
-mrb_fixnum_to_s(mrb_state *mrb, mrb_value self) /* fix_to_s */
+fix_to_s(mrb_state *mrb, mrb_value self)
{
- mrb_value *argv;
- int argc;
+ mrb_int base = 10;
- mrb_get_args(mrb, "*", &argv, &argc);
- return mrb_fix_to_s(mrb, self, argc, argv);
+ mrb_get_args(mrb, "|i", &base);
+ return mrb_fix2str(mrb, self, base);
}
/* 15.2.9.3.6 */
@@ -1236,7 +1253,7 @@ num_cmp(mrb_state *mrb, mrb_value self)
* and <code>other</code>.
*/
static mrb_value
-mrb_float_plus(mrb_state *mrb, mrb_value self)
+flo_plus(mrb_state *mrb, mrb_value self)
{
mrb_float x, y;
@@ -1266,9 +1283,9 @@ mrb_init_numeric(mrb_state *mrb)
integer = mrb_define_class(mrb, "Integer", numeric);
fixnum = mrb->fixnum_class = mrb_define_class(mrb, "Fixnum", integer);
- mrb_undef_method(mrb, fixnum, "new");
- mrb_define_method(mrb, fixnum, "+", mrb_fixnum_plus, ARGS_REQ(1)); /* 15.2.8.3.1 */
- mrb_define_method(mrb, fixnum, "-", mrb_fixnum_minus, ARGS_REQ(1)); /* 15.2.8.3.2 */
+ mrb_undef_class_method(mrb, fixnum, "new");
+ mrb_define_method(mrb, fixnum, "+", fix_plus, ARGS_REQ(1)); /* 15.2.8.3.1 */
+ mrb_define_method(mrb, fixnum, "-", fix_minus, ARGS_REQ(1)); /* 15.2.8.3.2 */
mrb_define_method(mrb, fixnum, "-@", fix_uminus, ARGS_REQ(1)); /* 15.2.7.4.2 */
mrb_define_method(mrb, fixnum, "*", fix_mul, ARGS_REQ(1)); /* 15.2.8.3.3 */
mrb_define_method(mrb, fixnum, "%", fix_mod, ARGS_REQ(1)); /* 15.2.8.3.5 */
@@ -1277,8 +1294,8 @@ mrb_init_numeric(mrb_state *mrb)
mrb_define_method(mrb, fixnum, "&", fix_and, ARGS_REQ(1)); /* 15.2.8.3.9 */
mrb_define_method(mrb, fixnum, "|", fix_or, ARGS_REQ(1)); /* 15.2.8.3.10 */
mrb_define_method(mrb, fixnum, "^", fix_xor, ARGS_REQ(1)); /* 15.2.8.3.11 */
- mrb_define_method(mrb, fixnum, "<<", mrb_fix_lshift, ARGS_REQ(1)); /* 15.2.8.3.12 */
- mrb_define_method(mrb, fixnum, ">>", mrb_fix_rshift, ARGS_REQ(1)); /* 15.2.8.3.13 */
+ mrb_define_method(mrb, fixnum, "<<", fix_lshift, ARGS_REQ(1)); /* 15.2.8.3.12 */
+ mrb_define_method(mrb, fixnum, ">>", fix_rshift, ARGS_REQ(1)); /* 15.2.8.3.13 */
mrb_define_method(mrb, fixnum, "ceil", int_to_i, ARGS_NONE()); /* 15.2.8.3.14 */
mrb_define_method(mrb, fixnum, "eql?", num_eql, ARGS_REQ(1)); /* 15.2.8.3.16 */
mrb_define_method(mrb, fixnum, "floor", num_floor, ARGS_NONE()); /* 15.2.8.3.17 */
@@ -1288,22 +1305,22 @@ mrb_init_numeric(mrb_state *mrb)
mrb_define_method(mrb, fixnum, "succ", fix_succ, ARGS_NONE()); /* 15.2.8.3.21 */
mrb_define_method(mrb, fixnum, "to_f", fix_to_f, ARGS_NONE()); /* 15.2.8.3.23 */
mrb_define_method(mrb, fixnum, "to_i", int_to_i, ARGS_NONE()); /* 15.2.8.3.24 */
- mrb_define_method(mrb, fixnum, "to_s", mrb_fixnum_to_s, ARGS_NONE()); /* 15.2.8.3.25 */
+ mrb_define_method(mrb, fixnum, "to_s", fix_to_s, ARGS_NONE()); /* 15.2.8.3.25 */
mrb_define_method(mrb, fixnum, "truncate", int_to_i, ARGS_NONE()); /* 15.2.8.3.26 */
mrb_define_method(mrb, fixnum, "divmod", fix_divmod, ARGS_REQ(1)); /* 15.2.8.3.30 (x) */
/* Float Class */
fl = mrb->float_class = mrb_define_class(mrb, "Float", numeric);
- mrb_undef_method(mrb, fl, "new");
- mrb_define_method(mrb, fl, "+", mrb_float_plus, ARGS_REQ(1)); /* 15.2.9.3.1 */
+ mrb_undef_class_method(mrb, fl, "new");
+ mrb_define_method(mrb, fl, "+", flo_plus, ARGS_REQ(1)); /* 15.2.9.3.1 */
mrb_define_method(mrb, fl, "-", flo_minus, ARGS_REQ(1)); /* 15.2.9.3.2 */
mrb_define_method(mrb, fl, "*", flo_mul, ARGS_REQ(1)); /* 15.2.9.3.3 */
mrb_define_method(mrb, fl, "%", flo_mod, ARGS_REQ(1)); /* 15.2.9.3.5 */
mrb_define_method(mrb, fl, "==", flo_eq, ARGS_REQ(1)); /* 15.2.9.3.7 */
mrb_define_method(mrb, fl, "ceil", flo_ceil, ARGS_NONE()); /* 15.2.9.3.8 */
- mrb_define_method(mrb, fl, "finite?", flo_is_finite_p, ARGS_NONE()); /* 15.2.9.3.9 */
+ mrb_define_method(mrb, fl, "finite?", flo_finite_p, ARGS_NONE()); /* 15.2.9.3.9 */
mrb_define_method(mrb, fl, "floor", flo_floor, ARGS_NONE()); /* 15.2.9.3.10 */
- mrb_define_method(mrb, fl, "infinite?", flo_is_infinite_p,ARGS_NONE()); /* 15.2.9.3.11 */
+ mrb_define_method(mrb, fl, "infinite?", flo_infinite_p, ARGS_NONE()); /* 15.2.9.3.11 */
mrb_define_method(mrb, fl, "round", flo_round, ARGS_ANY()); /* 15.2.9.3.12 */
mrb_define_method(mrb, fl, "to_f", flo_to_f, ARGS_NONE()); /* 15.2.9.3.13 */
mrb_define_method(mrb, fl, "to_i", flo_truncate, ARGS_NONE()); /* 15.2.9.3.14 */