mbed I/F binding for mruby

Dependents:   mruby_mbed_web mirb_mbed

mbed-mruby

How to use

Class

Committer:
mzta
Date:
Mon Apr 13 05:20:15 2015 +0000
Revision:
1:8ccd1d494a4b
Parent:
0:158c61bb030f
- code refactoring.; - add SPI, SPISlave, I2C class to mruby-mbed (Incomplete).

Who changed what in which revision?

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