summaryrefslogtreecommitdiffhomepage
path: root/src/numeric.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/numeric.c')
-rw-r--r--src/numeric.c465
1 files changed, 277 insertions, 188 deletions
diff --git a/src/numeric.c b/src/numeric.c
index fe1a18f04..fd9f5ce2c 100644
--- a/src/numeric.c
+++ b/src/numeric.c
@@ -4,36 +4,25 @@
** See Copyright Notice in mruby.h
*/
-#ifndef MRB_NO_FLOAT
-#include <float.h>
-#include <math.h>
-#endif
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-
#include <mruby.h>
#include <mruby/array.h>
#include <mruby/numeric.h>
#include <mruby/string.h>
#include <mruby/class.h>
#include <mruby/presym.h>
+#include <string.h>
#ifndef MRB_NO_FLOAT
#ifdef MRB_USE_FLOAT32
#define trunc(f) truncf(f)
-#define floor(f) floorf(f)
-#define ceil(f) ceilf(f)
#define fmod(x,y) fmodf(x,y)
-#define FLO_TO_STR_PREC 8
#else
-#define FLO_TO_STR_PREC 16
#endif
#endif
#ifndef MRB_NO_FLOAT
MRB_API mrb_float
-mrb_to_flo(mrb_state *mrb, mrb_value val)
+mrb_as_float(mrb_state *mrb, mrb_value val)
{
switch (mrb_type(val)) {
case MRB_TT_INTEGER:
@@ -137,10 +126,6 @@ mrb_div_int(mrb_state *mrb, mrb_int x, mrb_int y)
return 0;
}
-#ifndef MRB_NO_FLOAT
-mrb_float mrb_div_flo(mrb_float x, mrb_float y);
-#endif
-
/* 15.2.8.3.4 */
/* 15.2.9.3.4 */
/*
@@ -164,7 +149,7 @@ int_div(mrb_state *mrb, mrb_value x)
#ifdef MRB_NO_FLOAT
mrb_raise(mrb, E_TYPE_ERROR, "non integer division");
#else
- return mrb_float_value(mrb, mrb_div_flo((mrb_float)a, mrb_to_flo(mrb, y)));
+ return mrb_float_value(mrb, mrb_div_float((mrb_float)a, mrb_as_float(mrb, y)));
#endif
}
@@ -191,7 +176,7 @@ int_idiv(mrb_state *mrb, mrb_value x)
if (y == 0) {
int_zerodiv(mrb);
}
- return mrb_fixnum_value(mrb_integer(x) / y);
+ return mrb_int_value(mrb, mrb_integer(x) / y);
}
static mrb_value
@@ -218,8 +203,9 @@ coerce_step_counter(mrb_state *mrb, mrb_value self)
mrb_get_args(mrb, "oo", &num, &step);
#ifndef MRB_NO_FLOAT
- if (mrb_float_p(self) || mrb_float_p(num) || mrb_float_p(step)) {
- return mrb_Float(mrb, self);
+ mrb->c->ci->mid = 0;
+ if (mrb_float_p(num) || mrb_float_p(step)) {
+ return mrb_to_float(mrb, self);
}
#endif
@@ -240,7 +226,7 @@ static mrb_value
flo_pow(mrb_state *mrb, mrb_value x)
{
mrb_value y = mrb_get_arg1(mrb);
- mrb_float d = pow(mrb_to_flo(mrb, x), mrb_to_flo(mrb, y));
+ mrb_float d = pow(mrb_as_float(mrb, x), mrb_as_float(mrb, y));
return mrb_float_value(mrb, d);
}
@@ -255,7 +241,7 @@ flo_idiv(mrb_state *mrb, mrb_value xv)
}
mrb_float
-mrb_div_flo(mrb_float x, mrb_float y)
+mrb_div_float(mrb_float x, mrb_float y)
{
if (y != 0.0) {
return x / y;
@@ -275,14 +261,39 @@ flo_div(mrb_state *mrb, mrb_value x)
mrb_float a = mrb_float(x);
if (mrb_float_p(y)) {
- a = mrb_div_flo(a, mrb_float(y));
+ a = mrb_div_float(a, mrb_float(y));
}
else {
- a = mrb_div_flo(a, mrb_to_flo(mrb, y));
+ a = mrb_div_float(a, mrb_as_float(mrb, y));
}
return mrb_float_value(mrb, a);
}
+/* the argument `fmt` is no longer used; you can pass `NULL` */
+mrb_value
+mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt)
+{
+ char buf[25];
+#ifdef MRB_USE_FLOAT32
+ const int prec = 7;
+#else
+ const int prec = 15;
+#endif
+
+ mrb_format_float(mrb_float(flo), buf, sizeof(buf), 'g', prec, '\0');
+ for (char *p = buf; *p; p++) {
+ if (*p == '.') goto exit;
+ if (*p == 'e') {
+ memmove(p+2, p, strlen(p)+1);
+ memcpy(p, ".0", 2);
+ goto exit;
+ }
+ }
+ strcat(buf, ".0");
+ exit:
+ return mrb_str_new_cstr(mrb, buf);
+}
+
/* 15.2.9.3.16(x) */
/*
* call-seq:
@@ -307,49 +318,14 @@ flo_to_s(mrb_state *mrb, mrb_value flt)
if (isinf(f)) {
str = f < 0 ? mrb_str_new_lit(mrb, "-Infinity")
: mrb_str_new_lit(mrb, "Infinity");
- goto exit;
}
else if (isnan(f)) {
str = mrb_str_new_lit(mrb, "NaN");
- goto exit;
}
else {
- char fmt[] = "%." MRB_STRINGIZE(FLO_TO_STR_PREC) "g";
- mrb_int len;
- char *begp, *p, *endp;
-
- str = mrb_float_to_str(mrb, flt, fmt);
-
- insert_dot_zero:
- begp = RSTRING_PTR(str);
- len = RSTRING_LEN(str);
- for (p = begp, endp = p + len; p < endp; ++p) {
- if (*p == '.') {
- goto exit;
- }
- else if (*p == 'e') {
- ptrdiff_t e_pos = p - begp;
- mrb_str_cat(mrb, str, ".0", 2);
- p = RSTRING_PTR(str) + e_pos;
- memmove(p + 2, p, len - e_pos);
- memcpy(p, ".0", 2);
- goto exit;
- }
- }
-
- if (FLO_TO_STR_PREC + (begp[0] == '-') <= len) {
- --fmt[sizeof(fmt) - 3]; /* %.16g(%.8g) -> %.15g(%.7g) */
- str = mrb_float_to_str(mrb, flt, fmt);
- goto insert_dot_zero;
- }
- else {
- mrb_str_cat(mrb, str, ".0", 2);
- }
-
- goto exit;
+ str = mrb_float_to_str(mrb, flt, NULL);
}
- exit:
RSTR_SET_ASCII_FLAG(mrb_str_ptr(str));
return str;
}
@@ -376,7 +352,7 @@ flo_add(mrb_state *mrb, mrb_value x)
return mrb_funcall_id(mrb, y, MRB_OPSYM(add), 1, x);
#endif
default:
- return mrb_float_value(mrb, a + mrb_to_flo(mrb, y));
+ return mrb_float_value(mrb, a + mrb_as_float(mrb, y));
}
}
@@ -404,7 +380,7 @@ flo_sub(mrb_state *mrb, mrb_value x)
return mrb_funcall_id(mrb, x, MRB_OPSYM(minus), 0);
#endif
default:
- return mrb_float_value(mrb, a - mrb_to_flo(mrb, y));
+ return mrb_float_value(mrb, a - mrb_as_float(mrb, y));
}
}
@@ -431,7 +407,7 @@ flo_mul(mrb_state *mrb, mrb_value x)
return mrb_funcall_id(mrb, y, MRB_OPSYM(mul), 1, x);
#endif
default:
- return mrb_float_value(mrb, a * mrb_to_flo(mrb, y));
+ return mrb_float_value(mrb, a * mrb_as_float(mrb, y));
}
}
@@ -490,7 +466,7 @@ flo_mod(mrb_state *mrb, mrb_value x)
mrb_value y = mrb_get_arg1(mrb);
mrb_float mod;
- flodivmod(mrb, mrb_float(x), mrb_to_flo(mrb, y), 0, &mod);
+ flodivmod(mrb, mrb_float(x), mrb_as_float(mrb, y), 0, &mod);
return mrb_float_value(mrb, mod);
}
#endif
@@ -551,7 +527,7 @@ flo_eq(mrb_state *mrb, mrb_value x)
return mrb_bool_value(mrb_float(x) == mrb_float(y));
#ifdef MRB_USE_RATIONAL
case MRB_TT_RATIONAL:
- return mrb_bool_value(mrb_float(x) == mrb_to_flo(mrb, y));
+ return mrb_bool_value(mrb_float(x) == mrb_as_float(mrb, y));
#endif
#ifdef MRB_USE_COMPLEX
case MRB_TT_COMPLEX:
@@ -761,49 +737,127 @@ mrb_check_num_exact(mrb_state *mrb, mrb_float num)
}
}
+static mrb_value
+flo_ceil_floor(mrb_state *mrb, mrb_value num, double (*func)(double))
+{
+ mrb_float f = mrb_float(num);
+ mrb_int ndigits = 0;
+#ifdef MRB_USE_FLOAT32
+ const int fprec = 7;
+#else
+ const int fprec = 15;
+#endif
+
+ mrb_get_args(mrb, "|i", &ndigits);
+ if (f == 0.0) {
+ return ndigits > 0 ? mrb_float_value(mrb, f) : mrb_fixnum_value(0);
+ }
+ if (ndigits > 0) {
+ if (ndigits > fprec) return num;
+ mrb_float d = pow(10, ndigits);
+ f = func(f * d) / d;
+ return mrb_float_value(mrb, f);
+ }
+ if (ndigits < 0) {
+ mrb_float d = pow(10, -ndigits);
+ f = func(f / d) * d;
+ }
+ else { /* ndigits == 0 */
+ f = func(f);
+ }
+ mrb_check_num_exact(mrb, f);
+ return mrb_int_value(mrb, (mrb_int)f);
+}
+
/* 15.2.9.3.10 */
/*
* call-seq:
- * flt.floor -> integer
+ * float.floor([ndigits]) -> integer or float
*
- * Returns the largest integer less than or equal to <i>flt</i>.
+ * Returns the largest number less than or equal to +float+ with
+ * a precision of +ndigits+ decimal digits (default: 0).
+ *
+ * When the precision is negative, the returned value is an integer
+ * with at least <code>ndigits.abs</code> trailing zeros.
+ *
+ * Returns a floating point number when +ndigits+ is positive,
+ * otherwise returns an integer.
*
* 1.2.floor #=> 1
* 2.0.floor #=> 2
* (-1.2).floor #=> -2
* (-2.0).floor #=> -2
+ *
+ * 1.234567.floor(2) #=> 1.23
+ * 1.234567.floor(3) #=> 1.234
+ * 1.234567.floor(4) #=> 1.2345
+ * 1.234567.floor(5) #=> 1.23456
+ *
+ * 34567.89.floor(-5) #=> 0
+ * 34567.89.floor(-4) #=> 30000
+ * 34567.89.floor(-3) #=> 34000
+ * 34567.89.floor(-2) #=> 34500
+ * 34567.89.floor(-1) #=> 34560
+ * 34567.89.floor(0) #=> 34567
+ * 34567.89.floor(1) #=> 34567.8
+ * 34567.89.floor(2) #=> 34567.89
+ * 34567.89.floor(3) #=> 34567.89
+ *
+ * Note that the limited precision of floating point arithmetic
+ * might lead to surprising results:
+ *
+ * (0.3 / 0.1).floor #=> 2 (!)
*/
-
static mrb_value
flo_floor(mrb_state *mrb, mrb_value num)
{
- mrb_float f = floor(mrb_float(num));
-
- mrb_check_num_exact(mrb, f);
- return mrb_int_value(mrb, (mrb_int)f);
+ return flo_ceil_floor(mrb, num, floor);
}
/* 15.2.9.3.8 */
/*
* call-seq:
- * flt.ceil -> integer
+ * float.ceil([ndigits]) -> integer or float
+ *
+ * Returns the smallest number greater than or equal to +float+ with
+ * a precision of +ndigits+ decimal digits (default: 0).
+ *
+ * When the precision is negative, the returned value is an integer
+ * with at least <code>ndigits.abs</code> trailing zeros.
*
- * Returns the smallest <code>Integer</code> greater than or equal to
- * <i>flt</i>.
+ * Returns a floating point number when +ndigits+ is positive,
+ * otherwise returns an integer.
*
* 1.2.ceil #=> 2
* 2.0.ceil #=> 2
* (-1.2).ceil #=> -1
* (-2.0).ceil #=> -2
+ *
+ * 1.234567.ceil(2) #=> 1.24
+ * 1.234567.ceil(3) #=> 1.235
+ * 1.234567.ceil(4) #=> 1.2346
+ * 1.234567.ceil(5) #=> 1.23457
+ *
+ * 34567.89.ceil(-5) #=> 100000
+ * 34567.89.ceil(-4) #=> 40000
+ * 34567.89.ceil(-3) #=> 35000
+ * 34567.89.ceil(-2) #=> 34600
+ * 34567.89.ceil(-1) #=> 34570
+ * 34567.89.ceil(0) #=> 34568
+ * 34567.89.ceil(1) #=> 34567.9
+ * 34567.89.ceil(2) #=> 34567.89
+ * 34567.89.ceil(3) #=> 34567.89
+ *
+ * Note that the limited precision of floating point arithmetic
+ * might lead to surprising results:
+ *
+ * (2.1 / 0.7).ceil #=> 4 (!)
*/
static mrb_value
flo_ceil(mrb_state *mrb, mrb_value num)
{
- mrb_float f = ceil(mrb_float(num));
-
- mrb_check_num_exact(mrb, f);
- return mrb_int_value(mrb, (mrb_int)f);
+ return flo_ceil_floor(mrb, num, ceil);
}
/* 15.2.9.3.12 */
@@ -853,6 +907,7 @@ flo_round(mrb_state *mrb, mrb_value num)
mrb_check_num_exact(mrb, number);
f = 1.0;
+ if (ndigits < -DBL_DIG-2) return mrb_fixnum_value(0);
i = ndigits >= 0 ? ndigits : -ndigits;
if (ndigits > DBL_DIG+2) return num;
while (--i >= 0)
@@ -891,6 +946,18 @@ flo_round(mrb_state *mrb, mrb_value num)
}
/* 15.2.9.3.14 */
+static mrb_value
+flo_to_i(mrb_state *mrb, mrb_value num)
+{
+ mrb_float f = mrb_float(num);
+
+ if (f > 0.0) f = floor(f);
+ if (f < 0.0) f = ceil(f);
+
+ mrb_check_num_exact(mrb, f);
+ return mrb_int_value(mrb, (mrb_int)f);
+}
+
/* 15.2.9.3.15 */
/*
* call-seq:
@@ -903,13 +970,8 @@ flo_round(mrb_state *mrb, mrb_value num)
static mrb_value
flo_truncate(mrb_state *mrb, mrb_value num)
{
- mrb_float f = mrb_float(num);
-
- if (f > 0.0) f = floor(f);
- if (f < 0.0) f = ceil(f);
-
- mrb_check_num_exact(mrb, f);
- return mrb_int_value(mrb, (mrb_int)f);
+ if (signbit(mrb_float(num))) return flo_ceil(mrb, num);
+ return flo_floor(mrb, num);
}
static mrb_value
@@ -917,6 +979,15 @@ flo_nan_p(mrb_state *mrb, mrb_value num)
{
return mrb_bool_value(isnan(mrb_float(num)));
}
+
+static mrb_value
+flo_abs(mrb_state *mrb, mrb_value num)
+{
+ mrb_float f = mrb_float(num);
+
+ if (signbit(f)) return mrb_float_value(mrb, -f);
+ return num;
+}
#endif
/*
@@ -967,7 +1038,7 @@ fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y)
#ifdef MRB_NO_FLOAT
mrb_raise(mrb, E_TYPE_ERROR, "non integer multiplication");
#else
- return mrb_float_value(mrb, (mrb_float)a * mrb_to_flo(mrb, y));
+ return mrb_float_value(mrb, (mrb_float)a * mrb_as_float(mrb, y));
#endif
}
}
@@ -980,7 +1051,7 @@ mrb_num_mul(mrb_state *mrb, mrb_value x, mrb_value y)
}
#ifndef MRB_NO_FLOAT
if (mrb_float_p(x)) {
- return mrb_float_value(mrb, mrb_float(x) * mrb_to_flo(mrb, y));
+ return mrb_float_value(mrb, mrb_float(x) * mrb_as_float(mrb, y));
}
#endif
#if defined(MRB_USE_RATIONAL) || defined(MRB_USE_COMPLEX)
@@ -999,7 +1070,7 @@ mrb_num_mul(mrb_state *mrb, mrb_value x, mrb_value y)
/* 15.2.8.3.3 */
/*
* call-seq:
- * fix * numeric -> numeric_result
+ * int * numeric -> numeric_result
*
* Performs multiplication: the class of the resulting object depends on
* the class of <code>numeric</code> and on the magnitude of the
@@ -1015,7 +1086,7 @@ int_mul(mrb_state *mrb, mrb_value x)
}
static void
-fixdivmod(mrb_state *mrb, mrb_int x, mrb_int y, mrb_int *divp, mrb_int *modp)
+intdivmod(mrb_state *mrb, mrb_int x, mrb_int y, mrb_int *divp, mrb_int *modp)
{
if (y == 0) {
int_zerodiv(mrb);
@@ -1039,10 +1110,9 @@ fixdivmod(mrb_state *mrb, mrb_int x, mrb_int y, mrb_int *divp, mrb_int *modp)
/* 15.2.8.3.5 */
/*
* call-seq:
- * fix % other -> real
- * fix.modulo(other) -> real
+ * int % other -> real
*
- * Returns <code>fix</code> modulo <code>other</code>.
+ * Returns <code>int</code> modulo <code>other</code>.
* See <code>numeric.divmod</code> for more information.
*/
@@ -1053,27 +1123,29 @@ int_mod(mrb_state *mrb, mrb_value x)
mrb_int a, b;
a = mrb_integer(x);
- if (mrb_integer_p(y) && a != MRB_INT_MIN && (b=mrb_integer(y)) != MRB_INT_MIN) {
- mrb_int mod;
-
- fixdivmod(mrb, a, b, NULL, &mod);
- return mrb_fixnum_value(mod);
+ if (mrb_integer_p(y)) {
+ b = mrb_integer(y);
+ if (b == 0) int_zerodiv(mrb);
+ if (a == MRB_INT_MIN && b == -1) return mrb_fixnum_value(0);
+ mrb_int mod = a % b;
+ if ((a < 0) != (b < 0) && mod != 0) {
+ mod += b;
+ }
+ return mrb_int_value(mrb, mod);
}
#ifdef MRB_NO_FLOAT
mrb_raise(mrb, E_TYPE_ERROR, "non integer modulo");
#else
- else {
- mrb_float mod;
+ mrb_float mod;
- flodivmod(mrb, (mrb_float)a, mrb_to_flo(mrb, y), NULL, &mod);
- return mrb_float_value(mrb, mod);
- }
+ flodivmod(mrb, (mrb_float)a, mrb_as_float(mrb, y), NULL, &mod);
+ return mrb_float_value(mrb, mod);
#endif
}
/*
* call-seq:
- * fix.divmod(numeric) -> array
+ * int.divmod(numeric) -> array
*
* See <code>Numeric#divmod</code>.
*/
@@ -1085,7 +1157,7 @@ int_divmod(mrb_state *mrb, mrb_value x)
if (mrb_integer_p(y)) {
mrb_int div, mod;
- fixdivmod(mrb, mrb_integer(x), mrb_integer(y), &div, &mod);
+ intdivmod(mrb, mrb_integer(x), mrb_integer(y), &div, &mod);
return mrb_assoc_new(mrb, mrb_int_value(mrb, div), mrb_int_value(mrb, mod));
}
#ifdef MRB_NO_FLOAT
@@ -1095,7 +1167,7 @@ int_divmod(mrb_state *mrb, mrb_value x)
mrb_float div, mod;
mrb_value a, b;
- flodivmod(mrb, (mrb_float)mrb_integer(x), mrb_to_flo(mrb, y), &div, &mod);
+ flodivmod(mrb, (mrb_float)mrb_integer(x), mrb_as_float(mrb, y), &div, &mod);
a = mrb_int_value(mrb, (mrb_int)div);
b = mrb_float_value(mrb, mod);
return mrb_assoc_new(mrb, a, b);
@@ -1111,7 +1183,7 @@ flo_divmod(mrb_state *mrb, mrb_value x)
mrb_float div, mod;
mrb_value a, b;
- flodivmod(mrb, mrb_float(x), mrb_to_flo(mrb, y), &div, &mod);
+ flodivmod(mrb, mrb_float(x), mrb_as_float(mrb, y), &div, &mod);
if (!FIXABLE_FLOAT(div))
a = mrb_float_value(mrb, div);
else
@@ -1124,9 +1196,9 @@ flo_divmod(mrb_state *mrb, mrb_value x)
/* 15.2.8.3.7 */
/*
* call-seq:
- * fix == other -> true or false
+ * int == other -> true or false
*
- * Return <code>true</code> if <code>fix</code> equals <code>other</code>
+ * Return <code>true</code> if <code>int</code> equals <code>other</code>
* numerically.
*
* 1 == 2 #=> false
@@ -1161,7 +1233,7 @@ int_equal(mrb_state *mrb, mrb_value x)
/* 15.2.8.3.8 */
/*
* call-seq:
- * ~fix -> integer
+ * ~int -> integer
*
* One's complement: returns a number where each bit is flipped.
* ex.0---00001 (1)-> 1---11110 (-2)
@@ -1194,7 +1266,7 @@ static mrb_value flo_xor(mrb_state *mrb, mrb_value x);
/* 15.2.8.3.9 */
/*
* call-seq:
- * fix & integer -> integer_result
+ * int & integer -> integer_result
*
* Bitwise AND.
*/
@@ -1210,7 +1282,7 @@ int_and(mrb_state *mrb, mrb_value x)
/* 15.2.8.3.10 */
/*
* call-seq:
- * fix | integer -> integer_result
+ * int | integer -> integer_result
*
* Bitwise OR.
*/
@@ -1226,7 +1298,7 @@ int_or(mrb_state *mrb, mrb_value x)
/* 15.2.8.3.11 */
/*
* call-seq:
- * fix ^ integer -> integer_result
+ * int ^ integer -> integer_result
*
* Bitwise EXCLUSIVE OR.
*/
@@ -1241,45 +1313,48 @@ int_xor(mrb_state *mrb, mrb_value x)
#define NUMERIC_SHIFT_WIDTH_MAX (MRB_INT_BIT-1)
-static mrb_value
-lshift(mrb_state *mrb, mrb_int val, mrb_int width)
+mrb_bool
+mrb_num_shift(mrb_state *mrb, mrb_int val, mrb_int width, mrb_int *num)
{
- mrb_assert(width >= 0);
- if (val > 0) {
+ if (width < 0) { /* rshift */
+ if (width == MRB_INT_MIN || -width >= NUMERIC_SHIFT_WIDTH_MAX) {
+ if (val < 0) {
+ *num = -1;
+ }
+ else {
+ *num = 0;
+ }
+ }
+ else {
+ *num = val >> -width;
+ }
+ }
+ else if (val > 0) {
if ((width > NUMERIC_SHIFT_WIDTH_MAX) ||
(val > (MRB_INT_MAX >> width))) {
- int_overflow(mrb, "bit shift");
+ return FALSE;
}
- return mrb_int_value(mrb, val << width);
+ *num = val << width;
}
else {
if ((width > NUMERIC_SHIFT_WIDTH_MAX) ||
- (val <= (MRB_INT_MIN >> width))) {
- int_overflow(mrb, "bit shift");
+ (val < (MRB_INT_MIN >> width))) {
+ return FALSE;
}
- return mrb_int_value(mrb, (val * ((mrb_int)1 << width)));
+ if (width == NUMERIC_SHIFT_WIDTH_MAX)
+ *num = MRB_INT_MIN;
+ else
+ *num = val * ((mrb_int)1 << width);
}
-}
-
-static mrb_value
-rshift(mrb_state *mrb, mrb_int val, mrb_int width)
-{
- mrb_assert(width >= 0);
- if (width >= NUMERIC_SHIFT_WIDTH_MAX) {
- if (val < 0) {
- return mrb_fixnum_value(-1);
- }
- return mrb_fixnum_value(0);
- }
- return mrb_int_value(mrb, val >> width);
+ return TRUE;
}
/* 15.2.8.3.12 */
/*
* call-seq:
- * fix << count -> integer or float
+ * int << count -> integer or float
*
- * Shifts _fix_ left _count_ positions (right if _count_ is negative).
+ * Shifts _int_ left _count_ positions (right if _count_ is negative).
*/
static mrb_value
@@ -1293,19 +1368,18 @@ int_lshift(mrb_state *mrb, mrb_value x)
}
val = mrb_integer(x);
if (val == 0) return x;
- if (width < 0) {
- if (width == MRB_INT_MIN) return rshift(mrb, val, MRB_INT_BIT);
- return rshift(mrb, val, -width);
+ if (!mrb_num_shift(mrb, val, width, &val)) {
+ int_overflow(mrb, "bit shift");
}
- return lshift(mrb, val, width);
+ return mrb_int_value(mrb, val);
}
/* 15.2.8.3.13 */
/*
* call-seq:
- * fix >> count -> integer or float
+ * int >> count -> integer or float
*
- * Shifts _fix_ right _count_ positions (left if _count_ is negative).
+ * Shifts _int_ right _count_ positions (left if _count_ is negative).
*/
static mrb_value
@@ -1319,19 +1393,19 @@ int_rshift(mrb_state *mrb, mrb_value x)
}
val = mrb_integer(x);
if (val == 0) return x;
- if (width < 0) {
- if (width == MRB_INT_MIN) int_overflow(mrb, "bit shift");
- return lshift(mrb, val, -width);
+ if (width == MRB_INT_MIN) int_overflow(mrb, "bit shift");
+ if (!mrb_num_shift(mrb, val, -width, &val)) {
+ int_overflow(mrb, "bit shift");
}
- return rshift(mrb, val, width);
+ return mrb_int_value(mrb, val);
}
/* 15.2.8.3.23 */
/*
* call-seq:
- * fix.to_f -> float
+ * int.to_f -> float
*
- * Converts <i>fix</i> to a <code>Float</code>.
+ * Converts <i>int</i> to a <code>Float</code>.
*
*/
@@ -1357,13 +1431,12 @@ int_to_f(mrb_state *mrb, mrb_value num)
*/
/* ------------------------------------------------------------------------*/
MRB_API mrb_value
-mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x)
+mrb_float_to_integer(mrb_state *mrb, mrb_value x)
{
mrb_int z = 0;
if (!mrb_float_p(x)) {
mrb_raise(mrb, E_TYPE_ERROR, "non float value");
- z = 0; /* not reached. just suppress warnings. */
}
else {
mrb_float d = mrb_float(x);
@@ -1406,7 +1479,7 @@ int_plus(mrb_state *mrb, mrb_value x, mrb_value y)
#ifdef MRB_NO_FLOAT
mrb_raise(mrb, E_TYPE_ERROR, "non integer addition");
#else
- return mrb_float_value(mrb, (mrb_float)a + mrb_to_flo(mrb, y));
+ return mrb_float_value(mrb, (mrb_float)a + mrb_as_float(mrb, y));
#endif
}
}
@@ -1419,7 +1492,7 @@ mrb_num_plus(mrb_state *mrb, mrb_value x, mrb_value y)
}
#ifndef MRB_NO_FLOAT
if (mrb_float_p(x)) {
- return mrb_float_value(mrb, mrb_float(x) + mrb_to_flo(mrb, y));
+ return mrb_float_value(mrb, mrb_float(x) + mrb_as_float(mrb, y));
}
#endif
#if defined(MRB_USE_RATIONAL) || defined(MRB_USE_COMPLEX)
@@ -1438,7 +1511,7 @@ mrb_num_plus(mrb_state *mrb, mrb_value x, mrb_value y)
/* 15.2.8.3.1 */
/*
* call-seq:
- * fix + numeric -> numeric_result
+ * int + numeric -> numeric_result
*
* Performs addition: the class of the resulting object depends on
* the class of <code>numeric</code> and on the magnitude of the
@@ -1478,7 +1551,7 @@ int_minus(mrb_state *mrb, mrb_value x, mrb_value y)
#ifdef MRB_NO_FLOAT
mrb_raise(mrb, E_TYPE_ERROR, "non integer subtraction");
#else
- return mrb_float_value(mrb, (mrb_float)a - mrb_to_flo(mrb, y));
+ return mrb_float_value(mrb, (mrb_float)a - mrb_as_float(mrb, y));
#endif
}
}
@@ -1491,7 +1564,7 @@ mrb_num_minus(mrb_state *mrb, mrb_value x, mrb_value y)
}
#ifndef MRB_NO_FLOAT
if (mrb_float_p(x)) {
- return mrb_float_value(mrb, mrb_float(x) - mrb_to_flo(mrb, y));
+ return mrb_float_value(mrb, mrb_float(x) - mrb_as_float(mrb, y));
}
#endif
#if defined(MRB_USE_RATIONAL) || defined(MRB_USE_COMPLEX)
@@ -1511,7 +1584,7 @@ mrb_num_minus(mrb_state *mrb, mrb_value x, mrb_value y)
/* 15.2.8.3.16 */
/*
* call-seq:
- * fix - numeric -> numeric_result
+ * int - numeric -> numeric_result
*
* Performs subtraction: the class of the resulting object depends on
* the class of <code>numeric</code> and on the magnitude of the
@@ -1525,35 +1598,51 @@ int_sub(mrb_state *mrb, mrb_value self)
return int_minus(mrb, self, other);
}
-
-MRB_API mrb_value
-mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, mrb_int base)
+MRB_API char*
+mrb_int_to_cstr(char *buf, size_t len, mrb_int n, mrb_int base)
{
- char buf[MRB_INT_BIT+1];
- char *b = buf + sizeof buf;
- mrb_int val = mrb_integer(x);
- mrb_value str;
+ char *bufend = buf + len;
+ char *b = bufend-1;
- if (base < 2 || 36 < base) {
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %i", base);
- }
+ if (base < 2 || 36 < base) return NULL;
+ if (len < 2) return NULL;
- if (val == 0) {
- *--b = '0';
+ if (n == 0) {
+ buf[0] = '0';
+ buf[1] = '\0';
+ return buf;
}
- else if (val < 0) {
+
+ *b = '\0';
+ if (n < 0) {
do {
- *--b = mrb_digitmap[-(val % base)];
- } while (val /= base);
- *--b = '-';
+ if (b-- == buf) return NULL;
+ *b = mrb_digitmap[-(n % base)];
+ } while (n /= base);
+ if (b-- == buf) return NULL;
+ *b = '-';
}
else {
do {
- *--b = mrb_digitmap[(int)(val % base)];
- } while (val /= base);
+ if (b-- == buf) return NULL;
+ *b = mrb_digitmap[(int)(n % base)];
+ } while (n /= base);
}
+ return b;
+}
- str = mrb_str_new(mrb, b, buf + sizeof(buf) - b);
+MRB_API mrb_value
+mrb_integer_to_str(mrb_state *mrb, mrb_value x, mrb_int base)
+{
+ char buf[MRB_INT_BIT+1];
+ mrb_int val = mrb_integer(x);
+
+ if (base < 2 || 36 < base) {
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %i", base);
+ }
+ const char *p = mrb_int_to_cstr(buf, sizeof(buf), val, base);
+ mrb_assert(p != NULL);
+ mrb_value str = mrb_str_new_cstr(mrb, p);
RSTR_SET_ASCII_FLAG(mrb_str_ptr(str));
return str;
}
@@ -1561,9 +1650,9 @@ mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, mrb_int base)
/* 15.2.8.3.25 */
/*
* call-seq:
- * fix.to_s(base=10) -> string
+ * int.to_s(base=10) -> string
*
- * Returns a string containing the representation of <i>fix</i> radix
+ * Returns a string containing the representation of <i>int</i> radix
* <i>base</i> (between 2 and 36).
*
* 12345.to_s #=> "12345"
@@ -1580,7 +1669,7 @@ int_to_s(mrb_state *mrb, mrb_value self)
mrb_int base = 10;
mrb_get_args(mrb, "|i", &base);
- return mrb_fixnum_to_str(mrb, self, base);
+ return mrb_integer_to_str(mrb, self, base);
}
/* compare two numbers: (1:0:-1; -2 for error) */
@@ -1596,7 +1685,7 @@ cmpnum(mrb_state *mrb, mrb_value v1, mrb_value v2)
#ifdef MRB_NO_FLOAT
x = mrb_integer(v1);
#else
- x = mrb_to_flo(mrb, v1);
+ x = mrb_as_float(mrb, v1);
#endif
switch (mrb_type(v2)) {
case MRB_TT_INTEGER:
@@ -1612,7 +1701,7 @@ cmpnum(mrb_state *mrb, mrb_value v1, mrb_value v2)
break;
#ifdef MRB_USE_RATIONAL
case MRB_TT_RATIONAL:
- y = mrb_to_flo(mrb, v2);
+ y = mrb_as_float(mrb, v2);
break;
#endif
#endif
@@ -1635,7 +1724,7 @@ cmpnum(mrb_state *mrb, mrb_value v1, mrb_value v2)
* < => -1
* = => 0
* > => +1
- * Comparison---Returns -1, 0, or +1 depending on whether <i>fix</i> is
+ * Comparison---Returns -1, 0, or +1 depending on whether <i>int</i> is
* less than, equal to, or greater than <i>numeric</i>. This is the
* basis for the tests in <code>Comparable</code>. When the operands are
* not comparable, it returns nil instead of raising an exception.
@@ -1817,21 +1906,21 @@ mrb_init_numeric(mrb_state *mrb)
mrb_define_method(mrb, fl, "^", flo_xor, MRB_ARGS_REQ(1));
mrb_define_method(mrb, fl, ">>", flo_rshift, MRB_ARGS_REQ(1));
mrb_define_method(mrb, fl, "<<", flo_lshift, MRB_ARGS_REQ(1));
- mrb_define_method(mrb, fl, "ceil", flo_ceil, MRB_ARGS_NONE()); /* 15.2.9.3.8 */
+ mrb_define_method(mrb, fl, "ceil", flo_ceil, MRB_ARGS_OPT(1)); /* 15.2.9.3.8 */
mrb_define_method(mrb, fl, "finite?", flo_finite_p, MRB_ARGS_NONE()); /* 15.2.9.3.9 */
- mrb_define_method(mrb, fl, "floor", flo_floor, MRB_ARGS_NONE()); /* 15.2.9.3.10 */
+ mrb_define_method(mrb, fl, "floor", flo_floor, MRB_ARGS_OPT(1)); /* 15.2.9.3.10 */
mrb_define_method(mrb, fl, "infinite?", flo_infinite_p, MRB_ARGS_NONE()); /* 15.2.9.3.11 */
mrb_define_method(mrb, fl, "round", flo_round, MRB_ARGS_OPT(1)); /* 15.2.9.3.12 */
mrb_define_method(mrb, fl, "to_f", flo_to_f, MRB_ARGS_NONE()); /* 15.2.9.3.13 */
- mrb_define_method(mrb, fl, "to_i", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.14 */
- mrb_define_method(mrb, fl, "to_int", flo_truncate, MRB_ARGS_NONE());
- mrb_define_method(mrb, fl, "truncate", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.15 */
+ mrb_define_method(mrb, fl, "to_i", flo_to_i, MRB_ARGS_NONE()); /* 15.2.9.3.14 */
+ mrb_define_method(mrb, fl, "truncate", flo_truncate, MRB_ARGS_OPT(1)); /* 15.2.9.3.15 */
mrb_define_method(mrb, fl, "divmod", flo_divmod, MRB_ARGS_REQ(1));
mrb_define_method(mrb, fl, "eql?", flo_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */
mrb_define_method(mrb, fl, "to_s", flo_to_s, MRB_ARGS_NONE()); /* 15.2.9.3.16(x) */
mrb_define_method(mrb, fl, "inspect", flo_to_s, MRB_ARGS_NONE());
mrb_define_method(mrb, fl, "nan?", flo_nan_p, MRB_ARGS_NONE());
+ mrb_define_method(mrb, fl, "abs", flo_abs, MRB_ARGS_NONE()); /* 15.2.7.4.3 */
#ifdef INFINITY
mrb_define_const_id(mrb, fl, MRB_SYM(INFINITY), mrb_float_value(mrb, INFINITY));