2000-05-01 13:42:38 +04:00
|
|
|
/**********************************************************************
|
1998-01-16 15:13:05 +03:00
|
|
|
|
|
|
|
numeric.c -
|
|
|
|
|
|
|
|
$Author$
|
|
|
|
created at: Fri Aug 13 18:33:09 JST 1993
|
|
|
|
|
* encoding.c: provide basic features for M17N.
* parse.y: encoding aware parsing.
* parse.y (pragma_encoding): encoding specification pragma.
* parse.y (rb_intern3): encoding specified symbols.
* string.c (rb_str_length): length based on characters.
for older behavior, bytesize method added.
* string.c (rb_str_index_m): index based on characters. rindex as
well.
* string.c (succ_char): encoding aware succeeding string.
* string.c (rb_str_reverse): reverse based on characters.
* string.c (rb_str_inspect): encoding aware string description.
* string.c (rb_str_upcase_bang): encoding aware case conversion.
downcase, capitalize, swapcase as well.
* string.c (rb_str_tr_bang): tr based on characters. delete,
squeeze, tr_s, count as well.
* string.c (rb_str_split_m): split based on characters.
* string.c (rb_str_each_line): encoding aware each_line.
* string.c (rb_str_each_char): added. iteration based on
characters.
* string.c (rb_str_strip_bang): encoding aware whitespace
stripping. lstrip, rstrip as well.
* string.c (rb_str_justify): encoding aware justifying (ljust,
rjust, center).
* string.c (str_encoding): get encoding attribute from a string.
* re.c (rb_reg_initialize): encoding aware regular expression
* sprintf.c (rb_str_format): formatting (i.e. length count) based
on characters.
* io.c (rb_io_getc): getc to return one-character string.
for older behavior, getbyte method added.
* ext/stringio/stringio.c (strio_getc): ditto.
* io.c (rb_io_ungetc): allow pushing arbitrary string at the
current reading point.
* ext/stringio/stringio.c (strio_ungetc): ditto.
* ext/strscan/strscan.c: encoding support.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13261 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-08-25 07:29:39 +04:00
|
|
|
Copyright (C) 1993-2007 Yukihiro Matsumoto
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2000-05-01 13:42:38 +04:00
|
|
|
**********************************************************************/
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2020-05-08 12:31:09 +03:00
|
|
|
#include "ruby/internal/config.h"
|
2019-12-04 11:16:30 +03:00
|
|
|
|
2016-06-13 14:43:54 +03:00
|
|
|
#include <assert.h>
|
2004-06-16 18:21:34 +04:00
|
|
|
#include <ctype.h>
|
1998-01-16 15:13:05 +03:00
|
|
|
#include <math.h>
|
1999-01-20 07:59:39 +03:00
|
|
|
#include <stdio.h>
|
2002-12-19 12:20:20 +03:00
|
|
|
|
|
|
|
#ifdef HAVE_FLOAT_H
|
|
|
|
#include <float.h>
|
|
|
|
#endif
|
|
|
|
|
2003-12-11 05:39:59 +03:00
|
|
|
#ifdef HAVE_IEEEFP_H
|
|
|
|
#include <ieeefp.h>
|
|
|
|
#endif
|
|
|
|
|
2019-12-04 11:16:30 +03:00
|
|
|
#include "id.h"
|
|
|
|
#include "internal.h"
|
|
|
|
#include "internal/array.h"
|
|
|
|
#include "internal/compilers.h"
|
|
|
|
#include "internal/complex.h"
|
|
|
|
#include "internal/enumerator.h"
|
|
|
|
#include "internal/gc.h"
|
|
|
|
#include "internal/hash.h"
|
|
|
|
#include "internal/numeric.h"
|
|
|
|
#include "internal/object.h"
|
|
|
|
#include "internal/rational.h"
|
Optimize dynamic string interpolation for symbol/true/false/nil/0-9
This provides a significant speedup for symbol, true, false,
nil, and 0-9, class/module, and a small speedup in most other cases.
Speedups (using included benchmarks):
:symbol :: 60%
0-9 :: 50%
Class/Module :: 50%
nil/true/false :: 20%
integer :: 10%
[] :: 10%
"" :: 3%
One reason this approach is faster is it reduces the number of
VM instructions for each interpolated value.
Initial idea, approach, and benchmarks from Eric Wong. I applied
the same approach against the master branch, updating it to handle
the significant internal changes since this was first proposed 4
years ago (such as CALL_INFO/CALL_CACHE -> CALL_DATA). I also
expanded it to optimize true/false/nil/0-9/class/module, and added
handling of missing methods, refined methods, and RUBY_DEBUG.
This renames the tostring insn to anytostring, and adds an
objtostring insn that implements the optimization. This requires
making a few functions non-static, and adding some non-static
functions.
This disables 4 YJIT tests. Those tests should be reenabled after
YJIT optimizes the new objtostring insn.
Implements [Feature #13715]
Co-authored-by: Eric Wong <e@80x24.org>
Co-authored-by: Alan Wu <XrXr@users.noreply.github.com>
Co-authored-by: Yusuke Endoh <mame@ruby-lang.org>
Co-authored-by: Koichi Sasada <ko1@atdot.net>
2021-11-19 02:10:20 +03:00
|
|
|
#include "internal/string.h"
|
2019-12-04 11:16:30 +03:00
|
|
|
#include "internal/util.h"
|
|
|
|
#include "internal/variable.h"
|
|
|
|
#include "ruby/encoding.h"
|
|
|
|
#include "ruby/util.h"
|
2020-06-21 00:55:09 +03:00
|
|
|
#include "builtin.h"
|
2019-12-04 11:16:30 +03:00
|
|
|
|
2002-12-24 11:53:56 +03:00
|
|
|
/* use IEEE 64bit values if not defined */
|
|
|
|
#ifndef FLT_RADIX
|
|
|
|
#define FLT_RADIX 2
|
|
|
|
#endif
|
|
|
|
#ifndef DBL_MIN
|
|
|
|
#define DBL_MIN 2.2250738585072014e-308
|
|
|
|
#endif
|
|
|
|
#ifndef DBL_MAX
|
|
|
|
#define DBL_MAX 1.7976931348623157e+308
|
|
|
|
#endif
|
|
|
|
#ifndef DBL_MIN_EXP
|
|
|
|
#define DBL_MIN_EXP (-1021)
|
|
|
|
#endif
|
|
|
|
#ifndef DBL_MAX_EXP
|
|
|
|
#define DBL_MAX_EXP 1024
|
|
|
|
#endif
|
|
|
|
#ifndef DBL_MIN_10_EXP
|
|
|
|
#define DBL_MIN_10_EXP (-307)
|
|
|
|
#endif
|
|
|
|
#ifndef DBL_MAX_10_EXP
|
2002-12-24 13:20:29 +03:00
|
|
|
#define DBL_MAX_10_EXP 308
|
2002-12-24 11:53:56 +03:00
|
|
|
#endif
|
|
|
|
#ifndef DBL_DIG
|
|
|
|
#define DBL_DIG 15
|
|
|
|
#endif
|
|
|
|
#ifndef DBL_MANT_DIG
|
|
|
|
#define DBL_MANT_DIG 53
|
|
|
|
#endif
|
2002-12-19 12:20:20 +03:00
|
|
|
#ifndef DBL_EPSILON
|
2002-12-24 11:53:56 +03:00
|
|
|
#define DBL_EPSILON 2.2204460492503131e-16
|
2002-12-19 12:20:20 +03:00
|
|
|
#endif
|
|
|
|
|
2018-01-27 07:14:26 +03:00
|
|
|
#ifndef USE_RB_INFINITY
|
2011-08-05 17:28:50 +04:00
|
|
|
#elif !defined(WORDS_BIGENDIAN) /* BYTE_ORDER == LITTLE_ENDIAN */
|
2011-10-23 13:03:33 +04:00
|
|
|
const union bytesequence4_or_float rb_infinity = {{0x00, 0x00, 0x80, 0x7f}};
|
2009-12-29 10:05:39 +03:00
|
|
|
#else
|
2011-10-23 13:03:33 +04:00
|
|
|
const union bytesequence4_or_float rb_infinity = {{0x7f, 0x80, 0x00, 0x00}};
|
2009-12-29 10:05:39 +03:00
|
|
|
#endif
|
|
|
|
|
2018-01-27 07:14:26 +03:00
|
|
|
#ifndef USE_RB_NAN
|
2011-08-05 17:28:50 +04:00
|
|
|
#elif !defined(WORDS_BIGENDIAN) /* BYTE_ORDER == LITTLE_ENDIAN */
|
2011-10-23 13:03:33 +04:00
|
|
|
const union bytesequence4_or_float rb_nan = {{0x00, 0x00, 0xc0, 0x7f}};
|
2009-12-29 10:05:39 +03:00
|
|
|
#else
|
2011-10-23 13:03:33 +04:00
|
|
|
const union bytesequence4_or_float rb_nan = {{0x7f, 0xc0, 0x00, 0x00}};
|
2009-12-29 10:05:39 +03:00
|
|
|
#endif
|
|
|
|
|
2007-11-13 19:34:45 +03:00
|
|
|
#ifndef HAVE_ROUND
|
|
|
|
double
|
|
|
|
round(double x)
|
|
|
|
{
|
|
|
|
double f;
|
|
|
|
|
|
|
|
if (x > 0.0) {
|
|
|
|
f = floor(x);
|
|
|
|
x = f + (x - f >= 0.5);
|
|
|
|
}
|
|
|
|
else if (x < 0.0) {
|
|
|
|
f = ceil(x);
|
|
|
|
x = f - (f - x >= 0.5);
|
|
|
|
}
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-08-15 04:59:58 +03:00
|
|
|
static double
|
2016-11-05 12:49:39 +03:00
|
|
|
round_half_up(double x, double s)
|
2016-08-15 04:59:58 +03:00
|
|
|
{
|
|
|
|
double f, xs = x * s;
|
|
|
|
|
|
|
|
f = round(xs);
|
2016-11-18 09:29:51 +03:00
|
|
|
if (s == 1.0) return f;
|
2016-08-15 04:59:58 +03:00
|
|
|
if (x > 0) {
|
|
|
|
if ((double)((f + 0.5) / s) <= x) f += 1;
|
|
|
|
x = f;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if ((double)((f - 0.5) / s) >= x) f -= 1;
|
|
|
|
x = f;
|
|
|
|
}
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
2016-11-25 09:28:00 +03:00
|
|
|
static double
|
|
|
|
round_half_down(double x, double s)
|
|
|
|
{
|
|
|
|
double f, xs = x * s;
|
|
|
|
|
|
|
|
f = round(xs);
|
|
|
|
if (x > 0) {
|
|
|
|
if ((double)((f - 0.5) / s) >= x) f -= 1;
|
|
|
|
x = f;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if ((double)((f + 0.5) / s) <= x) f += 1;
|
|
|
|
x = f;
|
|
|
|
}
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
2016-11-05 12:49:39 +03:00
|
|
|
static double
|
|
|
|
round_half_even(double x, double s)
|
|
|
|
{
|
|
|
|
double f, d, xs = x * s;
|
|
|
|
|
|
|
|
if (x > 0.0) {
|
|
|
|
f = floor(xs);
|
|
|
|
d = xs - f;
|
|
|
|
if (d > 0.5)
|
|
|
|
d = 1.0;
|
|
|
|
else if (d == 0.5 || ((double)((f + 0.5) / s) <= x))
|
|
|
|
d = fmod(f, 2.0);
|
|
|
|
else
|
|
|
|
d = 0.0;
|
|
|
|
x = f + d;
|
|
|
|
}
|
|
|
|
else if (x < 0.0) {
|
|
|
|
f = ceil(xs);
|
|
|
|
d = f - xs;
|
|
|
|
if (d > 0.5)
|
|
|
|
d = 1.0;
|
|
|
|
else if (d == 0.5 || ((double)((f - 0.5) / s) >= x))
|
|
|
|
d = fmod(-f, 2.0);
|
|
|
|
else
|
|
|
|
d = 0.0;
|
|
|
|
x = f - d;
|
|
|
|
}
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
2016-04-03 01:38:44 +03:00
|
|
|
static VALUE fix_lshift(long, unsigned long);
|
|
|
|
static VALUE fix_rshift(long, unsigned long);
|
2011-03-23 02:07:36 +03:00
|
|
|
static VALUE int_pow(long x, unsigned long y);
|
2020-06-16 11:47:59 +03:00
|
|
|
static VALUE rb_int_floor(VALUE num, int ndigits);
|
|
|
|
static VALUE rb_int_ceil(VALUE num, int ndigits);
|
2016-04-18 06:56:33 +03:00
|
|
|
static VALUE flo_to_i(VALUE num);
|
2017-05-27 04:26:31 +03:00
|
|
|
static int float_round_overflow(int ndigits, int binexp);
|
|
|
|
static int float_round_underflow(int ndigits, int binexp);
|
2011-03-23 02:07:36 +03:00
|
|
|
|
2019-08-03 02:37:08 +03:00
|
|
|
static ID id_coerce;
|
|
|
|
#define id_div idDiv
|
|
|
|
#define id_divmod idDivmod
|
2014-05-20 12:28:33 +04:00
|
|
|
#define id_to_i idTo_i
|
2014-02-28 19:47:52 +04:00
|
|
|
#define id_eq idEq
|
|
|
|
#define id_cmp idCmp
|
1998-01-16 15:13:05 +03:00
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
VALUE rb_cNumeric;
|
|
|
|
VALUE rb_cFloat;
|
|
|
|
VALUE rb_cInteger;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
1999-08-13 09:45:20 +04:00
|
|
|
VALUE rb_eZeroDivError;
|
|
|
|
VALUE rb_eFloatDomainError;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2014-07-01 18:36:03 +04:00
|
|
|
static ID id_to, id_by;
|
2013-09-02 18:56:06 +04:00
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
void
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
rb_num_zerodiv(void)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
1999-08-13 09:45:20 +04:00
|
|
|
rb_raise(rb_eZeroDivError, "divided by 0");
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2016-11-05 12:49:39 +03:00
|
|
|
enum ruby_num_rounding_mode
|
|
|
|
rb_num_get_rounding_option(VALUE opts)
|
|
|
|
{
|
|
|
|
static ID round_kwds[1];
|
|
|
|
VALUE rounding;
|
2016-11-21 05:17:29 +03:00
|
|
|
VALUE str;
|
2016-11-05 12:49:39 +03:00
|
|
|
const char *s;
|
|
|
|
|
|
|
|
if (!NIL_P(opts)) {
|
|
|
|
if (!round_kwds[0]) {
|
|
|
|
round_kwds[0] = rb_intern_const("half");
|
|
|
|
}
|
|
|
|
if (!rb_get_kwargs(opts, round_kwds, 0, 1, &rounding)) goto noopt;
|
2016-11-21 05:17:29 +03:00
|
|
|
if (SYMBOL_P(rounding)) {
|
|
|
|
str = rb_sym2str(rounding);
|
|
|
|
}
|
2016-12-21 04:29:57 +03:00
|
|
|
else if (NIL_P(rounding)) {
|
|
|
|
goto noopt;
|
|
|
|
}
|
2016-11-21 05:17:29 +03:00
|
|
|
else if (!RB_TYPE_P(str = rounding, T_STRING)) {
|
|
|
|
str = rb_check_string_type(rounding);
|
|
|
|
if (NIL_P(str)) goto invalid;
|
|
|
|
}
|
2020-01-27 10:12:15 +03:00
|
|
|
rb_must_asciicompat(str);
|
2016-11-21 05:17:29 +03:00
|
|
|
s = RSTRING_PTR(str);
|
|
|
|
switch (RSTRING_LEN(str)) {
|
2016-11-05 12:49:39 +03:00
|
|
|
case 2:
|
2016-11-21 05:17:29 +03:00
|
|
|
if (rb_memcicmp(s, "up", 2) == 0)
|
2016-11-05 12:49:39 +03:00
|
|
|
return RUBY_NUM_ROUND_HALF_UP;
|
|
|
|
break;
|
|
|
|
case 4:
|
2016-11-21 05:17:29 +03:00
|
|
|
if (rb_memcicmp(s, "even", 4) == 0)
|
2016-11-05 12:49:39 +03:00
|
|
|
return RUBY_NUM_ROUND_HALF_EVEN;
|
2016-11-25 09:28:00 +03:00
|
|
|
if (strncasecmp(s, "down", 4) == 0)
|
|
|
|
return RUBY_NUM_ROUND_HALF_DOWN;
|
2016-11-05 12:49:39 +03:00
|
|
|
break;
|
|
|
|
}
|
2016-11-21 05:17:29 +03:00
|
|
|
invalid:
|
2016-12-21 16:26:16 +03:00
|
|
|
rb_raise(rb_eArgError, "invalid rounding mode: % "PRIsVALUE, rounding);
|
2016-11-05 12:49:39 +03:00
|
|
|
}
|
|
|
|
noopt:
|
|
|
|
return RUBY_NUM_ROUND_DEFAULT;
|
|
|
|
}
|
|
|
|
|
2010-10-13 07:56:31 +04:00
|
|
|
/* experimental API */
|
|
|
|
int
|
|
|
|
rb_num_to_uint(VALUE val, unsigned int *ret)
|
|
|
|
{
|
|
|
|
#define NUMERR_TYPE 1
|
|
|
|
#define NUMERR_NEGATIVE 2
|
|
|
|
#define NUMERR_TOOLARGE 3
|
|
|
|
if (FIXNUM_P(val)) {
|
|
|
|
long v = FIX2LONG(val);
|
2010-10-13 09:58:35 +04:00
|
|
|
#if SIZEOF_INT < SIZEOF_LONG
|
|
|
|
if (v > (long)UINT_MAX) return NUMERR_TOOLARGE;
|
|
|
|
#endif
|
2010-10-13 07:56:31 +04:00
|
|
|
if (v < 0) return NUMERR_NEGATIVE;
|
|
|
|
*ret = (unsigned int)v;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-09-03 14:50:12 +03:00
|
|
|
if (RB_BIGNUM_TYPE_P(val)) {
|
2014-02-16 01:17:34 +04:00
|
|
|
if (BIGNUM_NEGATIVE_P(val)) return NUMERR_NEGATIVE;
|
2010-10-13 07:56:31 +04:00
|
|
|
#if SIZEOF_INT < SIZEOF_LONG
|
|
|
|
/* long is 64bit */
|
|
|
|
return NUMERR_TOOLARGE;
|
|
|
|
#else
|
|
|
|
/* long is 32bit */
|
2013-06-08 18:57:28 +04:00
|
|
|
if (rb_absint_size(val, NULL) > sizeof(int)) return NUMERR_TOOLARGE;
|
2010-10-13 07:56:31 +04:00
|
|
|
*ret = (unsigned int)rb_big2ulong((VALUE)val);
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
return NUMERR_TYPE;
|
|
|
|
}
|
2003-12-27 08:46:46 +03:00
|
|
|
|
2012-06-20 10:31:35 +04:00
|
|
|
#define method_basic_p(klass) rb_method_basic_definition_p(klass, mid)
|
|
|
|
|
2016-03-26 04:54:50 +03:00
|
|
|
static inline int
|
|
|
|
int_pos_p(VALUE num)
|
|
|
|
{
|
|
|
|
if (FIXNUM_P(num)) {
|
2016-03-28 15:25:41 +03:00
|
|
|
return FIXNUM_POSITIVE_P(num);
|
2016-03-26 04:54:50 +03:00
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(num)) {
|
2016-03-28 15:25:41 +03:00
|
|
|
return BIGNUM_POSITIVE_P(num);
|
2016-03-26 04:54:50 +03:00
|
|
|
}
|
2016-11-05 18:45:42 +03:00
|
|
|
rb_raise(rb_eTypeError, "not an Integer");
|
2016-03-26 04:54:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
int_neg_p(VALUE num)
|
|
|
|
{
|
|
|
|
if (FIXNUM_P(num)) {
|
|
|
|
return FIXNUM_NEGATIVE_P(num);
|
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(num)) {
|
2016-03-26 04:54:50 +03:00
|
|
|
return BIGNUM_NEGATIVE_P(num);
|
|
|
|
}
|
2016-11-05 18:45:42 +03:00
|
|
|
rb_raise(rb_eTypeError, "not an Integer");
|
2016-03-26 04:54:50 +03:00
|
|
|
}
|
|
|
|
|
2018-06-14 10:09:02 +03:00
|
|
|
int
|
|
|
|
rb_int_positive_p(VALUE num)
|
|
|
|
{
|
|
|
|
return int_pos_p(num);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
rb_int_negative_p(VALUE num)
|
|
|
|
{
|
|
|
|
return int_neg_p(num);
|
|
|
|
}
|
|
|
|
|
2013-02-22 07:46:47 +04:00
|
|
|
int
|
|
|
|
rb_num_negative_p(VALUE num)
|
|
|
|
{
|
2017-12-04 05:35:40 +03:00
|
|
|
return rb_num_negative_int_p(num);
|
2013-02-22 07:46:47 +04:00
|
|
|
}
|
|
|
|
|
2016-08-13 17:08:03 +03:00
|
|
|
static VALUE
|
|
|
|
num_funcall_op_0(VALUE x, VALUE arg, int recursive)
|
|
|
|
{
|
|
|
|
ID func = (ID)arg;
|
|
|
|
if (recursive) {
|
|
|
|
const char *name = rb_id2name(func);
|
|
|
|
if (ISALNUM(name[0])) {
|
|
|
|
rb_name_error(func, "%"PRIsVALUE".%"PRIsVALUE,
|
|
|
|
x, ID2SYM(func));
|
|
|
|
}
|
|
|
|
else if (name[0] && name[1] == '@' && !name[2]) {
|
|
|
|
rb_name_error(func, "%c%"PRIsVALUE,
|
|
|
|
name[0], x);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
rb_name_error(func, "%"PRIsVALUE"%"PRIsVALUE,
|
|
|
|
ID2SYM(func), x);
|
|
|
|
}
|
|
|
|
}
|
2017-04-15 05:09:27 +03:00
|
|
|
return rb_funcallv(x, func, 0, 0);
|
2016-08-13 17:08:03 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
num_funcall0(VALUE x, ID func)
|
|
|
|
{
|
|
|
|
return rb_exec_recursive(num_funcall_op_0, x, (VALUE)func);
|
|
|
|
}
|
|
|
|
|
2018-01-18 12:44:39 +03:00
|
|
|
NORETURN(static void num_funcall_op_1_recursion(VALUE x, ID func, VALUE y));
|
|
|
|
|
2016-11-02 01:34:30 +03:00
|
|
|
static void
|
|
|
|
num_funcall_op_1_recursion(VALUE x, ID func, VALUE y)
|
|
|
|
{
|
|
|
|
const char *name = rb_id2name(func);
|
|
|
|
if (ISALNUM(name[0])) {
|
|
|
|
rb_name_error(func, "%"PRIsVALUE".%"PRIsVALUE"(%"PRIsVALUE")",
|
|
|
|
x, ID2SYM(func), y);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
rb_name_error(func, "%"PRIsVALUE"%"PRIsVALUE"%"PRIsVALUE,
|
|
|
|
x, ID2SYM(func), y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-13 17:08:03 +03:00
|
|
|
static VALUE
|
2016-10-22 16:33:34 +03:00
|
|
|
num_funcall_op_1(VALUE y, VALUE arg, int recursive)
|
2016-08-13 17:08:03 +03:00
|
|
|
{
|
|
|
|
ID func = (ID)((VALUE *)arg)[0];
|
2016-10-22 16:33:34 +03:00
|
|
|
VALUE x = ((VALUE *)arg)[1];
|
2016-08-13 17:08:03 +03:00
|
|
|
if (recursive) {
|
2016-11-02 01:34:30 +03:00
|
|
|
num_funcall_op_1_recursion(x, func, y);
|
2016-08-13 17:08:03 +03:00
|
|
|
}
|
|
|
|
return rb_funcall(x, func, 1, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
num_funcall1(VALUE x, ID func, VALUE y)
|
|
|
|
{
|
|
|
|
VALUE args[2];
|
|
|
|
args[0] = (VALUE)func;
|
2016-10-22 16:33:34 +03:00
|
|
|
args[1] = x;
|
|
|
|
return rb_exec_recursive_paired(num_funcall_op_1, y, x, (VALUE)args);
|
2016-08-13 17:08:03 +03:00
|
|
|
}
|
|
|
|
|
2003-12-27 08:46:46 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-10-19 02:35:06 +03:00
|
|
|
* coerce(other) -> array
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-10-19 02:35:06 +03:00
|
|
|
* Returns a 2-element array containing two numeric elements,
|
|
|
|
* formed from the two operands +self+ and +other+,
|
|
|
|
* of a common compatible type.
|
2013-07-15 22:27:23 +04:00
|
|
|
*
|
2021-10-19 02:35:06 +03:00
|
|
|
* Of the Core and Standard Library classes,
|
|
|
|
* Integer, Rational, and Complex use this implementation.
|
|
|
|
*
|
|
|
|
* Examples:
|
|
|
|
*
|
|
|
|
* i = 2 # => 2
|
|
|
|
* i.coerce(3) # => [3, 2]
|
|
|
|
* i.coerce(3.0) # => [3.0, 2.0]
|
|
|
|
* i.coerce(Rational(1, 2)) # => [0.5, 2.0]
|
|
|
|
* i.coerce(Complex(3, 4)) # Raises RangeError.
|
|
|
|
*
|
|
|
|
* r = Rational(5, 2) # => (5/2)
|
|
|
|
* r.coerce(2) # => [(2/1), (5/2)]
|
|
|
|
* r.coerce(2.0) # => [2.0, 2.5]
|
|
|
|
* r.coerce(Rational(2, 3)) # => [(2/3), (5/2)]
|
|
|
|
* r.coerce(Complex(3, 4)) # => [(3+4i), ((5/2)+0i)]
|
|
|
|
*
|
|
|
|
* c = Complex(2, 3) # => (2+3i)
|
|
|
|
* c.coerce(2) # => [(2+0i), (2+3i)]
|
|
|
|
* c.coerce(2.0) # => [(2.0+0i), (2+3i)]
|
|
|
|
* c.coerce(Rational(1, 2)) # => [((1/2)+0i), (2+3i)]
|
|
|
|
* c.coerce(Complex(3, 4)) # => [(3+4i), (2+3i)]
|
|
|
|
*
|
|
|
|
* Raises an exception if any type conversion fails.
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2003-12-27 08:46:46 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
num_coerce(VALUE x, VALUE y)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
1999-01-20 07:59:39 +03:00
|
|
|
if (CLASS_OF(x) == CLASS_OF(y))
|
2000-02-17 10:11:22 +03:00
|
|
|
return rb_assoc_new(y, x);
|
2008-06-30 20:03:41 +04:00
|
|
|
x = rb_Float(x);
|
|
|
|
y = rb_Float(y);
|
|
|
|
return rb_assoc_new(y, x);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2014-01-15 12:16:37 +04:00
|
|
|
NORETURN(static void coerce_failed(VALUE x, VALUE y));
|
|
|
|
static void
|
|
|
|
coerce_failed(VALUE x, VALUE y)
|
|
|
|
{
|
2019-08-25 01:39:57 +03:00
|
|
|
if (SPECIAL_CONST_P(y) || SYMBOL_P(y) || RB_FLOAT_TYPE_P(y)) {
|
2015-01-13 15:07:14 +03:00
|
|
|
y = rb_inspect(y);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
y = rb_obj_class(y);
|
|
|
|
}
|
2014-01-15 12:16:37 +04:00
|
|
|
rb_raise(rb_eTypeError, "%"PRIsVALUE" can't be coerced into %"PRIsVALUE,
|
2015-01-13 15:07:14 +03:00
|
|
|
y, rb_obj_class(x));
|
2014-01-15 12:16:37 +04:00
|
|
|
}
|
|
|
|
|
2002-12-19 12:20:20 +03:00
|
|
|
static int
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
do_coerce(VALUE *x, VALUE *y, int err)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2017-04-25 14:42:20 +03:00
|
|
|
VALUE ary = rb_check_funcall(*y, id_coerce, 1, x);
|
|
|
|
if (ary == Qundef) {
|
2013-01-10 10:30:23 +04:00
|
|
|
if (err) {
|
2016-02-17 05:38:09 +03:00
|
|
|
coerce_failed(*x, *y);
|
2013-01-10 12:12:58 +04:00
|
|
|
}
|
|
|
|
return FALSE;
|
2013-01-10 10:30:23 +04:00
|
|
|
}
|
2017-04-25 14:42:20 +03:00
|
|
|
if (!err && NIL_P(ary)) {
|
2014-06-07 17:16:01 +04:00
|
|
|
return FALSE;
|
|
|
|
}
|
2011-09-29 15:07:45 +04:00
|
|
|
if (!RB_TYPE_P(ary, T_ARRAY) || RARRAY_LEN(ary) != 2) {
|
2017-04-25 14:42:20 +03:00
|
|
|
rb_raise(rb_eTypeError, "coerce must return [x, y]");
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2013-05-13 13:56:22 +04:00
|
|
|
*x = RARRAY_AREF(ary, 0);
|
|
|
|
*y = RARRAY_AREF(ary, 1);
|
2009-07-18 12:05:32 +04:00
|
|
|
return TRUE;
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
VALUE
|
2008-02-12 05:46:21 +03:00
|
|
|
rb_num_coerce_bin(VALUE x, VALUE y, ID func)
|
1999-01-20 07:59:39 +03:00
|
|
|
{
|
2009-07-18 12:05:32 +04:00
|
|
|
do_coerce(&x, &y, TRUE);
|
2008-02-12 05:46:21 +03:00
|
|
|
return rb_funcall(x, func, 1, y);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2002-12-19 12:20:20 +03:00
|
|
|
VALUE
|
2008-02-12 05:46:21 +03:00
|
|
|
rb_num_coerce_cmp(VALUE x, VALUE y, ID func)
|
2002-12-19 12:20:20 +03:00
|
|
|
{
|
2009-07-18 12:05:32 +04:00
|
|
|
if (do_coerce(&x, &y, FALSE))
|
2008-02-12 05:46:21 +03:00
|
|
|
return rb_funcall(x, func, 1, y);
|
2002-12-19 12:20:20 +03:00
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
2020-10-02 15:30:07 +03:00
|
|
|
static VALUE
|
|
|
|
ensure_cmp(VALUE c, VALUE x, VALUE y)
|
|
|
|
{
|
|
|
|
if (NIL_P(c)) rb_cmperr(x, y);
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
2003-07-31 12:42:44 +04:00
|
|
|
VALUE
|
2008-02-12 05:46:21 +03:00
|
|
|
rb_num_coerce_relop(VALUE x, VALUE y, ID func)
|
2003-05-08 07:56:12 +04:00
|
|
|
{
|
2020-10-02 15:30:07 +03:00
|
|
|
VALUE x0 = x, y0 = y;
|
2003-05-08 07:56:12 +04:00
|
|
|
|
2020-10-02 15:30:07 +03:00
|
|
|
if (!do_coerce(&x, &y, FALSE)) {
|
2003-05-08 07:56:12 +04:00
|
|
|
rb_cmperr(x0, y0);
|
2020-10-02 15:30:07 +03:00
|
|
|
UNREACHABLE_RETURN(Qnil);
|
2003-05-08 07:56:12 +04:00
|
|
|
}
|
2020-10-02 15:30:07 +03:00
|
|
|
return ensure_cmp(rb_funcall(x, func, 1, y), x0, y0);
|
2003-05-08 07:56:12 +04:00
|
|
|
}
|
|
|
|
|
2020-05-10 18:24:14 +03:00
|
|
|
NORETURN(static VALUE num_sadded(VALUE x, VALUE name));
|
|
|
|
|
2003-12-27 08:46:46 +03:00
|
|
|
/*
|
2017-05-06 10:17:41 +03:00
|
|
|
* :nodoc:
|
|
|
|
*
|
2013-07-15 22:27:23 +04:00
|
|
|
* Trap attempts to add methods to Numeric objects. Always raises a TypeError.
|
|
|
|
*
|
|
|
|
* Numerics should be values; singleton_methods should not be added to them.
|
2003-12-27 08:46:46 +03:00
|
|
|
*/
|
|
|
|
|
2003-12-01 16:16:09 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
num_sadded(VALUE x, VALUE name)
|
2003-12-01 16:16:09 +03:00
|
|
|
{
|
2009-08-27 13:31:11 +04:00
|
|
|
ID mid = rb_to_id(name);
|
* call_cfunc.ci, compile.c, compile.h, debug.h, eval.c,
eval_error.h, eval_jump.h, eval_load.c, eval_thread.c, gc.c,
insnhelper.h, insns.def, iseq.c, main.c, numeric.c, parse.y,
range.c, regenc.h, ruby.h, signal.c, thread.c, thread_win32.ci,
vm.c, vm.h, vm_dump.c, vm_evalbody.ci, yarvcore.c, yarvcore.h:
fixed indents and non-C90 comments.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11620 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-02-02 19:26:04 +03:00
|
|
|
/* ruby_frame = ruby_frame->prev; */ /* pop frame for "singleton_method_added" */
|
2009-08-27 13:31:11 +04:00
|
|
|
rb_remove_method_id(rb_singleton_class(x), mid);
|
2003-12-01 16:16:09 +03:00
|
|
|
rb_raise(rb_eTypeError,
|
2014-01-15 12:16:40 +04:00
|
|
|
"can't define singleton method \"%"PRIsVALUE"\" for %"PRIsVALUE,
|
|
|
|
rb_id2str(mid),
|
|
|
|
rb_obj_class(x));
|
2012-04-14 04:36:26 +04:00
|
|
|
|
2018-07-24 08:38:07 +03:00
|
|
|
UNREACHABLE_RETURN(Qnil);
|
2003-12-01 16:16:09 +03:00
|
|
|
}
|
|
|
|
|
2017-02-22 05:02:11 +03:00
|
|
|
#if 0
|
2013-07-15 22:27:23 +04:00
|
|
|
/*
|
2017-02-22 05:02:11 +03:00
|
|
|
* call-seq:
|
2021-10-19 02:35:06 +03:00
|
|
|
* clone(freeze: true) -> self
|
|
|
|
*
|
|
|
|
* Returns +self+.
|
|
|
|
*
|
|
|
|
* Raises an exception if the value for +freeze+ is neither +true+ nor +nil+.
|
|
|
|
*
|
|
|
|
* Related: Numeric#dup.
|
2013-07-15 22:27:23 +04:00
|
|
|
*
|
|
|
|
*/
|
1999-01-20 07:59:39 +03:00
|
|
|
static VALUE
|
2017-02-22 05:02:11 +03:00
|
|
|
num_clone(int argc, VALUE *argv, VALUE x)
|
1999-01-20 07:59:39 +03:00
|
|
|
{
|
2017-02-22 05:02:11 +03:00
|
|
|
return rb_immutable_obj_clone(argc, argv, x);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
# define num_clone rb_immutable_obj_clone
|
|
|
|
#endif
|
2012-04-14 04:36:26 +04:00
|
|
|
|
2017-02-22 05:02:11 +03:00
|
|
|
#if 0
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-10-19 02:35:06 +03:00
|
|
|
* dup -> self
|
|
|
|
*
|
|
|
|
* Returns +self+.
|
|
|
|
*
|
|
|
|
* Related: Numeric#clone.
|
2017-02-22 05:02:11 +03:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
static VALUE
|
|
|
|
num_dup(VALUE x)
|
|
|
|
{
|
|
|
|
return x;
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
2017-02-22 05:02:11 +03:00
|
|
|
#else
|
|
|
|
# define num_dup num_uplus
|
|
|
|
#endif
|
1999-01-20 07:59:39 +03:00
|
|
|
|
2003-12-27 08:46:46 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-10-19 20:00:22 +03:00
|
|
|
* +self -> self
|
2021-10-19 02:35:06 +03:00
|
|
|
*
|
|
|
|
* Returns +self+.
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2003-12-27 08:46:46 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
num_uplus(VALUE num)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
2009-08-17 02:28:48 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-10-19 02:35:06 +03:00
|
|
|
* i -> complex
|
|
|
|
*
|
|
|
|
* Returns <tt>Complex(0, self)</tt>:
|
2009-08-17 02:28:48 +04:00
|
|
|
*
|
2021-10-19 02:35:06 +03:00
|
|
|
* 2.i # => (0+2i)
|
|
|
|
* -2.i # => (0-2i)
|
|
|
|
* 2.0.i # => (0+2.0i)
|
|
|
|
* Rational(1, 2).i # => (0+(1/2)*i)
|
2021-10-19 20:00:22 +03:00
|
|
|
* Complex(3, 4).i # Raises NoMethodError.
|
2017-05-06 10:17:41 +03:00
|
|
|
*
|
2009-08-17 02:28:48 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
num_imaginary(VALUE num)
|
|
|
|
{
|
|
|
|
return rb_complex_new(INT2FIX(0), num);
|
|
|
|
}
|
|
|
|
|
2003-12-27 08:46:46 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-10-19 20:00:22 +03:00
|
|
|
* -self -> numeric
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2017-05-06 10:17:41 +03:00
|
|
|
* Unary Minus---Returns the receiver, negated.
|
2003-12-27 08:46:46 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
num_uminus(VALUE num)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
1999-01-20 07:59:39 +03:00
|
|
|
VALUE zero;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
zero = INT2FIX(0);
|
2009-07-18 12:05:32 +04:00
|
|
|
do_coerce(&zero, &num, TRUE);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2016-08-13 17:08:03 +03:00
|
|
|
return num_funcall1(zero, '-', num);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2003-12-27 08:46:46 +03:00
|
|
|
/*
|
2008-04-02 18:13:53 +04:00
|
|
|
* call-seq:
|
2021-10-19 20:00:22 +03:00
|
|
|
* fdiv(other) -> float
|
|
|
|
*
|
|
|
|
* Returns the quotient <tt>self/other</tt> as a float,
|
|
|
|
* using method +/+ in the derived class of +self+.
|
|
|
|
* (\Numeric itself does not define method +/+.)
|
|
|
|
*
|
|
|
|
* Of the Core and Standard Library classes,
|
|
|
|
* only BigDecimal uses this implementation.
|
2008-04-02 18:13:53 +04:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
2013-06-06 05:04:11 +04:00
|
|
|
num_fdiv(VALUE x, VALUE y)
|
2008-04-02 18:13:53 +04:00
|
|
|
{
|
2013-06-06 05:04:11 +04:00
|
|
|
return rb_funcall(rb_Float(x), '/', 1, y);
|
2008-04-02 18:13:53 +04:00
|
|
|
}
|
2003-12-27 08:46:46 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-10-19 20:00:22 +03:00
|
|
|
* div(other) -> integer
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-10-19 20:00:22 +03:00
|
|
|
* Returns the quotient <tt>self/other</tt> as an integer (via +floor+),
|
|
|
|
* using method +/+ in the derived class of +self+.
|
|
|
|
* (\Numeric itself does not define method +/+.)
|
2009-06-19 17:37:04 +04:00
|
|
|
*
|
2021-10-19 20:00:22 +03:00
|
|
|
* Of the Core and Standard Library classes,
|
2022-05-28 00:04:02 +03:00
|
|
|
* Only Float and Rational use this implementation.
|
2009-06-19 17:37:04 +04:00
|
|
|
*
|
2003-12-27 08:46:46 +03:00
|
|
|
*/
|
|
|
|
|
2001-07-31 10:24:45 +04:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
num_div(VALUE x, VALUE y)
|
2001-07-31 10:24:45 +04:00
|
|
|
{
|
2008-05-27 16:51:28 +04:00
|
|
|
if (rb_equal(INT2FIX(0), y)) rb_num_zerodiv();
|
2016-08-13 17:08:03 +03:00
|
|
|
return rb_funcall(num_funcall1(x, '/', y), rb_intern("floor"), 0);
|
2001-07-31 10:24:45 +04:00
|
|
|
}
|
|
|
|
|
2009-06-20 16:37:13 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-10-12 16:06:05 +03:00
|
|
|
* self % other -> real_numeric
|
2009-06-20 16:37:13 +04:00
|
|
|
*
|
2021-10-12 16:06:05 +03:00
|
|
|
* Returns +self+ modulo +other+ as a real number.
|
2009-06-20 16:37:13 +04:00
|
|
|
*
|
2021-10-12 16:06:05 +03:00
|
|
|
* Of the Core and Standard Library classes,
|
|
|
|
* only Rational uses this implementation.
|
|
|
|
*
|
|
|
|
* For \Rational +r+ and real number +n+, these expressions are equivalent:
|
|
|
|
*
|
2022-05-27 14:18:54 +03:00
|
|
|
* r % n
|
|
|
|
* r-n*(r/n).floor
|
|
|
|
* r.divmod(n)[1]
|
2009-06-20 16:37:13 +04:00
|
|
|
*
|
2013-07-15 22:27:23 +04:00
|
|
|
* See Numeric#divmod.
|
2021-10-12 16:06:05 +03:00
|
|
|
*
|
|
|
|
* Examples:
|
|
|
|
*
|
|
|
|
* r = Rational(1, 2) # => (1/2)
|
|
|
|
* r2 = Rational(2, 3) # => (2/3)
|
|
|
|
* r % r2 # => (1/2)
|
|
|
|
* r % 2 # => (1/2)
|
|
|
|
* r % 2.0 # => 0.5
|
|
|
|
*
|
|
|
|
* r = Rational(301,100) # => (301/100)
|
|
|
|
* r2 = Rational(7,5) # => (7/5)
|
|
|
|
* r % r2 # => (21/100)
|
|
|
|
* r % -r2 # => (-119/100)
|
|
|
|
* (-r) % r2 # => (119/100)
|
|
|
|
* (-r) %-r2 # => (-21/100)
|
|
|
|
*
|
|
|
|
* Numeric#modulo is an alias for Numeric#%.
|
|
|
|
*
|
2009-06-20 16:37:13 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
num_modulo(VALUE x, VALUE y)
|
|
|
|
{
|
2016-08-13 17:08:03 +03:00
|
|
|
VALUE q = num_funcall1(x, id_div, y);
|
2009-06-20 16:37:13 +04:00
|
|
|
return rb_funcall(x, '-', 1,
|
2016-08-13 17:08:03 +03:00
|
|
|
rb_funcall(y, '*', 1, q));
|
2009-06-20 16:37:13 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-10-16 00:20:52 +03:00
|
|
|
* remainder(other) -> real_number
|
2009-06-20 16:37:13 +04:00
|
|
|
*
|
2021-10-16 00:20:52 +03:00
|
|
|
* Returns the remainder after dividing +self+ by +other+.
|
|
|
|
*
|
|
|
|
* Of the Core and Standard Library classes,
|
|
|
|
* only Float and Rational use this implementation.
|
|
|
|
*
|
|
|
|
* Examples:
|
|
|
|
*
|
|
|
|
* 11.0.remainder(4) # => 3.0
|
|
|
|
* 11.0.remainder(-4) # => 3.0
|
|
|
|
* -11.0.remainder(4) # => -3.0
|
|
|
|
* -11.0.remainder(-4) # => -3.0
|
|
|
|
*
|
|
|
|
* 12.0.remainder(4) # => 0.0
|
|
|
|
* 12.0.remainder(-4) # => 0.0
|
|
|
|
* -12.0.remainder(4) # => -0.0
|
|
|
|
* -12.0.remainder(-4) # => -0.0
|
|
|
|
*
|
|
|
|
* 13.0.remainder(4.0) # => 1.0
|
|
|
|
* 13.0.remainder(Rational(4, 1)) # => 1.0
|
|
|
|
*
|
|
|
|
* Rational(13, 1).remainder(4) # => (1/1)
|
|
|
|
* Rational(13, 1).remainder(-4) # => (1/1)
|
|
|
|
* Rational(-13, 1).remainder(4) # => (-1/1)
|
|
|
|
* Rational(-13, 1).remainder(-4) # => (-1/1)
|
2009-06-20 16:37:13 +04:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
num_remainder(VALUE x, VALUE y)
|
|
|
|
{
|
2016-08-13 17:08:03 +03:00
|
|
|
VALUE z = num_funcall1(x, '%', y);
|
2009-06-20 16:37:13 +04:00
|
|
|
|
|
|
|
if ((!rb_equal(z, INT2FIX(0))) &&
|
2017-12-04 05:35:40 +03:00
|
|
|
((rb_num_negative_int_p(x) &&
|
|
|
|
rb_num_positive_int_p(y)) ||
|
|
|
|
(rb_num_positive_int_p(x) &&
|
|
|
|
rb_num_negative_int_p(y)))) {
|
2021-09-11 03:56:59 +03:00
|
|
|
if (RB_FLOAT_TYPE_P(y)) {
|
2021-03-11 00:15:50 +03:00
|
|
|
if (isinf(RFLOAT_VALUE(y))) {
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
}
|
2009-06-20 16:37:13 +04:00
|
|
|
return rb_funcall(z, '-', 1, y);
|
|
|
|
}
|
|
|
|
return z;
|
|
|
|
}
|
|
|
|
|
2003-12-27 08:46:46 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-10-15 20:51:37 +03:00
|
|
|
* divmod(other) -> array
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-10-15 20:51:37 +03:00
|
|
|
* Returns a 2-element array <tt>[q, r]</tt>, where
|
2013-07-15 22:27:23 +04:00
|
|
|
*
|
2021-10-15 20:51:37 +03:00
|
|
|
* q = (self/other).floor # Quotient
|
|
|
|
* r = self % other # Remainder
|
2003-12-27 08:46:46 +03:00
|
|
|
*
|
2021-10-15 20:51:37 +03:00
|
|
|
* Of the Core and Standard Library classes,
|
|
|
|
* only Rational uses this implementation.
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-10-15 20:51:37 +03:00
|
|
|
* Examples:
|
2003-12-27 08:46:46 +03:00
|
|
|
*
|
2021-10-15 20:51:37 +03:00
|
|
|
* Rational(11, 1).divmod(4) # => [2, (3/1)]
|
|
|
|
* Rational(11, 1).divmod(-4) # => [-3, (-1/1)]
|
|
|
|
* Rational(-11, 1).divmod(4) # => [-3, (1/1)]
|
|
|
|
* Rational(-11, 1).divmod(-4) # => [2, (-3/1)]
|
2003-12-27 08:46:46 +03:00
|
|
|
*
|
2021-10-15 20:51:37 +03:00
|
|
|
* Rational(12, 1).divmod(4) # => [3, (0/1)]
|
|
|
|
* Rational(12, 1).divmod(-4) # => [-3, (0/1)]
|
|
|
|
* Rational(-12, 1).divmod(4) # => [-3, (0/1)]
|
|
|
|
* Rational(-12, 1).divmod(-4) # => [3, (0/1)]
|
2008-03-09 04:04:46 +03:00
|
|
|
*
|
2021-10-15 20:51:37 +03:00
|
|
|
* Rational(13, 1).divmod(4.0) # => [3, 1.0]
|
|
|
|
* Rational(13, 1).divmod(Rational(4, 11)) # => [35, (3/11)]
|
2003-12-27 08:46:46 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
num_divmod(VALUE x, VALUE y)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2009-06-20 16:37:13 +04:00
|
|
|
return rb_assoc_new(num_div(x, y), num_modulo(x, y));
|
2000-07-06 11:21:26 +04:00
|
|
|
}
|
|
|
|
|
2003-12-27 08:46:46 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-10-19 20:00:22 +03:00
|
|
|
* abs -> numeric
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-10-19 20:00:22 +03:00
|
|
|
* Returns the absolute value of +self+.
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-10-19 20:00:22 +03:00
|
|
|
* 12.abs #=> 12
|
|
|
|
* (-34.56).abs #=> 34.56
|
|
|
|
* -34.56.abs #=> 34.56
|
2013-07-15 22:27:23 +04:00
|
|
|
*
|
2017-05-06 10:17:41 +03:00
|
|
|
* Numeric#magnitude is an alias for Numeric#abs.
|
2021-10-19 20:00:22 +03:00
|
|
|
*
|
2003-12-27 08:46:46 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
num_abs(VALUE num)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2017-12-04 05:35:40 +03:00
|
|
|
if (rb_num_negative_int_p(num)) {
|
2016-08-13 17:08:03 +03:00
|
|
|
return num_funcall0(num, idUMinus);
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
|
|
|
return num;
|
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2003-12-27 08:46:46 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-10-19 20:00:22 +03:00
|
|
|
* zero? -> true or false
|
|
|
|
*
|
|
|
|
* Returns +true+ if +zero+ has a zero value, +false+ otherwise.
|
|
|
|
*
|
|
|
|
* Of the Core and Standard Library classes,
|
|
|
|
* only Rational and Complex use this implementation.
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2003-12-27 08:46:46 +03:00
|
|
|
*/
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
num_zero_p(VALUE num)
|
2020-06-21 00:55:09 +03:00
|
|
|
{
|
2021-05-24 03:41:03 +03:00
|
|
|
return rb_equal(num, INT2FIX(0));
|
2020-06-21 00:55:09 +03:00
|
|
|
}
|
|
|
|
|
2022-01-01 10:06:07 +03:00
|
|
|
static bool
|
2020-06-21 00:55:09 +03:00
|
|
|
int_zero_p(VALUE num)
|
1999-01-20 07:59:39 +03:00
|
|
|
{
|
2016-03-17 20:11:42 +03:00
|
|
|
if (FIXNUM_P(num)) {
|
2022-01-01 10:06:07 +03:00
|
|
|
return FIXNUM_ZERO_P(num);
|
2016-03-17 20:11:42 +03:00
|
|
|
}
|
2021-09-15 02:11:05 +03:00
|
|
|
assert(RB_BIGNUM_TYPE_P(num));
|
2022-01-01 10:06:07 +03:00
|
|
|
return rb_bigzero_p(num);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2020-07-10 05:49:50 +03:00
|
|
|
VALUE
|
|
|
|
rb_int_zero_p(VALUE num)
|
|
|
|
{
|
2022-01-01 10:06:07 +03:00
|
|
|
return RBOOL(int_zero_p(num));
|
2020-07-10 05:49:50 +03:00
|
|
|
}
|
|
|
|
|
2003-12-27 08:46:46 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-10-19 20:00:22 +03:00
|
|
|
* nonzero? -> self or nil
|
|
|
|
*
|
|
|
|
* Returns +self+ if +self+ is not a zero value, +nil+ otherwise;
|
|
|
|
* uses method <tt>zero?</tt> for the evaluation.
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-10-19 20:00:22 +03:00
|
|
|
* The returned +self+ allows the method to be chained:
|
2013-07-15 22:27:23 +04:00
|
|
|
*
|
2021-10-19 20:00:22 +03:00
|
|
|
* a = %w[z Bb bB bb BB a aA Aa AA A]
|
|
|
|
* a.sort {|a, b| (a.downcase <=> b.downcase).nonzero? || a <=> b }
|
|
|
|
* # => ["A", "a", "AA", "Aa", "aA", "BB", "Bb", "bB", "bb", "z"]
|
|
|
|
*
|
|
|
|
* Of the Core and Standard Library classes,
|
|
|
|
* Integer, Float, Rational, and Complex use this implementation.
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2003-12-27 08:46:46 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
num_nonzero_p(VALUE num)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2016-08-13 17:08:03 +03:00
|
|
|
if (RTEST(num_funcall0(num, rb_intern("zero?")))) {
|
1999-08-13 09:45:20 +04:00
|
|
|
return Qnil;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
2003-12-27 08:46:46 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-10-19 20:00:22 +03:00
|
|
|
* to_int -> integer
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-10-19 20:00:22 +03:00
|
|
|
* Returns +self+ as an integer;
|
|
|
|
* converts using method +to_i+ in the derived class.
|
|
|
|
*
|
|
|
|
* Of the Core and Standard Library classes,
|
|
|
|
* only Rational and Complex use this implementation.
|
|
|
|
*
|
|
|
|
* Examples:
|
|
|
|
*
|
|
|
|
* Rational(1, 2).to_int # => 0
|
|
|
|
* Rational(2, 1).to_int # => 2
|
|
|
|
* Complex(2, 0).to_int # => 2
|
|
|
|
* Complex(2, 1) # Raises RangeError (non-zero imaginary part)
|
2013-02-22 06:01:28 +04:00
|
|
|
*
|
2003-12-27 08:46:46 +03:00
|
|
|
*/
|
|
|
|
|
2002-07-29 10:14:10 +04:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
num_to_int(VALUE num)
|
2002-07-29 10:14:10 +04:00
|
|
|
{
|
2016-08-13 17:08:03 +03:00
|
|
|
return num_funcall0(num, id_to_i);
|
2002-07-29 10:14:10 +04:00
|
|
|
}
|
|
|
|
|
2015-05-17 09:01:47 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-10-19 20:00:22 +03:00
|
|
|
* positive? -> true or false
|
|
|
|
*
|
|
|
|
* Returns +true+ if +self+ is greater than 0, +false+ otherwise.
|
2015-05-17 09:01:47 +03:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
num_positive_p(VALUE num)
|
|
|
|
{
|
|
|
|
const ID mid = '>';
|
|
|
|
|
|
|
|
if (FIXNUM_P(num)) {
|
Use Integer instead of Fixnum and Bignum.
* object.c, numeric.c, enum.c, ext/-test-/bignum/mul.c,
lib/rexml/quickpath.rb, lib/rexml/text.rb, lib/rexml/xpath_parser.rb,
lib/rubygems/specification.rb, lib/uri/generic.rb,
bootstraptest/test_eval.rb, basictest/test.rb,
test/-ext-/bignum/test_big2str.rb, test/-ext-/bignum/test_div.rb,
test/-ext-/bignum/test_mul.rb, test/-ext-/bignum/test_str2big.rb,
test/csv/test_data_converters.rb, test/date/test_date.rb,
test/json/test_json_generate.rb, test/minitest/test_minitest_mock.rb,
test/openssl/test_cipher.rb, test/rexml/test_jaxen.rb,
test/ruby/test_array.rb, test/ruby/test_basicinstructions.rb,
test/ruby/test_bignum.rb, test/ruby/test_case.rb,
test/ruby/test_class.rb, test/ruby/test_complex.rb,
test/ruby/test_enum.rb, test/ruby/test_eval.rb,
test/ruby/test_iseq.rb, test/ruby/test_literal.rb,
test/ruby/test_math.rb, test/ruby/test_module.rb,
test/ruby/test_numeric.rb, test/ruby/test_range.rb,
test/ruby/test_rational.rb, test/ruby/test_refinement.rb,
test/ruby/test_rubyvm.rb, test/ruby/test_struct.rb,
test/ruby/test_variable.rb, test/rubygems/test_gem_specification.rb,
test/thread/test_queue.rb: Use Integer instead of Fixnum and Bignum.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@55029 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2016-05-17 16:15:57 +03:00
|
|
|
if (method_basic_p(rb_cInteger))
|
2021-08-02 06:06:44 +03:00
|
|
|
return RBOOL((SIGNED_VALUE)num > (SIGNED_VALUE)INT2FIX(0));
|
2015-05-17 09:01:47 +03:00
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(num)) {
|
Use Integer instead of Fixnum and Bignum.
* object.c, numeric.c, enum.c, ext/-test-/bignum/mul.c,
lib/rexml/quickpath.rb, lib/rexml/text.rb, lib/rexml/xpath_parser.rb,
lib/rubygems/specification.rb, lib/uri/generic.rb,
bootstraptest/test_eval.rb, basictest/test.rb,
test/-ext-/bignum/test_big2str.rb, test/-ext-/bignum/test_div.rb,
test/-ext-/bignum/test_mul.rb, test/-ext-/bignum/test_str2big.rb,
test/csv/test_data_converters.rb, test/date/test_date.rb,
test/json/test_json_generate.rb, test/minitest/test_minitest_mock.rb,
test/openssl/test_cipher.rb, test/rexml/test_jaxen.rb,
test/ruby/test_array.rb, test/ruby/test_basicinstructions.rb,
test/ruby/test_bignum.rb, test/ruby/test_case.rb,
test/ruby/test_class.rb, test/ruby/test_complex.rb,
test/ruby/test_enum.rb, test/ruby/test_eval.rb,
test/ruby/test_iseq.rb, test/ruby/test_literal.rb,
test/ruby/test_math.rb, test/ruby/test_module.rb,
test/ruby/test_numeric.rb, test/ruby/test_range.rb,
test/ruby/test_rational.rb, test/ruby/test_refinement.rb,
test/ruby/test_rubyvm.rb, test/ruby/test_struct.rb,
test/ruby/test_variable.rb, test/rubygems/test_gem_specification.rb,
test/thread/test_queue.rb: Use Integer instead of Fixnum and Bignum.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@55029 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2016-05-17 16:15:57 +03:00
|
|
|
if (method_basic_p(rb_cInteger))
|
2021-08-02 06:06:44 +03:00
|
|
|
return RBOOL(BIGNUM_POSITIVE_P(num) && !rb_bigzero_p(num));
|
2015-05-17 09:01:47 +03:00
|
|
|
}
|
2017-12-04 05:35:40 +03:00
|
|
|
return rb_num_compare_with_zero(num, mid);
|
2015-05-17 09:01:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-10-19 20:00:22 +03:00
|
|
|
* negative? -> true or false
|
|
|
|
*
|
|
|
|
* Returns +true+ if +self+ is less than 0, +false+ otherwise.
|
2015-05-17 09:01:47 +03:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
num_negative_p(VALUE num)
|
|
|
|
{
|
2021-08-02 06:06:44 +03:00
|
|
|
return RBOOL(rb_num_negative_int_p(num));
|
2015-05-17 09:01:47 +03:00
|
|
|
}
|
|
|
|
|
2003-12-23 19:21:17 +03:00
|
|
|
|
|
|
|
/********************************************************************
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-11-27 22:07:37 +03:00
|
|
|
* Document-class: Float
|
2003-12-23 19:21:17 +03:00
|
|
|
*
|
2021-11-27 22:07:37 +03:00
|
|
|
* A \Float object represents a sometimes-inexact real number using the native
|
2013-07-15 22:27:23 +04:00
|
|
|
* architecture's double-precision floating point representation.
|
2010-08-29 04:42:05 +04:00
|
|
|
*
|
2013-08-10 09:02:56 +04:00
|
|
|
* Floating point has a different arithmetic and is an inexact number.
|
2017-05-06 10:17:41 +03:00
|
|
|
* So you should know its esoteric system. See following:
|
2011-05-15 15:55:52 +04:00
|
|
|
*
|
2020-08-04 16:17:31 +03:00
|
|
|
* - https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
|
2019-05-04 00:23:25 +03:00
|
|
|
* - https://github.com/rdp/ruby_tutorials_core/wiki/Ruby-Talk-FAQ#floats_imprecise
|
2020-07-28 13:51:07 +03:00
|
|
|
* - https://en.wikipedia.org/wiki/Floating_point#Accuracy_problems
|
2021-11-25 02:44:27 +03:00
|
|
|
*
|
2021-11-27 22:07:37 +03:00
|
|
|
* You can create a \Float object explicitly with:
|
|
|
|
*
|
2022-02-07 19:26:39 +03:00
|
|
|
* - A {floating-point literal}[rdoc-ref:syntax/literals.rdoc@Float+Literals].
|
2021-12-03 16:12:28 +03:00
|
|
|
*
|
|
|
|
* You can convert certain objects to Floats with:
|
|
|
|
*
|
2022-02-07 19:18:56 +03:00
|
|
|
* - \Method #Float.
|
2021-11-27 22:07:37 +03:00
|
|
|
*
|
2021-11-25 02:44:27 +03:00
|
|
|
* == What's Here
|
|
|
|
*
|
|
|
|
* First, what's elsewhere. \Class \Float:
|
|
|
|
*
|
2022-02-06 18:30:11 +03:00
|
|
|
* - Inherits from {class Numeric}[rdoc-ref:Numeric@What-27s+Here].
|
2021-11-25 02:44:27 +03:00
|
|
|
*
|
|
|
|
* Here, class \Float provides methods for:
|
|
|
|
*
|
2022-02-06 18:37:06 +03:00
|
|
|
* - {Querying}[rdoc-ref:Float@Querying]
|
|
|
|
* - {Comparing}[rdoc-ref:Float@Comparing]
|
|
|
|
* - {Converting}[rdoc-ref:Float@Converting]
|
2021-11-25 02:44:27 +03:00
|
|
|
*
|
|
|
|
* === Querying
|
|
|
|
*
|
2022-03-25 23:43:46 +03:00
|
|
|
* - #finite?: Returns whether +self+ is finite.
|
|
|
|
* - #hash: Returns the integer hash code for +self+.
|
|
|
|
* - #infinite?: Returns whether +self+ is infinite.
|
|
|
|
* - #nan?: Returns whether +self+ is a NaN (not-a-number).
|
2021-11-25 02:44:27 +03:00
|
|
|
*
|
|
|
|
* === Comparing
|
|
|
|
*
|
2022-03-26 15:07:06 +03:00
|
|
|
* - #<: Returns whether +self+ is less than the given value.
|
|
|
|
* - #<=: Returns whether +self+ is less than or equal to the given value.
|
|
|
|
* - #<=>: Returns a number indicating whether +self+ is less than, equal
|
2022-03-25 23:43:46 +03:00
|
|
|
* to, or greater than the given value.
|
|
|
|
* - #== (aliased as #=== and #eql?): Returns whether +self+ is equal to
|
|
|
|
* the given value.
|
2022-03-26 15:07:06 +03:00
|
|
|
* - #>: Returns whether +self+ is greater than the given value.
|
|
|
|
* - #>=: Returns whether +self+ is greater than or equal to the given value.
|
2021-11-25 02:44:27 +03:00
|
|
|
*
|
|
|
|
* === Converting
|
|
|
|
*
|
2022-03-25 23:43:46 +03:00
|
|
|
* - #% (aliased as #modulo): Returns +self+ modulo the given value.
|
|
|
|
* - #*: Returns the product of +self+ and the given value.
|
|
|
|
* - #**: Returns the value of +self+ raised to the power of the given value.
|
|
|
|
* - #+: Returns the sum of +self+ and the given value.
|
|
|
|
* - #-: Returns the difference of +self+ and the given value.
|
2022-03-26 15:07:06 +03:00
|
|
|
* - #/: Returns the quotient of +self+ and the given value.
|
2022-03-25 23:43:46 +03:00
|
|
|
* - #ceil: Returns the smallest number greater than or equal to +self+.
|
|
|
|
* - #coerce: Returns a 2-element array containing the given value converted to a \Float
|
|
|
|
and +self+
|
|
|
|
* - #divmod: Returns a 2-element array containing the quotient and remainder
|
|
|
|
* results of dividing +self+ by the given value.
|
|
|
|
* - #fdiv: Returns the Float result of dividing +self+ by the given value.
|
|
|
|
* - #floor: Returns the greatest number smaller than or equal to +self+.
|
|
|
|
* - #next_float: Returns the next-larger representable \Float.
|
|
|
|
* - #prev_float: Returns the next-smaller representable \Float.
|
|
|
|
* - #quo: Returns the quotient from dividing +self+ by the given value.
|
|
|
|
* - #round: Returns +self+ rounded to the nearest value, to a given precision.
|
|
|
|
* - #to_i (aliased as #to_int): Returns +self+ truncated to an Integer.
|
|
|
|
* - #to_s (aliased as #inspect): Returns a string containing the place-value
|
|
|
|
* representation of +self+ in the given radix.
|
|
|
|
* - #truncate: Returns +self+ truncated to a given precision.
|
2021-11-25 02:44:27 +03:00
|
|
|
*
|
2003-12-23 19:21:17 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE
|
2012-08-23 11:22:40 +04:00
|
|
|
rb_float_new_in_heap(double d)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
* gc.c: support RGENGC. [ruby-trunk - Feature #8339]
See this ticet about RGENGC.
* gc.c: Add several flags:
* RGENGC_DEBUG: if >0, then prints debug information.
* RGENGC_CHECK_MODE: if >0, add assertions.
* RGENGC_PROFILE: if >0, add profiling features.
check GC.stat and GC::Profiler.
* include/ruby/ruby.h: disable RGENGC by default (USE_RGENGC == 0).
* array.c: add write barriers for T_ARRAY and generate sunny objects.
* include/ruby/ruby.h (RARRAY_PTR_USE): added. Use this macro if
you want to access raw pointers. If you modify the contents which
pointer pointed, then you need to care write barrier.
* bignum.c, marshal.c, random.c: generate T_BIGNUM sunny objects.
* complex.c, include/ruby/ruby.h: add write barriers for T_COMPLEX
and generate sunny objects.
* rational.c (nurat_s_new_internal), include/ruby/ruby.h: add write
barriers for T_RATIONAL and generate sunny objects.
* internal.h: add write barriers for RBasic::klass.
* numeric.c (rb_float_new_in_heap): generate sunny T_FLOAT objects.
* object.c (rb_class_allocate_instance), range.c:
generate sunny T_OBJECT objects.
* string.c: add write barriers for T_STRING and generate sunny objects.
* variable.c: add write barriers for ivars.
* vm_insnhelper.c (vm_setivar): ditto.
* include/ruby/ruby.h, debug.c: use two flags
FL_WB_PROTECTED and FL_OLDGEN.
* node.h (NODE_FL_CREF_PUSHED_BY_EVAL, NODE_FL_CREF_OMOD_SHARED):
move flag bits.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40703 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-05-13 22:07:47 +04:00
|
|
|
NEWOBJ_OF(flt, struct RFloat, rb_cFloat, T_FLOAT | (RGENGC_WB_PROTECTED_FLOAT ? FL_WB_PROTECTED : 0));
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2021-10-26 18:50:41 +03:00
|
|
|
#if SIZEOF_DOUBLE <= SIZEOF_VALUE
|
2007-11-20 14:35:12 +03:00
|
|
|
flt->float_value = d;
|
2021-10-26 14:14:19 +03:00
|
|
|
#else
|
2021-10-26 17:39:43 +03:00
|
|
|
union {
|
|
|
|
double d;
|
|
|
|
rb_float_value_type v;
|
|
|
|
} u = {d};
|
|
|
|
flt->float_value = u.v;
|
2021-10-26 14:14:19 +03:00
|
|
|
#endif
|
2020-04-08 07:28:13 +03:00
|
|
|
OBJ_FREEZE((VALUE)flt);
|
1998-01-16 15:13:05 +03:00
|
|
|
return (VALUE)flt;
|
|
|
|
}
|
|
|
|
|
2003-12-23 19:21:17 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-19 21:16:16 +03:00
|
|
|
* to_s -> string
|
|
|
|
*
|
|
|
|
* Returns a string containing a representation of +self+;
|
|
|
|
* depending of the value of +self+, the string representation
|
|
|
|
* may contain:
|
|
|
|
*
|
|
|
|
* - A fixed-point number.
|
|
|
|
* - A number in "scientific notation" (containing an exponent).
|
|
|
|
* - 'Infinity'.
|
|
|
|
* - '-Infinity'.
|
|
|
|
* - 'NaN' (indicating not-a-number).
|
|
|
|
*
|
|
|
|
* 3.14.to_s # => "3.14"
|
|
|
|
* (10.1**50).to_s # => "1.644631821843879e+50"
|
|
|
|
* (10.1**500).to_s # => "Infinity"
|
|
|
|
* (-10.1**500).to_s # => "-Infinity"
|
|
|
|
* (0.0/0.0).to_s # => "NaN"
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2003-12-23 19:21:17 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
flo_to_s(VALUE flt)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2009-03-05 12:36:39 +03:00
|
|
|
enum {decimal_mant = DBL_MANT_DIG-DBL_DIG};
|
2009-04-06 20:08:23 +04:00
|
|
|
enum {float_dig = DBL_DIG+1};
|
2009-03-05 12:36:39 +03:00
|
|
|
char buf[float_dig + (decimal_mant + CHAR_BIT - 1) / CHAR_BIT + 10];
|
* include/ruby/ruby.h: introduce 2 macros:
RFLOAT_VALUE(v), DOUBLE2NUM(dbl).
Rename RFloat#value -> RFloat#double_value.
Do not touch RFloat#double_value directly.
* bignum.c, insns.def, marshal.c, math.c, numeric.c, object.c,
pack.c, parse.y, process.c, random.c, sprintf.c, string.c,
time.c: apply above changes.
* ext/dl/mkcallback.rb, ext/json/ext/generator/generator.c:
ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13913 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-11-13 19:00:53 +03:00
|
|
|
double value = RFLOAT_VALUE(flt);
|
2010-05-21 07:26:00 +04:00
|
|
|
VALUE s;
|
|
|
|
char *p, *e;
|
|
|
|
int sign, decpt, digs;
|
1999-08-13 09:45:20 +04:00
|
|
|
|
2016-02-24 05:20:45 +03:00
|
|
|
if (isinf(value)) {
|
|
|
|
static const char minf[] = "-Infinity";
|
|
|
|
const int pos = (value > 0); /* skip "-" */
|
|
|
|
return rb_usascii_str_new(minf+pos, strlen(minf)-pos);
|
|
|
|
}
|
2010-01-14 07:07:00 +03:00
|
|
|
else if (isnan(value))
|
* string.c (rb_str_usascii_new{,2}: defined.
(rb_str_new): set US-ASCII and ENC_CODERANGE_7BIT when empty
string.
* encoding.c (rb_usascii_encoding, rb_usascii_encindex): defined.
(rb_enc_inspect, enc_name, rb_locale_charmap, rb_enc_name_list_i):
use rb_str_ascii_new.
* array.c (recursive_join, inspect_ary): ditto.
* object.c (nil_to_s, nil_inspect, true_to_s, false_to_s,
rb_mod_to_s): ditto.
* hash.c (inspect_hash, rb_hash_inspect, rb_f_getenv, env_fetch,
env_clear, env_to_s, env_inspect): ditto.
* numeric.c (flo_to_s, int_chr, rb_fix2str): ditto.
* bignum.c (rb_big2str): ditto.
* file.c (rb_file_ftype, rb_file_s_dirname, rb_file_s_extname,
file_inspect_join, Init_file): ditto.
* test/ruby/test_ruby_m17n.rb: add checks for encoding of string.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@15244 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-01-25 19:40:02 +03:00
|
|
|
return rb_usascii_str_new2("NaN");
|
2004-05-07 12:44:24 +04:00
|
|
|
|
2010-05-12 05:57:08 +04:00
|
|
|
p = ruby_dtoa(value, 0, 0, &decpt, &sign, &e);
|
2010-05-21 07:26:00 +04:00
|
|
|
s = sign ? rb_usascii_str_new_cstr("-") : rb_usascii_str_new(0, 0);
|
|
|
|
if ((digs = (int)(e - p)) >= (int)sizeof(buf)) digs = (int)sizeof(buf) - 1;
|
|
|
|
memcpy(buf, p, digs);
|
|
|
|
xfree(p);
|
|
|
|
if (decpt > 0) {
|
2010-05-13 08:30:07 +04:00
|
|
|
if (decpt < digs) {
|
2010-05-21 07:26:00 +04:00
|
|
|
memmove(buf + decpt + 1, buf + decpt, digs - decpt);
|
|
|
|
buf[decpt] = '.';
|
|
|
|
rb_str_cat(s, buf, digs + 1);
|
|
|
|
}
|
2012-07-16 17:52:10 +04:00
|
|
|
else if (decpt <= DBL_DIG) {
|
2010-05-21 07:26:00 +04:00
|
|
|
long len;
|
|
|
|
char *ptr;
|
|
|
|
rb_str_cat(s, buf, digs);
|
|
|
|
rb_str_resize(s, (len = RSTRING_LEN(s)) + decpt - digs + 2);
|
|
|
|
ptr = RSTRING_PTR(s) + len;
|
|
|
|
if (decpt > digs) {
|
|
|
|
memset(ptr, '0', decpt - digs);
|
|
|
|
ptr += decpt - digs;
|
|
|
|
}
|
|
|
|
memcpy(ptr, ".0", 2);
|
2010-05-13 08:30:07 +04:00
|
|
|
}
|
|
|
|
else {
|
2010-05-21 07:26:00 +04:00
|
|
|
goto exp;
|
2010-05-13 08:30:07 +04:00
|
|
|
}
|
2010-05-21 07:26:00 +04:00
|
|
|
}
|
|
|
|
else if (decpt > -4) {
|
|
|
|
long len;
|
|
|
|
char *ptr;
|
|
|
|
rb_str_cat(s, "0.", 2);
|
|
|
|
rb_str_resize(s, (len = RSTRING_LEN(s)) - decpt + digs);
|
|
|
|
ptr = RSTRING_PTR(s);
|
|
|
|
memset(ptr += len, '0', -decpt);
|
|
|
|
memcpy(ptr -= decpt, buf, digs);
|
2004-05-07 12:44:24 +04:00
|
|
|
}
|
2010-05-12 05:57:08 +04:00
|
|
|
else {
|
2020-06-16 03:42:18 +03:00
|
|
|
goto exp;
|
|
|
|
}
|
|
|
|
return s;
|
|
|
|
|
|
|
|
exp:
|
|
|
|
if (digs > 1) {
|
|
|
|
memmove(buf + 2, buf + 1, digs - 1);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
buf[2] = '0';
|
|
|
|
digs++;
|
2004-05-17 11:14:45 +04:00
|
|
|
}
|
2020-06-16 03:42:18 +03:00
|
|
|
buf[1] = '.';
|
|
|
|
rb_str_cat(s, buf, digs + 1);
|
|
|
|
rb_str_catf(s, "e%+03d", decpt - 1);
|
2010-05-21 07:26:00 +04:00
|
|
|
return s;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2003-12-23 19:21:17 +03:00
|
|
|
/*
|
2011-05-13 14:27:10 +04:00
|
|
|
* call-seq:
|
2021-10-19 02:35:06 +03:00
|
|
|
* coerce(other) -> array
|
|
|
|
*
|
|
|
|
* Returns a 2-element array containing +other+ converted to a \Float
|
|
|
|
* and +self+:
|
|
|
|
*
|
|
|
|
* f = 3.14 # => 3.14
|
|
|
|
* f.coerce(2) # => [2.0, 3.14]
|
|
|
|
* f.coerce(2.0) # => [2.0, 3.14]
|
|
|
|
* f.coerce(Rational(1, 2)) # => [0.5, 3.14]
|
2021-11-19 21:16:16 +03:00
|
|
|
* f.coerce(Complex(1, 0)) # => [1.0, 3.14]
|
2011-05-13 14:27:10 +04:00
|
|
|
*
|
2021-10-19 02:35:06 +03:00
|
|
|
* Raises an exception if a type conversion fails.
|
2011-05-13 14:27:10 +04:00
|
|
|
*
|
2003-12-23 19:21:17 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
flo_coerce(VALUE x, VALUE y)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
1999-01-20 07:59:39 +03:00
|
|
|
return rb_assoc_new(rb_Float(y), x);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2021-01-19 01:52:07 +03:00
|
|
|
MJIT_FUNC_EXPORTED VALUE
|
2016-11-18 18:17:19 +03:00
|
|
|
rb_float_uminus(VALUE flt)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2008-09-05 22:24:21 +04:00
|
|
|
return DBL2NUM(-RFLOAT_VALUE(flt));
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2003-12-23 19:21:17 +03:00
|
|
|
/*
|
2021-11-19 21:16:16 +03:00
|
|
|
* call-seq:
|
2021-11-21 02:21:30 +03:00
|
|
|
* self + other -> numeric
|
2021-11-19 21:16:16 +03:00
|
|
|
*
|
|
|
|
* Returns a new \Float which is the sum of +self+ and +other+:
|
|
|
|
*
|
|
|
|
* f = 3.14
|
|
|
|
* f + 1 # => 4.140000000000001
|
|
|
|
* f + 1.0 # => 4.140000000000001
|
|
|
|
* f + Rational(1, 1) # => 4.140000000000001
|
|
|
|
* f + Complex(1, 0) # => (4.140000000000001+0i)
|
2003-12-23 19:21:17 +03:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2019-01-01 15:20:05 +03:00
|
|
|
VALUE
|
|
|
|
rb_float_plus(VALUE x, VALUE y)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2021-09-11 07:45:22 +03:00
|
|
|
if (FIXNUM_P(y)) {
|
2008-09-05 22:24:21 +04:00
|
|
|
return DBL2NUM(RFLOAT_VALUE(x) + (double)FIX2LONG(y));
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(y)) {
|
2008-09-05 22:24:21 +04:00
|
|
|
return DBL2NUM(RFLOAT_VALUE(x) + rb_big2dbl(y));
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(y)) {
|
2008-09-05 22:24:21 +04:00
|
|
|
return DBL2NUM(RFLOAT_VALUE(x) + RFLOAT_VALUE(y));
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
|
|
|
else {
|
2008-02-12 05:46:21 +03:00
|
|
|
return rb_num_coerce_bin(x, y, '+');
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-12-23 19:21:17 +03:00
|
|
|
/*
|
2021-11-19 21:16:16 +03:00
|
|
|
* call-seq:
|
2021-11-21 02:21:30 +03:00
|
|
|
* self - other -> numeric
|
2021-11-19 21:16:16 +03:00
|
|
|
*
|
|
|
|
* Returns a new \Float which is the difference of +self+ and +other+:
|
|
|
|
*
|
|
|
|
* f = 3.14
|
|
|
|
* f - 1 # => 2.14
|
|
|
|
* f - 1.0 # => 2.14
|
|
|
|
* f - Rational(1, 1) # => 2.14
|
|
|
|
* f - Complex(1, 0) # => (2.14+0i)
|
2003-12-23 19:21:17 +03:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2020-12-09 12:48:59 +03:00
|
|
|
VALUE
|
|
|
|
rb_float_minus(VALUE x, VALUE y)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2021-09-11 07:45:22 +03:00
|
|
|
if (FIXNUM_P(y)) {
|
2008-09-05 22:24:21 +04:00
|
|
|
return DBL2NUM(RFLOAT_VALUE(x) - (double)FIX2LONG(y));
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(y)) {
|
2008-09-05 22:24:21 +04:00
|
|
|
return DBL2NUM(RFLOAT_VALUE(x) - rb_big2dbl(y));
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(y)) {
|
2008-09-05 22:24:21 +04:00
|
|
|
return DBL2NUM(RFLOAT_VALUE(x) - RFLOAT_VALUE(y));
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
|
|
|
else {
|
2008-02-12 05:46:21 +03:00
|
|
|
return rb_num_coerce_bin(x, y, '-');
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-12-23 19:21:17 +03:00
|
|
|
/*
|
2021-11-19 21:16:16 +03:00
|
|
|
* call-seq:
|
2021-11-21 02:21:30 +03:00
|
|
|
* self * other -> numeric
|
2021-11-19 21:16:16 +03:00
|
|
|
*
|
|
|
|
* Returns a new \Float which is the product of +self+ and +other+:
|
2003-12-23 19:21:17 +03:00
|
|
|
*
|
2021-11-19 21:16:16 +03:00
|
|
|
* f = 3.14
|
|
|
|
* f * 2 # => 6.28
|
|
|
|
* f * 2.0 # => 6.28
|
|
|
|
* f * Rational(1, 2) # => 1.57
|
|
|
|
* f * Complex(2, 0) # => (6.28+0.0i)
|
2003-12-23 19:21:17 +03:00
|
|
|
*/
|
|
|
|
|
2019-01-03 09:19:17 +03:00
|
|
|
VALUE
|
|
|
|
rb_float_mul(VALUE x, VALUE y)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2021-09-11 07:45:22 +03:00
|
|
|
if (FIXNUM_P(y)) {
|
2008-09-05 22:24:21 +04:00
|
|
|
return DBL2NUM(RFLOAT_VALUE(x) * (double)FIX2LONG(y));
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(y)) {
|
2008-09-05 22:24:21 +04:00
|
|
|
return DBL2NUM(RFLOAT_VALUE(x) * rb_big2dbl(y));
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(y)) {
|
2008-09-05 22:24:21 +04:00
|
|
|
return DBL2NUM(RFLOAT_VALUE(x) * RFLOAT_VALUE(y));
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
|
|
|
else {
|
2008-02-12 05:46:21 +03:00
|
|
|
return rb_num_coerce_bin(x, y, '*');
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-12 06:26:39 +03:00
|
|
|
static double
|
|
|
|
double_div_double(double x, double y)
|
|
|
|
{
|
|
|
|
if (LIKELY(y != 0.0)) {
|
|
|
|
return x / y;
|
|
|
|
}
|
|
|
|
else if (x == 0.0) {
|
|
|
|
return nan("");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
double z = signbit(y) ? -1.0 : 1.0;
|
|
|
|
return x * z * HUGE_VAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-12 10:14:43 +03:00
|
|
|
MJIT_FUNC_EXPORTED VALUE
|
2018-11-12 06:26:39 +03:00
|
|
|
rb_flo_div_flo(VALUE x, VALUE y)
|
|
|
|
{
|
|
|
|
double num = RFLOAT_VALUE(x);
|
|
|
|
double den = RFLOAT_VALUE(y);
|
2018-11-12 07:09:24 +03:00
|
|
|
double ret = double_div_double(num, den);
|
2018-11-12 06:26:39 +03:00
|
|
|
return DBL2NUM(ret);
|
|
|
|
}
|
|
|
|
|
2003-12-23 19:21:17 +03:00
|
|
|
/*
|
2021-11-19 21:16:16 +03:00
|
|
|
* call-seq:
|
2021-11-21 02:21:30 +03:00
|
|
|
* self / other -> numeric
|
2021-11-19 21:16:16 +03:00
|
|
|
*
|
|
|
|
* Returns a new \Float which is the result of dividing +self+ by +other+:
|
|
|
|
*
|
|
|
|
* f = 3.14
|
|
|
|
* f / 2 # => 1.57
|
|
|
|
* f / 2.0 # => 1.57
|
|
|
|
* f / Rational(2, 1) # => 1.57
|
|
|
|
* f / Complex(2, 0) # => (1.57+0.0i)
|
2003-12-23 19:21:17 +03:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2019-08-10 08:30:34 +03:00
|
|
|
VALUE
|
|
|
|
rb_float_div(VALUE x, VALUE y)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2018-11-09 12:14:23 +03:00
|
|
|
double num = RFLOAT_VALUE(x);
|
2018-11-12 06:26:39 +03:00
|
|
|
double den;
|
|
|
|
double ret;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2021-09-11 07:45:22 +03:00
|
|
|
if (FIXNUM_P(y)) {
|
2018-11-12 06:26:39 +03:00
|
|
|
den = FIX2LONG(y);
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(y)) {
|
2018-11-12 06:26:39 +03:00
|
|
|
den = rb_big2dbl(y);
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(y)) {
|
2018-11-12 06:26:39 +03:00
|
|
|
den = RFLOAT_VALUE(y);
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
|
|
|
else {
|
2008-02-12 05:46:21 +03:00
|
|
|
return rb_num_coerce_bin(x, y, '/');
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2018-11-09 12:14:23 +03:00
|
|
|
|
2018-11-12 06:26:39 +03:00
|
|
|
ret = double_div_double(num, den);
|
|
|
|
return DBL2NUM(ret);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2009-09-05 10:41:40 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-21 02:21:30 +03:00
|
|
|
* quo(other) -> numeric
|
|
|
|
*
|
|
|
|
* Returns the quotient from dividing +self+ by +other+:
|
|
|
|
*
|
|
|
|
* f = 3.14
|
|
|
|
* f.quo(2) # => 1.57
|
|
|
|
* f.quo(-2) # => -1.57
|
|
|
|
* f.quo(Rational(2, 1)) # => 1.57
|
|
|
|
* f.quo(Complex(2, 0)) # => (1.57+0.0i)
|
|
|
|
*
|
|
|
|
* Float#fdiv is an alias for Float#quo.
|
2009-09-05 10:41:40 +04:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2008-03-16 03:23:43 +03:00
|
|
|
static VALUE
|
2008-04-07 17:52:26 +04:00
|
|
|
flo_quo(VALUE x, VALUE y)
|
2008-03-16 03:23:43 +03:00
|
|
|
{
|
2016-08-13 17:08:03 +03:00
|
|
|
return num_funcall1(x, '/', y);
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2000-07-03 09:46:36 +04:00
|
|
|
static void
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
flodivmod(double x, double y, double *divp, double *modp)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2000-07-06 11:21:26 +04:00
|
|
|
double div, mod;
|
1999-01-20 07:59:39 +03:00
|
|
|
|
2014-08-01 11:35:48 +04:00
|
|
|
if (isnan(y)) {
|
|
|
|
/* y is NaN so all results are NaN */
|
|
|
|
if (modp) *modp = y;
|
|
|
|
if (divp) *divp = y;
|
|
|
|
return;
|
|
|
|
}
|
2008-11-27 19:01:54 +03:00
|
|
|
if (y == 0.0) rb_num_zerodiv();
|
2012-12-01 19:25:28 +04:00
|
|
|
if ((x == 0.0) || (isinf(y) && !isinf(x)))
|
2012-03-14 10:10:01 +04:00
|
|
|
mod = x;
|
|
|
|
else {
|
2012-03-14 12:56:42 +04:00
|
|
|
#ifdef HAVE_FMOD
|
|
|
|
mod = fmod(x, y);
|
|
|
|
#else
|
2000-07-03 09:46:36 +04:00
|
|
|
double z;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2000-11-27 12:23:38 +03:00
|
|
|
modf(x/y, &z);
|
2001-05-02 08:22:21 +04:00
|
|
|
mod = x - z * y;
|
1998-01-16 15:13:05 +03:00
|
|
|
#endif
|
2012-03-14 12:56:42 +04:00
|
|
|
}
|
2014-08-01 11:35:48 +04:00
|
|
|
if (isinf(x) && !isinf(y))
|
2007-11-13 10:33:09 +03:00
|
|
|
div = x;
|
2016-04-03 03:34:31 +03:00
|
|
|
else {
|
2007-11-13 10:33:09 +03:00
|
|
|
div = (x - mod) / y;
|
2021-03-11 00:15:50 +03:00
|
|
|
if (modp && divp) div = round(div);
|
2016-04-03 03:34:31 +03:00
|
|
|
}
|
2000-07-06 11:21:26 +04:00
|
|
|
if (y*mod < 0) {
|
2021-03-11 00:15:50 +03:00
|
|
|
mod += y;
|
|
|
|
div -= 1.0;
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
2000-07-06 11:21:26 +04:00
|
|
|
if (modp) *modp = mod;
|
|
|
|
if (divp) *divp = div;
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2012-03-14 10:10:01 +04:00
|
|
|
/*
|
|
|
|
* Returns the modulo of division of x by y.
|
|
|
|
* An error will be raised if y == 0.
|
|
|
|
*/
|
|
|
|
|
mjit_compile.c: merge initial JIT compiler
which has been developed by Takashi Kokubun <takashikkbn@gmail> as
YARV-MJIT. Many of its bugs are fixed by wanabe <s.wanabe@gmail.com>.
This JIT compiler is designed to be a safe migration path to introduce
JIT compiler to MRI. So this commit does not include any bytecode
changes or dynamic instruction modifications, which are done in original
MJIT.
This commit even strips off some aggressive optimizations from
YARV-MJIT, and thus it's slower than YARV-MJIT too. But it's still
fairly faster than Ruby 2.5 in some benchmarks (attached below).
Note that this JIT compiler passes `make test`, `make test-all`, `make
test-spec` without JIT, and even with JIT. Not only it's perfectly safe
with JIT disabled because it does not replace VM instructions unlike
MJIT, but also with JIT enabled it stably runs Ruby applications
including Rails applications.
I'm expecting this version as just "initial" JIT compiler. I have many
optimization ideas which are skipped for initial merging, and you may
easily replace this JIT compiler with a faster one by just replacing
mjit_compile.c. `mjit_compile` interface is designed for the purpose.
common.mk: update dependencies for mjit_compile.c.
internal.h: declare `rb_vm_insn_addr2insn` for MJIT.
vm.c: exclude some definitions if `-DMJIT_HEADER` is provided to
compiler. This avoids to include some functions which take a long time
to compile, e.g. vm_exec_core. Some of the purpose is achieved in
transform_mjit_header.rb (see `IGNORED_FUNCTIONS`) but others are
manually resolved for now. Load mjit_helper.h for MJIT header.
mjit_helper.h: New. This is a file used only by JIT-ed code. I'll
refactor `mjit_call_cfunc` later.
vm_eval.c: add some #ifdef switches to skip compiling some functions
like Init_vm_eval.
win32/mkexports.rb: export thread/ec functions, which are used by MJIT.
include/ruby/defines.h: add MJIT_FUNC_EXPORTED macro alis to clarify
that a function is exported only for MJIT.
array.c: export a function used by MJIT.
bignum.c: ditto.
class.c: ditto.
compile.c: ditto.
error.c: ditto.
gc.c: ditto.
hash.c: ditto.
iseq.c: ditto.
numeric.c: ditto.
object.c: ditto.
proc.c: ditto.
re.c: ditto.
st.c: ditto.
string.c: ditto.
thread.c: ditto.
variable.c: ditto.
vm_backtrace.c: ditto.
vm_insnhelper.c: ditto.
vm_method.c: ditto.
I would like to improve maintainability of function exports, but I
believe this way is acceptable as initial merging if we clarify the
new exports are for MJIT (so that we can use them as TODO list to fix)
and add unit tests to detect unresolved symbols.
I'll add unit tests of JIT compilations in succeeding commits.
Author: Takashi Kokubun <takashikkbn@gmail.com>
Contributor: wanabe <s.wanabe@gmail.com>
Part of [Feature #14235]
---
* Known issues
* Code generated by gcc is faster than clang. The benchmark may be worse
in macOS. Following benchmark result is provided by gcc w/ Linux.
* Performance is decreased when Google Chrome is running
* JIT can work on MinGW, but it doesn't improve performance at least
in short running benchmark.
* Currently it doesn't perform well with Rails. We'll try to fix this
before release.
---
* Benchmark reslts
Benchmarked with:
Intel 4.0GHz i7-4790K with 16GB memory under x86-64 Ubuntu 8 Cores
- 2.0.0-p0: Ruby 2.0.0-p0
- r62186: Ruby trunk (early 2.6.0), before MJIT changes
- JIT off: On this commit, but without `--jit` option
- JIT on: On this commit, and with `--jit` option
** Optcarrot fps
Benchmark: https://github.com/mame/optcarrot
| |2.0.0-p0 |r62186 |JIT off |JIT on |
|:--------|:--------|:--------|:--------|:--------|
|fps |37.32 |51.46 |51.31 |58.88 |
|vs 2.0.0 |1.00x |1.38x |1.37x |1.58x |
** MJIT benchmarks
Benchmark: https://github.com/benchmark-driver/mjit-benchmarks
(Original: https://github.com/vnmakarov/ruby/tree/rtl_mjit_branch/MJIT-benchmarks)
| |2.0.0-p0 |r62186 |JIT off |JIT on |
|:----------|:--------|:--------|:--------|:--------|
|aread |1.00 |1.09 |1.07 |2.19 |
|aref |1.00 |1.13 |1.11 |2.22 |
|aset |1.00 |1.50 |1.45 |2.64 |
|awrite |1.00 |1.17 |1.13 |2.20 |
|call |1.00 |1.29 |1.26 |2.02 |
|const2 |1.00 |1.10 |1.10 |2.19 |
|const |1.00 |1.11 |1.10 |2.19 |
|fannk |1.00 |1.04 |1.02 |1.00 |
|fib |1.00 |1.32 |1.31 |1.84 |
|ivread |1.00 |1.13 |1.12 |2.43 |
|ivwrite |1.00 |1.23 |1.21 |2.40 |
|mandelbrot |1.00 |1.13 |1.16 |1.28 |
|meteor |1.00 |2.97 |2.92 |3.17 |
|nbody |1.00 |1.17 |1.15 |1.49 |
|nest-ntimes|1.00 |1.22 |1.20 |1.39 |
|nest-while |1.00 |1.10 |1.10 |1.37 |
|norm |1.00 |1.18 |1.16 |1.24 |
|nsvb |1.00 |1.16 |1.16 |1.17 |
|red-black |1.00 |1.02 |0.99 |1.12 |
|sieve |1.00 |1.30 |1.28 |1.62 |
|trees |1.00 |1.14 |1.13 |1.19 |
|while |1.00 |1.12 |1.11 |2.41 |
** Discourse's script/bench.rb
Benchmark: https://github.com/discourse/discourse/blob/v1.8.7/script/bench.rb
NOTE: Rails performance was somehow a little degraded with JIT for now.
We should fix this.
(At least I know opt_aref is performing badly in JIT and I have an idea
to fix it. Please wait for the fix.)
*** JIT off
Your Results: (note for timings- percentile is first, duration is second in millisecs)
categories_admin:
50: 17
75: 18
90: 22
99: 29
home_admin:
50: 21
75: 21
90: 27
99: 40
topic_admin:
50: 17
75: 18
90: 22
99: 32
categories:
50: 35
75: 41
90: 43
99: 77
home:
50: 39
75: 46
90: 49
99: 95
topic:
50: 46
75: 52
90: 56
99: 101
*** JIT on
Your Results: (note for timings- percentile is first, duration is second in millisecs)
categories_admin:
50: 19
75: 21
90: 25
99: 33
home_admin:
50: 24
75: 26
90: 30
99: 35
topic_admin:
50: 19
75: 20
90: 25
99: 30
categories:
50: 40
75: 44
90: 48
99: 76
home:
50: 42
75: 48
90: 51
99: 89
topic:
50: 49
75: 55
90: 58
99: 99
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62197 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2018-02-04 14:22:28 +03:00
|
|
|
MJIT_FUNC_EXPORTED double
|
2012-03-15 05:39:00 +04:00
|
|
|
ruby_float_mod(double x, double y)
|
|
|
|
{
|
2012-03-14 10:10:01 +04:00
|
|
|
double mod;
|
|
|
|
flodivmod(x, y, 0, &mod);
|
|
|
|
return mod;
|
|
|
|
}
|
|
|
|
|
2003-12-23 19:21:17 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-10-15 19:57:49 +03:00
|
|
|
* self % other -> float
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-10-15 19:57:49 +03:00
|
|
|
* Returns +self+ modulo +other+ as a float.
|
|
|
|
*
|
|
|
|
* For float +f+ and real number +r+, these expressions are equivalent:
|
|
|
|
*
|
|
|
|
* f % r
|
|
|
|
* f-r*(f/r).floor
|
|
|
|
* f.divmod(r)[1]
|
|
|
|
*
|
|
|
|
* See Numeric#divmod.
|
|
|
|
*
|
|
|
|
* Examples:
|
|
|
|
*
|
|
|
|
* 10.0 % 2 # => 0.0
|
|
|
|
* 10.0 % 3 # => 1.0
|
|
|
|
* 10.0 % 4 # => 2.0
|
|
|
|
*
|
|
|
|
* 10.0 % -2 # => 0.0
|
|
|
|
* 10.0 % -3 # => -2.0
|
|
|
|
* 10.0 % -4 # => -2.0
|
|
|
|
*
|
|
|
|
* 10.0 % 4.0 # => 2.0
|
|
|
|
* 10.0 % Rational(4, 1) # => 2.0
|
|
|
|
*
|
|
|
|
* Float#modulo is an alias for Float#%.
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2003-12-23 19:21:17 +03:00
|
|
|
*/
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
flo_mod(VALUE x, VALUE y)
|
1999-01-20 07:59:39 +03:00
|
|
|
{
|
2012-03-14 10:10:01 +04:00
|
|
|
double fy;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2021-09-11 07:45:22 +03:00
|
|
|
if (FIXNUM_P(y)) {
|
2000-07-03 09:46:36 +04:00
|
|
|
fy = (double)FIX2LONG(y);
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(y)) {
|
2000-07-03 09:46:36 +04:00
|
|
|
fy = rb_big2dbl(y);
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(y)) {
|
* include/ruby/ruby.h: introduce 2 macros:
RFLOAT_VALUE(v), DOUBLE2NUM(dbl).
Rename RFloat#value -> RFloat#double_value.
Do not touch RFloat#double_value directly.
* bignum.c, insns.def, marshal.c, math.c, numeric.c, object.c,
pack.c, parse.y, process.c, random.c, sprintf.c, string.c,
time.c: apply above changes.
* ext/dl/mkcallback.rb, ext/json/ext/generator/generator.c:
ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13913 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-11-13 19:00:53 +03:00
|
|
|
fy = RFLOAT_VALUE(y);
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
|
|
|
else {
|
2008-02-12 05:46:21 +03:00
|
|
|
return rb_num_coerce_bin(x, y, '%');
|
2000-07-03 09:46:36 +04:00
|
|
|
}
|
2012-03-14 10:10:01 +04:00
|
|
|
return DBL2NUM(ruby_float_mod(RFLOAT_VALUE(x), fy));
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
|
|
|
|
2008-03-13 19:37:54 +03:00
|
|
|
static VALUE
|
|
|
|
dbl2ival(double d)
|
|
|
|
{
|
2017-03-09 05:31:23 +03:00
|
|
|
if (FIXABLE(d)) {
|
|
|
|
return LONG2FIX((long)d);
|
|
|
|
}
|
|
|
|
return rb_dbl2big(d);
|
2008-03-13 19:37:54 +03:00
|
|
|
}
|
|
|
|
|
2003-12-23 19:21:17 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-10-15 20:51:37 +03:00
|
|
|
* divmod(other) -> array
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-10-15 20:51:37 +03:00
|
|
|
* Returns a 2-element array <tt>[q, r]</tt>, where
|
|
|
|
*
|
|
|
|
* q = (self/other).floor # Quotient
|
|
|
|
* r = self % other # Remainder
|
|
|
|
*
|
|
|
|
* Examples:
|
|
|
|
*
|
|
|
|
* 11.0.divmod(4) # => [2, 3.0]
|
|
|
|
* 11.0.divmod(-4) # => [-3, -1.0]
|
|
|
|
* -11.0.divmod(4) # => [-3, 1.0]
|
|
|
|
* -11.0.divmod(-4) # => [2, -3.0]
|
|
|
|
*
|
|
|
|
* 12.0.divmod(4) # => [3, 0.0]
|
|
|
|
* 12.0.divmod(-4) # => [-3, 0.0]
|
|
|
|
* -12.0.divmod(4) # => [-3, -0.0]
|
|
|
|
* -12.0.divmod(-4) # => [3, -0.0]
|
|
|
|
*
|
|
|
|
* 13.0.divmod(4.0) # => [3, 1.0]
|
|
|
|
* 13.0.divmod(Rational(4, 1)) # => [3, 1.0]
|
2013-02-22 06:01:28 +04:00
|
|
|
*
|
2003-12-23 19:21:17 +03:00
|
|
|
*/
|
|
|
|
|
2000-02-01 06:12:21 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
flo_divmod(VALUE x, VALUE y)
|
2000-02-01 06:12:21 +03:00
|
|
|
{
|
2008-03-14 08:03:28 +03:00
|
|
|
double fy, div, mod;
|
2004-11-17 05:27:38 +03:00
|
|
|
volatile VALUE a, b;
|
2000-02-01 06:12:21 +03:00
|
|
|
|
2021-09-11 07:45:22 +03:00
|
|
|
if (FIXNUM_P(y)) {
|
2000-07-03 09:46:36 +04:00
|
|
|
fy = (double)FIX2LONG(y);
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(y)) {
|
2000-07-03 09:46:36 +04:00
|
|
|
fy = rb_big2dbl(y);
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(y)) {
|
* include/ruby/ruby.h: introduce 2 macros:
RFLOAT_VALUE(v), DOUBLE2NUM(dbl).
Rename RFloat#value -> RFloat#double_value.
Do not touch RFloat#double_value directly.
* bignum.c, insns.def, marshal.c, math.c, numeric.c, object.c,
pack.c, parse.y, process.c, random.c, sprintf.c, string.c,
time.c: apply above changes.
* ext/dl/mkcallback.rb, ext/json/ext/generator/generator.c:
ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13913 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-11-13 19:00:53 +03:00
|
|
|
fy = RFLOAT_VALUE(y);
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
|
|
|
else {
|
2015-10-12 03:08:58 +03:00
|
|
|
return rb_num_coerce_bin(x, y, id_divmod);
|
2000-02-01 06:12:21 +03:00
|
|
|
}
|
* include/ruby/ruby.h: introduce 2 macros:
RFLOAT_VALUE(v), DOUBLE2NUM(dbl).
Rename RFloat#value -> RFloat#double_value.
Do not touch RFloat#double_value directly.
* bignum.c, insns.def, marshal.c, math.c, numeric.c, object.c,
pack.c, parse.y, process.c, random.c, sprintf.c, string.c,
time.c: apply above changes.
* ext/dl/mkcallback.rb, ext/json/ext/generator/generator.c:
ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13913 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-11-13 19:00:53 +03:00
|
|
|
flodivmod(RFLOAT_VALUE(x), fy, &div, &mod);
|
2008-03-13 19:37:54 +03:00
|
|
|
a = dbl2ival(div);
|
2008-09-05 22:24:21 +04:00
|
|
|
b = DBL2NUM(mod);
|
2004-11-17 05:27:38 +03:00
|
|
|
return rb_assoc_new(a, b);
|
2000-02-01 06:12:21 +03:00
|
|
|
}
|
|
|
|
|
2003-12-23 19:21:17 +03:00
|
|
|
/*
|
2021-11-21 02:21:30 +03:00
|
|
|
* call-seq:
|
|
|
|
* self ** other -> numeric
|
2003-12-23 19:21:17 +03:00
|
|
|
*
|
2021-11-21 02:21:30 +03:00
|
|
|
* Raises +self+ to the power of +other+:
|
|
|
|
*
|
|
|
|
* f = 3.14
|
|
|
|
* f ** 2 # => 9.8596
|
|
|
|
* f ** -2 # => 0.1014239928597509
|
|
|
|
* f ** 2.1 # => 11.054834900588839
|
|
|
|
* f ** Rational(2, 1) # => 9.8596
|
|
|
|
* f ** Complex(2, 0) # => (9.8596+0i)
|
2009-06-19 18:44:03 +04:00
|
|
|
*
|
2003-12-23 19:21:17 +03:00
|
|
|
*/
|
2007-05-09 08:11:41 +04:00
|
|
|
|
2016-11-11 19:38:28 +03:00
|
|
|
VALUE
|
|
|
|
rb_float_pow(VALUE x, VALUE y)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2015-10-12 03:08:44 +03:00
|
|
|
double dx, dy;
|
2020-05-11 20:12:06 +03:00
|
|
|
if (y == INT2FIX(2)) {
|
|
|
|
dx = RFLOAT_VALUE(x);
|
|
|
|
return DBL2NUM(dx * dx);
|
|
|
|
}
|
2021-09-11 07:45:22 +03:00
|
|
|
else if (FIXNUM_P(y)) {
|
2015-10-12 03:08:44 +03:00
|
|
|
dx = RFLOAT_VALUE(x);
|
|
|
|
dy = (double)FIX2LONG(y);
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(y)) {
|
2015-10-12 03:08:44 +03:00
|
|
|
dx = RFLOAT_VALUE(x);
|
|
|
|
dy = rb_big2dbl(y);
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(y)) {
|
2015-10-12 03:08:44 +03:00
|
|
|
dx = RFLOAT_VALUE(x);
|
|
|
|
dy = RFLOAT_VALUE(y);
|
|
|
|
if (dx < 0 && dy != round(dy))
|
2018-12-12 14:06:47 +03:00
|
|
|
return rb_dbl_complex_new_polar_pi(pow(-dx, dy), dy);
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
|
|
|
else {
|
2015-10-12 03:08:58 +03:00
|
|
|
return rb_num_coerce_bin(x, y, idPow);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2015-10-12 03:08:44 +03:00
|
|
|
return DBL2NUM(pow(dx, dy));
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2003-12-27 08:46:46 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-10-28 23:11:11 +03:00
|
|
|
* eql?(other) -> true or false
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-10-28 23:11:11 +03:00
|
|
|
* Returns +true+ if +self+ and +other+ are the same type and have equal values.
|
|
|
|
*
|
|
|
|
* Of the Core and Standard Library classes,
|
|
|
|
* only Integer, Rational, and Complex use this implementation.
|
|
|
|
*
|
|
|
|
* Examples:
|
|
|
|
*
|
|
|
|
* 1.eql?(1) # => true
|
|
|
|
* 1.eql?(1.0) # => false
|
|
|
|
* 1.eql?(Rational(1, 1)) # => false
|
|
|
|
* 1.eql?(Complex(1, 0)) # => false
|
|
|
|
*
|
|
|
|
* \Method +eql?+ is different from +==+ in that +eql?+ requires matching types,
|
|
|
|
* while +==+ does not.
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2003-12-27 08:46:46 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
num_eql(VALUE x, VALUE y)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
1999-01-20 07:59:39 +03:00
|
|
|
if (TYPE(x) != TYPE(y)) return Qfalse;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2021-09-03 14:50:12 +03:00
|
|
|
if (RB_BIGNUM_TYPE_P(x)) {
|
2016-03-18 16:11:09 +03:00
|
|
|
return rb_big_eql(x, y);
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
return rb_equal(x, y);
|
|
|
|
}
|
|
|
|
|
2003-12-27 08:46:46 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-10-28 23:11:11 +03:00
|
|
|
* self <=> other -> zero or nil
|
|
|
|
*
|
|
|
|
* Returns zero if +self+ is the same as +other+, +nil+ otherwise.
|
|
|
|
*
|
|
|
|
* No subclass in the Ruby Core or Standard Library uses this implementation.
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2003-12-27 08:46:46 +03:00
|
|
|
*/
|
|
|
|
|
2002-11-22 12:14:24 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
num_cmp(VALUE x, VALUE y)
|
2002-11-22 12:14:24 +03:00
|
|
|
{
|
|
|
|
if (x == y) return INT2FIX(0);
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
num_equal(VALUE x, VALUE y)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2016-11-13 05:04:51 +03:00
|
|
|
VALUE result;
|
2003-07-21 22:48:58 +04:00
|
|
|
if (x == y) return Qtrue;
|
2016-11-13 05:04:51 +03:00
|
|
|
result = num_funcall1(y, id_eq, x);
|
2021-08-02 06:06:44 +03:00
|
|
|
return RBOOL(RTEST(result));
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2003-12-23 19:21:17 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-21 02:21:30 +03:00
|
|
|
* self == other -> true or false
|
2013-07-15 22:27:23 +04:00
|
|
|
*
|
2021-11-21 02:21:30 +03:00
|
|
|
* Returns +true+ if +other+ has the same value as +self+, +false+ otherwise:
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-11-21 02:21:30 +03:00
|
|
|
* 2.0 == 2 # => true
|
|
|
|
* 2.0 == 2.0 # => true
|
|
|
|
* 2.0 == Rational(2, 1) # => true
|
|
|
|
* 2.0 == Complex(2, 0) # => true
|
|
|
|
*
|
|
|
|
* <tt>Float::NAN == Float::NAN</tt> returns an implementation-dependent value.
|
|
|
|
*
|
|
|
|
* Related: Float#eql? (requires +other+ to be a \Float).
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2003-12-23 19:21:17 +03:00
|
|
|
*/
|
|
|
|
|
mjit_compile.c: merge initial JIT compiler
which has been developed by Takashi Kokubun <takashikkbn@gmail> as
YARV-MJIT. Many of its bugs are fixed by wanabe <s.wanabe@gmail.com>.
This JIT compiler is designed to be a safe migration path to introduce
JIT compiler to MRI. So this commit does not include any bytecode
changes or dynamic instruction modifications, which are done in original
MJIT.
This commit even strips off some aggressive optimizations from
YARV-MJIT, and thus it's slower than YARV-MJIT too. But it's still
fairly faster than Ruby 2.5 in some benchmarks (attached below).
Note that this JIT compiler passes `make test`, `make test-all`, `make
test-spec` without JIT, and even with JIT. Not only it's perfectly safe
with JIT disabled because it does not replace VM instructions unlike
MJIT, but also with JIT enabled it stably runs Ruby applications
including Rails applications.
I'm expecting this version as just "initial" JIT compiler. I have many
optimization ideas which are skipped for initial merging, and you may
easily replace this JIT compiler with a faster one by just replacing
mjit_compile.c. `mjit_compile` interface is designed for the purpose.
common.mk: update dependencies for mjit_compile.c.
internal.h: declare `rb_vm_insn_addr2insn` for MJIT.
vm.c: exclude some definitions if `-DMJIT_HEADER` is provided to
compiler. This avoids to include some functions which take a long time
to compile, e.g. vm_exec_core. Some of the purpose is achieved in
transform_mjit_header.rb (see `IGNORED_FUNCTIONS`) but others are
manually resolved for now. Load mjit_helper.h for MJIT header.
mjit_helper.h: New. This is a file used only by JIT-ed code. I'll
refactor `mjit_call_cfunc` later.
vm_eval.c: add some #ifdef switches to skip compiling some functions
like Init_vm_eval.
win32/mkexports.rb: export thread/ec functions, which are used by MJIT.
include/ruby/defines.h: add MJIT_FUNC_EXPORTED macro alis to clarify
that a function is exported only for MJIT.
array.c: export a function used by MJIT.
bignum.c: ditto.
class.c: ditto.
compile.c: ditto.
error.c: ditto.
gc.c: ditto.
hash.c: ditto.
iseq.c: ditto.
numeric.c: ditto.
object.c: ditto.
proc.c: ditto.
re.c: ditto.
st.c: ditto.
string.c: ditto.
thread.c: ditto.
variable.c: ditto.
vm_backtrace.c: ditto.
vm_insnhelper.c: ditto.
vm_method.c: ditto.
I would like to improve maintainability of function exports, but I
believe this way is acceptable as initial merging if we clarify the
new exports are for MJIT (so that we can use them as TODO list to fix)
and add unit tests to detect unresolved symbols.
I'll add unit tests of JIT compilations in succeeding commits.
Author: Takashi Kokubun <takashikkbn@gmail.com>
Contributor: wanabe <s.wanabe@gmail.com>
Part of [Feature #14235]
---
* Known issues
* Code generated by gcc is faster than clang. The benchmark may be worse
in macOS. Following benchmark result is provided by gcc w/ Linux.
* Performance is decreased when Google Chrome is running
* JIT can work on MinGW, but it doesn't improve performance at least
in short running benchmark.
* Currently it doesn't perform well with Rails. We'll try to fix this
before release.
---
* Benchmark reslts
Benchmarked with:
Intel 4.0GHz i7-4790K with 16GB memory under x86-64 Ubuntu 8 Cores
- 2.0.0-p0: Ruby 2.0.0-p0
- r62186: Ruby trunk (early 2.6.0), before MJIT changes
- JIT off: On this commit, but without `--jit` option
- JIT on: On this commit, and with `--jit` option
** Optcarrot fps
Benchmark: https://github.com/mame/optcarrot
| |2.0.0-p0 |r62186 |JIT off |JIT on |
|:--------|:--------|:--------|:--------|:--------|
|fps |37.32 |51.46 |51.31 |58.88 |
|vs 2.0.0 |1.00x |1.38x |1.37x |1.58x |
** MJIT benchmarks
Benchmark: https://github.com/benchmark-driver/mjit-benchmarks
(Original: https://github.com/vnmakarov/ruby/tree/rtl_mjit_branch/MJIT-benchmarks)
| |2.0.0-p0 |r62186 |JIT off |JIT on |
|:----------|:--------|:--------|:--------|:--------|
|aread |1.00 |1.09 |1.07 |2.19 |
|aref |1.00 |1.13 |1.11 |2.22 |
|aset |1.00 |1.50 |1.45 |2.64 |
|awrite |1.00 |1.17 |1.13 |2.20 |
|call |1.00 |1.29 |1.26 |2.02 |
|const2 |1.00 |1.10 |1.10 |2.19 |
|const |1.00 |1.11 |1.10 |2.19 |
|fannk |1.00 |1.04 |1.02 |1.00 |
|fib |1.00 |1.32 |1.31 |1.84 |
|ivread |1.00 |1.13 |1.12 |2.43 |
|ivwrite |1.00 |1.23 |1.21 |2.40 |
|mandelbrot |1.00 |1.13 |1.16 |1.28 |
|meteor |1.00 |2.97 |2.92 |3.17 |
|nbody |1.00 |1.17 |1.15 |1.49 |
|nest-ntimes|1.00 |1.22 |1.20 |1.39 |
|nest-while |1.00 |1.10 |1.10 |1.37 |
|norm |1.00 |1.18 |1.16 |1.24 |
|nsvb |1.00 |1.16 |1.16 |1.17 |
|red-black |1.00 |1.02 |0.99 |1.12 |
|sieve |1.00 |1.30 |1.28 |1.62 |
|trees |1.00 |1.14 |1.13 |1.19 |
|while |1.00 |1.12 |1.11 |2.41 |
** Discourse's script/bench.rb
Benchmark: https://github.com/discourse/discourse/blob/v1.8.7/script/bench.rb
NOTE: Rails performance was somehow a little degraded with JIT for now.
We should fix this.
(At least I know opt_aref is performing badly in JIT and I have an idea
to fix it. Please wait for the fix.)
*** JIT off
Your Results: (note for timings- percentile is first, duration is second in millisecs)
categories_admin:
50: 17
75: 18
90: 22
99: 29
home_admin:
50: 21
75: 21
90: 27
99: 40
topic_admin:
50: 17
75: 18
90: 22
99: 32
categories:
50: 35
75: 41
90: 43
99: 77
home:
50: 39
75: 46
90: 49
99: 95
topic:
50: 46
75: 52
90: 56
99: 101
*** JIT on
Your Results: (note for timings- percentile is first, duration is second in millisecs)
categories_admin:
50: 19
75: 21
90: 25
99: 33
home_admin:
50: 24
75: 26
90: 30
99: 35
topic_admin:
50: 19
75: 20
90: 25
99: 30
categories:
50: 40
75: 44
90: 48
99: 76
home:
50: 42
75: 48
90: 51
99: 89
topic:
50: 49
75: 55
90: 58
99: 99
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62197 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2018-02-04 14:22:28 +03:00
|
|
|
MJIT_FUNC_EXPORTED VALUE
|
2017-03-06 09:44:11 +03:00
|
|
|
rb_float_equal(VALUE x, VALUE y)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2004-06-04 13:56:25 +04:00
|
|
|
volatile double a, b;
|
2003-04-11 10:37:48 +04:00
|
|
|
|
2021-09-11 07:45:22 +03:00
|
|
|
if (RB_INTEGER_TYPE_P(y)) {
|
2012-07-16 14:39:42 +04:00
|
|
|
return rb_integer_float_eq(y, x);
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(y)) {
|
* include/ruby/ruby.h: introduce 2 macros:
RFLOAT_VALUE(v), DOUBLE2NUM(dbl).
Rename RFloat#value -> RFloat#double_value.
Do not touch RFloat#double_value directly.
* bignum.c, insns.def, marshal.c, math.c, numeric.c, object.c,
pack.c, parse.y, process.c, random.c, sprintf.c, string.c,
time.c: apply above changes.
* ext/dl/mkcallback.rb, ext/json/ext/generator/generator.c:
ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13913 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-11-13 19:00:53 +03:00
|
|
|
b = RFLOAT_VALUE(y);
|
2019-12-02 08:58:43 +03:00
|
|
|
#if MSC_VERSION_BEFORE(1300)
|
2009-02-27 08:42:06 +03:00
|
|
|
if (isnan(b)) return Qfalse;
|
|
|
|
#endif
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
|
|
|
else {
|
1998-01-16 15:13:05 +03:00
|
|
|
return num_equal(x, y);
|
|
|
|
}
|
* include/ruby/ruby.h: introduce 2 macros:
RFLOAT_VALUE(v), DOUBLE2NUM(dbl).
Rename RFloat#value -> RFloat#double_value.
Do not touch RFloat#double_value directly.
* bignum.c, insns.def, marshal.c, math.c, numeric.c, object.c,
pack.c, parse.y, process.c, random.c, sprintf.c, string.c,
time.c: apply above changes.
* ext/dl/mkcallback.rb, ext/json/ext/generator/generator.c:
ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13913 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-11-13 19:00:53 +03:00
|
|
|
a = RFLOAT_VALUE(x);
|
2019-12-02 08:58:43 +03:00
|
|
|
#if MSC_VERSION_BEFORE(1300)
|
2009-02-27 08:42:06 +03:00
|
|
|
if (isnan(a)) return Qfalse;
|
|
|
|
#endif
|
2021-09-15 02:11:05 +03:00
|
|
|
return RBOOL(a == b);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2017-03-06 09:44:11 +03:00
|
|
|
#define flo_eq rb_float_equal
|
2019-11-18 06:13:08 +03:00
|
|
|
static VALUE rb_dbl_hash(double d);
|
2017-03-06 09:44:11 +03:00
|
|
|
|
2003-12-23 19:21:17 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-21 02:21:30 +03:00
|
|
|
* hash -> integer
|
2003-12-23 19:21:17 +03:00
|
|
|
*
|
2021-11-21 02:21:30 +03:00
|
|
|
* Returns the integer hash value for +self+.
|
2014-03-14 05:27:43 +04:00
|
|
|
*
|
|
|
|
* See also Object#hash.
|
2003-12-23 19:21:17 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
flo_hash(VALUE num)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2015-03-18 06:01:58 +03:00
|
|
|
return rb_dbl_hash(RFLOAT_VALUE(num));
|
|
|
|
}
|
|
|
|
|
2019-11-18 06:13:08 +03:00
|
|
|
static VALUE
|
2015-03-18 06:01:58 +03:00
|
|
|
rb_dbl_hash(double d)
|
|
|
|
{
|
2020-04-08 07:28:13 +03:00
|
|
|
return ST2FIX(rb_dbl_long_hash(d));
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2002-08-19 09:56:09 +04:00
|
|
|
VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
rb_dbl_cmp(double a, double b)
|
2002-08-19 09:56:09 +04:00
|
|
|
{
|
2003-04-11 10:37:48 +04:00
|
|
|
if (isnan(a) || isnan(b)) return Qnil;
|
2002-08-19 09:56:09 +04:00
|
|
|
if (a == b) return INT2FIX(0);
|
|
|
|
if (a > b) return INT2FIX(1);
|
|
|
|
if (a < b) return INT2FIX(-1);
|
2002-12-19 12:20:20 +03:00
|
|
|
return Qnil;
|
2002-08-19 09:56:09 +04:00
|
|
|
}
|
|
|
|
|
2003-12-23 19:21:17 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-21 02:21:30 +03:00
|
|
|
* self <=> other -> -1, 0, +1, or nil
|
|
|
|
*
|
|
|
|
* Returns a value that depends on the numeric relation
|
|
|
|
* between +self+ and +other+:
|
|
|
|
*
|
|
|
|
* - -1, if +self+ is less than +other+.
|
|
|
|
* - 0, if +self+ is equal to +other+.
|
|
|
|
* - 1, if +self+ is greater than +other+.
|
|
|
|
* - +nil+, if the two values are incommensurate.
|
|
|
|
*
|
|
|
|
* Examples:
|
|
|
|
*
|
|
|
|
* 2.0 <=> 2 # => 0
|
|
|
|
2.0 <=> 2.0 # => 0
|
|
|
|
2.0 <=> Rational(2, 1) # => 0
|
|
|
|
2.0 <=> Complex(2, 0) # => 0
|
|
|
|
2.0 <=> 1.9 # => 1
|
|
|
|
2.0 <=> 2.1 # => -1
|
|
|
|
2.0 <=> 'foo' # => nil
|
2013-02-23 07:35:38 +04:00
|
|
|
*
|
2017-05-06 10:17:41 +03:00
|
|
|
* This is the basis for the tests in the Comparable module.
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-11-21 02:21:30 +03:00
|
|
|
* <tt>Float::NAN <=> Float::NAN</tt> returns an implementation-dependent value.
|
2013-02-23 07:35:38 +04:00
|
|
|
*
|
2003-12-23 19:21:17 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
flo_cmp(VALUE x, VALUE y)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2010-07-27 11:27:48 +04:00
|
|
|
double a, b;
|
|
|
|
VALUE i;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
* include/ruby/ruby.h: introduce 2 macros:
RFLOAT_VALUE(v), DOUBLE2NUM(dbl).
Rename RFloat#value -> RFloat#double_value.
Do not touch RFloat#double_value directly.
* bignum.c, insns.def, marshal.c, math.c, numeric.c, object.c,
pack.c, parse.y, process.c, random.c, sprintf.c, string.c,
time.c: apply above changes.
* ext/dl/mkcallback.rb, ext/json/ext/generator/generator.c:
ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13913 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-11-13 19:00:53 +03:00
|
|
|
a = RFLOAT_VALUE(x);
|
2009-06-19 12:19:14 +04:00
|
|
|
if (isnan(a)) return Qnil;
|
2021-09-11 07:45:22 +03:00
|
|
|
if (RB_INTEGER_TYPE_P(y)) {
|
2012-07-16 13:41:25 +04:00
|
|
|
VALUE rel = rb_integer_float_cmp(y, x);
|
2012-07-16 10:02:21 +04:00
|
|
|
if (FIXNUM_P(rel))
|
2019-11-07 12:48:51 +03:00
|
|
|
return LONG2FIX(-FIX2LONG(rel));
|
2012-07-16 10:02:21 +04:00
|
|
|
return rel;
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(y)) {
|
* include/ruby/ruby.h: introduce 2 macros:
RFLOAT_VALUE(v), DOUBLE2NUM(dbl).
Rename RFloat#value -> RFloat#double_value.
Do not touch RFloat#double_value directly.
* bignum.c, insns.def, marshal.c, math.c, numeric.c, object.c,
pack.c, parse.y, process.c, random.c, sprintf.c, string.c,
time.c: apply above changes.
* ext/dl/mkcallback.rb, ext/json/ext/generator/generator.c:
ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13913 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-11-13 19:00:53 +03:00
|
|
|
b = RFLOAT_VALUE(y);
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
|
|
|
else {
|
2010-07-25 00:37:31 +04:00
|
|
|
if (isinf(a) && (i = rb_check_funcall(y, rb_intern("infinite?"), 0, 0)) != Qundef) {
|
|
|
|
if (RTEST(i)) {
|
|
|
|
int j = rb_cmpint(i, x, y);
|
|
|
|
j = (a > 0.0) ? (j > 0 ? 0 : +1) : (j < 0 ? 0 : -1);
|
|
|
|
return INT2FIX(j);
|
|
|
|
}
|
2009-06-19 12:19:14 +04:00
|
|
|
if (a > 0.0) return INT2FIX(1);
|
|
|
|
return INT2FIX(-1);
|
|
|
|
}
|
2014-02-28 06:04:28 +04:00
|
|
|
return rb_num_coerce_cmp(x, y, id_cmp);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2002-08-19 09:56:09 +04:00
|
|
|
return rb_dbl_cmp(a, b);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
mjit_compile.c: merge initial JIT compiler
which has been developed by Takashi Kokubun <takashikkbn@gmail> as
YARV-MJIT. Many of its bugs are fixed by wanabe <s.wanabe@gmail.com>.
This JIT compiler is designed to be a safe migration path to introduce
JIT compiler to MRI. So this commit does not include any bytecode
changes or dynamic instruction modifications, which are done in original
MJIT.
This commit even strips off some aggressive optimizations from
YARV-MJIT, and thus it's slower than YARV-MJIT too. But it's still
fairly faster than Ruby 2.5 in some benchmarks (attached below).
Note that this JIT compiler passes `make test`, `make test-all`, `make
test-spec` without JIT, and even with JIT. Not only it's perfectly safe
with JIT disabled because it does not replace VM instructions unlike
MJIT, but also with JIT enabled it stably runs Ruby applications
including Rails applications.
I'm expecting this version as just "initial" JIT compiler. I have many
optimization ideas which are skipped for initial merging, and you may
easily replace this JIT compiler with a faster one by just replacing
mjit_compile.c. `mjit_compile` interface is designed for the purpose.
common.mk: update dependencies for mjit_compile.c.
internal.h: declare `rb_vm_insn_addr2insn` for MJIT.
vm.c: exclude some definitions if `-DMJIT_HEADER` is provided to
compiler. This avoids to include some functions which take a long time
to compile, e.g. vm_exec_core. Some of the purpose is achieved in
transform_mjit_header.rb (see `IGNORED_FUNCTIONS`) but others are
manually resolved for now. Load mjit_helper.h for MJIT header.
mjit_helper.h: New. This is a file used only by JIT-ed code. I'll
refactor `mjit_call_cfunc` later.
vm_eval.c: add some #ifdef switches to skip compiling some functions
like Init_vm_eval.
win32/mkexports.rb: export thread/ec functions, which are used by MJIT.
include/ruby/defines.h: add MJIT_FUNC_EXPORTED macro alis to clarify
that a function is exported only for MJIT.
array.c: export a function used by MJIT.
bignum.c: ditto.
class.c: ditto.
compile.c: ditto.
error.c: ditto.
gc.c: ditto.
hash.c: ditto.
iseq.c: ditto.
numeric.c: ditto.
object.c: ditto.
proc.c: ditto.
re.c: ditto.
st.c: ditto.
string.c: ditto.
thread.c: ditto.
variable.c: ditto.
vm_backtrace.c: ditto.
vm_insnhelper.c: ditto.
vm_method.c: ditto.
I would like to improve maintainability of function exports, but I
believe this way is acceptable as initial merging if we clarify the
new exports are for MJIT (so that we can use them as TODO list to fix)
and add unit tests to detect unresolved symbols.
I'll add unit tests of JIT compilations in succeeding commits.
Author: Takashi Kokubun <takashikkbn@gmail.com>
Contributor: wanabe <s.wanabe@gmail.com>
Part of [Feature #14235]
---
* Known issues
* Code generated by gcc is faster than clang. The benchmark may be worse
in macOS. Following benchmark result is provided by gcc w/ Linux.
* Performance is decreased when Google Chrome is running
* JIT can work on MinGW, but it doesn't improve performance at least
in short running benchmark.
* Currently it doesn't perform well with Rails. We'll try to fix this
before release.
---
* Benchmark reslts
Benchmarked with:
Intel 4.0GHz i7-4790K with 16GB memory under x86-64 Ubuntu 8 Cores
- 2.0.0-p0: Ruby 2.0.0-p0
- r62186: Ruby trunk (early 2.6.0), before MJIT changes
- JIT off: On this commit, but without `--jit` option
- JIT on: On this commit, and with `--jit` option
** Optcarrot fps
Benchmark: https://github.com/mame/optcarrot
| |2.0.0-p0 |r62186 |JIT off |JIT on |
|:--------|:--------|:--------|:--------|:--------|
|fps |37.32 |51.46 |51.31 |58.88 |
|vs 2.0.0 |1.00x |1.38x |1.37x |1.58x |
** MJIT benchmarks
Benchmark: https://github.com/benchmark-driver/mjit-benchmarks
(Original: https://github.com/vnmakarov/ruby/tree/rtl_mjit_branch/MJIT-benchmarks)
| |2.0.0-p0 |r62186 |JIT off |JIT on |
|:----------|:--------|:--------|:--------|:--------|
|aread |1.00 |1.09 |1.07 |2.19 |
|aref |1.00 |1.13 |1.11 |2.22 |
|aset |1.00 |1.50 |1.45 |2.64 |
|awrite |1.00 |1.17 |1.13 |2.20 |
|call |1.00 |1.29 |1.26 |2.02 |
|const2 |1.00 |1.10 |1.10 |2.19 |
|const |1.00 |1.11 |1.10 |2.19 |
|fannk |1.00 |1.04 |1.02 |1.00 |
|fib |1.00 |1.32 |1.31 |1.84 |
|ivread |1.00 |1.13 |1.12 |2.43 |
|ivwrite |1.00 |1.23 |1.21 |2.40 |
|mandelbrot |1.00 |1.13 |1.16 |1.28 |
|meteor |1.00 |2.97 |2.92 |3.17 |
|nbody |1.00 |1.17 |1.15 |1.49 |
|nest-ntimes|1.00 |1.22 |1.20 |1.39 |
|nest-while |1.00 |1.10 |1.10 |1.37 |
|norm |1.00 |1.18 |1.16 |1.24 |
|nsvb |1.00 |1.16 |1.16 |1.17 |
|red-black |1.00 |1.02 |0.99 |1.12 |
|sieve |1.00 |1.30 |1.28 |1.62 |
|trees |1.00 |1.14 |1.13 |1.19 |
|while |1.00 |1.12 |1.11 |2.41 |
** Discourse's script/bench.rb
Benchmark: https://github.com/discourse/discourse/blob/v1.8.7/script/bench.rb
NOTE: Rails performance was somehow a little degraded with JIT for now.
We should fix this.
(At least I know opt_aref is performing badly in JIT and I have an idea
to fix it. Please wait for the fix.)
*** JIT off
Your Results: (note for timings- percentile is first, duration is second in millisecs)
categories_admin:
50: 17
75: 18
90: 22
99: 29
home_admin:
50: 21
75: 21
90: 27
99: 40
topic_admin:
50: 17
75: 18
90: 22
99: 32
categories:
50: 35
75: 41
90: 43
99: 77
home:
50: 39
75: 46
90: 49
99: 95
topic:
50: 46
75: 52
90: 56
99: 101
*** JIT on
Your Results: (note for timings- percentile is first, duration is second in millisecs)
categories_admin:
50: 19
75: 21
90: 25
99: 33
home_admin:
50: 24
75: 26
90: 30
99: 35
topic_admin:
50: 19
75: 20
90: 25
99: 30
categories:
50: 40
75: 44
90: 48
99: 76
home:
50: 42
75: 48
90: 51
99: 89
topic:
50: 49
75: 55
90: 58
99: 99
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62197 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2018-02-04 14:22:28 +03:00
|
|
|
MJIT_FUNC_EXPORTED int
|
2017-04-13 10:22:35 +03:00
|
|
|
rb_float_cmp(VALUE x, VALUE y)
|
|
|
|
{
|
2020-10-02 15:30:07 +03:00
|
|
|
return NUM2INT(ensure_cmp(flo_cmp(x, y), x, y));
|
2017-04-13 10:22:35 +03:00
|
|
|
}
|
|
|
|
|
2003-12-23 19:21:17 +03:00
|
|
|
/*
|
2021-11-22 23:57:17 +03:00
|
|
|
* call-seq:
|
|
|
|
* self > other -> true or false
|
|
|
|
*
|
|
|
|
* Returns +true+ if +self+ is numerically greater than +other+:
|
2013-07-15 22:27:23 +04:00
|
|
|
*
|
2021-11-22 23:57:17 +03:00
|
|
|
* 2.0 > 1 # => true
|
|
|
|
* 2.0 > 1.0 # => true
|
|
|
|
* 2.0 > Rational(1, 2) # => true
|
|
|
|
* 2.0 > 2.0 # => false
|
|
|
|
*
|
|
|
|
* <tt>Float::NAN > Float::NAN</tt> returns an implementation-dependent value.
|
2003-12-23 19:21:17 +03:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2016-11-22 08:21:12 +03:00
|
|
|
VALUE
|
|
|
|
rb_float_gt(VALUE x, VALUE y)
|
1999-01-20 07:59:39 +03:00
|
|
|
{
|
|
|
|
double a, b;
|
|
|
|
|
* include/ruby/ruby.h: introduce 2 macros:
RFLOAT_VALUE(v), DOUBLE2NUM(dbl).
Rename RFloat#value -> RFloat#double_value.
Do not touch RFloat#double_value directly.
* bignum.c, insns.def, marshal.c, math.c, numeric.c, object.c,
pack.c, parse.y, process.c, random.c, sprintf.c, string.c,
time.c: apply above changes.
* ext/dl/mkcallback.rb, ext/json/ext/generator/generator.c:
ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13913 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-11-13 19:00:53 +03:00
|
|
|
a = RFLOAT_VALUE(x);
|
2021-09-11 07:45:22 +03:00
|
|
|
if (RB_INTEGER_TYPE_P(y)) {
|
2012-07-16 13:41:25 +04:00
|
|
|
VALUE rel = rb_integer_float_cmp(y, x);
|
2012-07-16 10:02:21 +04:00
|
|
|
if (FIXNUM_P(rel))
|
2021-08-02 06:06:44 +03:00
|
|
|
return RBOOL(-FIX2LONG(rel) > 0);
|
2012-07-16 10:02:21 +04:00
|
|
|
return Qfalse;
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(y)) {
|
* include/ruby/ruby.h: introduce 2 macros:
RFLOAT_VALUE(v), DOUBLE2NUM(dbl).
Rename RFloat#value -> RFloat#double_value.
Do not touch RFloat#double_value directly.
* bignum.c, insns.def, marshal.c, math.c, numeric.c, object.c,
pack.c, parse.y, process.c, random.c, sprintf.c, string.c,
time.c: apply above changes.
* ext/dl/mkcallback.rb, ext/json/ext/generator/generator.c:
ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13913 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-11-13 19:00:53 +03:00
|
|
|
b = RFLOAT_VALUE(y);
|
2019-12-02 08:58:43 +03:00
|
|
|
#if MSC_VERSION_BEFORE(1300)
|
2009-02-27 08:42:06 +03:00
|
|
|
if (isnan(b)) return Qfalse;
|
|
|
|
#endif
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
|
|
|
else {
|
2008-02-12 05:46:21 +03:00
|
|
|
return rb_num_coerce_relop(x, y, '>');
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
2019-12-02 08:58:43 +03:00
|
|
|
#if MSC_VERSION_BEFORE(1300)
|
2009-02-27 08:42:06 +03:00
|
|
|
if (isnan(a)) return Qfalse;
|
|
|
|
#endif
|
2021-09-15 02:11:05 +03:00
|
|
|
return RBOOL(a > b);
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
|
|
|
|
2003-12-23 19:21:17 +03:00
|
|
|
/*
|
2021-11-22 23:57:17 +03:00
|
|
|
* call-seq:
|
|
|
|
* self >= other -> true or false
|
2013-07-15 22:27:23 +04:00
|
|
|
*
|
2021-11-22 23:57:17 +03:00
|
|
|
* Returns +true+ if +self+ is numerically greater than or equal to +other+:
|
|
|
|
*
|
|
|
|
* 2.0 >= 1 # => true
|
|
|
|
* 2.0 >= 1.0 # => true
|
|
|
|
* 2.0 >= Rational(1, 2) # => true
|
|
|
|
* 2.0 >= 2.0 # => true
|
|
|
|
* 2.0 >= 2.1 # => false
|
|
|
|
*
|
|
|
|
* <tt>Float::NAN >= Float::NAN</tt> returns an implementation-dependent value.
|
2003-12-23 19:21:17 +03:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
flo_ge(VALUE x, VALUE y)
|
1999-01-20 07:59:39 +03:00
|
|
|
{
|
|
|
|
double a, b;
|
|
|
|
|
* include/ruby/ruby.h: introduce 2 macros:
RFLOAT_VALUE(v), DOUBLE2NUM(dbl).
Rename RFloat#value -> RFloat#double_value.
Do not touch RFloat#double_value directly.
* bignum.c, insns.def, marshal.c, math.c, numeric.c, object.c,
pack.c, parse.y, process.c, random.c, sprintf.c, string.c,
time.c: apply above changes.
* ext/dl/mkcallback.rb, ext/json/ext/generator/generator.c:
ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13913 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-11-13 19:00:53 +03:00
|
|
|
a = RFLOAT_VALUE(x);
|
2021-09-03 14:50:12 +03:00
|
|
|
if (RB_TYPE_P(y, T_FIXNUM) || RB_BIGNUM_TYPE_P(y)) {
|
2012-07-16 13:41:25 +04:00
|
|
|
VALUE rel = rb_integer_float_cmp(y, x);
|
2012-07-16 10:02:21 +04:00
|
|
|
if (FIXNUM_P(rel))
|
2021-08-02 06:06:44 +03:00
|
|
|
return RBOOL(-FIX2LONG(rel) >= 0);
|
2012-07-16 10:02:21 +04:00
|
|
|
return Qfalse;
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(y)) {
|
* include/ruby/ruby.h: introduce 2 macros:
RFLOAT_VALUE(v), DOUBLE2NUM(dbl).
Rename RFloat#value -> RFloat#double_value.
Do not touch RFloat#double_value directly.
* bignum.c, insns.def, marshal.c, math.c, numeric.c, object.c,
pack.c, parse.y, process.c, random.c, sprintf.c, string.c,
time.c: apply above changes.
* ext/dl/mkcallback.rb, ext/json/ext/generator/generator.c:
ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13913 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-11-13 19:00:53 +03:00
|
|
|
b = RFLOAT_VALUE(y);
|
2019-12-02 08:58:43 +03:00
|
|
|
#if MSC_VERSION_BEFORE(1300)
|
2009-02-27 08:42:06 +03:00
|
|
|
if (isnan(b)) return Qfalse;
|
|
|
|
#endif
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
|
|
|
else {
|
2015-10-12 03:08:58 +03:00
|
|
|
return rb_num_coerce_relop(x, y, idGE);
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
2019-12-02 08:58:43 +03:00
|
|
|
#if MSC_VERSION_BEFORE(1300)
|
2009-02-27 08:42:06 +03:00
|
|
|
if (isnan(a)) return Qfalse;
|
|
|
|
#endif
|
2021-09-15 02:11:05 +03:00
|
|
|
return RBOOL(a >= b);
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
|
|
|
|
2003-12-23 19:21:17 +03:00
|
|
|
/*
|
2021-11-22 23:57:17 +03:00
|
|
|
* call-seq:
|
|
|
|
* self < other -> true or false
|
|
|
|
*
|
|
|
|
* Returns +true+ if +self+ is numerically less than +other+:
|
|
|
|
*
|
|
|
|
* 2.0 < 3 # => true
|
|
|
|
* 2.0 < 3.0 # => true
|
|
|
|
* 2.0 < Rational(3, 1) # => true
|
|
|
|
* 2.0 < 2.0 # => false
|
2013-07-15 22:27:23 +04:00
|
|
|
*
|
2021-11-22 23:57:17 +03:00
|
|
|
* <tt>Float::NAN < Float::NAN</tt> returns an implementation-dependent value.
|
2003-12-23 19:21:17 +03:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
flo_lt(VALUE x, VALUE y)
|
1999-01-20 07:59:39 +03:00
|
|
|
{
|
|
|
|
double a, b;
|
|
|
|
|
* include/ruby/ruby.h: introduce 2 macros:
RFLOAT_VALUE(v), DOUBLE2NUM(dbl).
Rename RFloat#value -> RFloat#double_value.
Do not touch RFloat#double_value directly.
* bignum.c, insns.def, marshal.c, math.c, numeric.c, object.c,
pack.c, parse.y, process.c, random.c, sprintf.c, string.c,
time.c: apply above changes.
* ext/dl/mkcallback.rb, ext/json/ext/generator/generator.c:
ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13913 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-11-13 19:00:53 +03:00
|
|
|
a = RFLOAT_VALUE(x);
|
2021-09-11 07:45:22 +03:00
|
|
|
if (RB_INTEGER_TYPE_P(y)) {
|
2012-07-16 13:41:25 +04:00
|
|
|
VALUE rel = rb_integer_float_cmp(y, x);
|
2012-07-16 10:02:21 +04:00
|
|
|
if (FIXNUM_P(rel))
|
2021-08-02 06:06:44 +03:00
|
|
|
return RBOOL(-FIX2LONG(rel) < 0);
|
2012-07-16 10:02:21 +04:00
|
|
|
return Qfalse;
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(y)) {
|
* include/ruby/ruby.h: introduce 2 macros:
RFLOAT_VALUE(v), DOUBLE2NUM(dbl).
Rename RFloat#value -> RFloat#double_value.
Do not touch RFloat#double_value directly.
* bignum.c, insns.def, marshal.c, math.c, numeric.c, object.c,
pack.c, parse.y, process.c, random.c, sprintf.c, string.c,
time.c: apply above changes.
* ext/dl/mkcallback.rb, ext/json/ext/generator/generator.c:
ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13913 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-11-13 19:00:53 +03:00
|
|
|
b = RFLOAT_VALUE(y);
|
2019-12-02 08:58:43 +03:00
|
|
|
#if MSC_VERSION_BEFORE(1300)
|
2009-02-27 08:42:06 +03:00
|
|
|
if (isnan(b)) return Qfalse;
|
|
|
|
#endif
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
|
|
|
else {
|
2008-02-12 05:46:21 +03:00
|
|
|
return rb_num_coerce_relop(x, y, '<');
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
2019-12-02 08:58:43 +03:00
|
|
|
#if MSC_VERSION_BEFORE(1300)
|
2009-02-27 08:42:06 +03:00
|
|
|
if (isnan(a)) return Qfalse;
|
|
|
|
#endif
|
2021-09-15 02:11:05 +03:00
|
|
|
return RBOOL(a < b);
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
|
|
|
|
2003-12-23 19:21:17 +03:00
|
|
|
/*
|
2021-11-22 23:57:17 +03:00
|
|
|
* call-seq:
|
|
|
|
* self <= other -> true or false
|
|
|
|
*
|
|
|
|
* Returns +true+ if +self+ is numerically less than or equal to +other+:
|
2013-07-15 22:27:23 +04:00
|
|
|
*
|
2021-11-22 23:57:17 +03:00
|
|
|
* 2.0 <= 3 # => true
|
|
|
|
* 2.0 <= 3.0 # => true
|
|
|
|
* 2.0 <= Rational(3, 1) # => true
|
|
|
|
* 2.0 <= 2.0 # => true
|
|
|
|
* 2.0 <= 1.0 # => false
|
|
|
|
*
|
|
|
|
* <tt>Float::NAN <= Float::NAN</tt> returns an implementation-dependent value.
|
2003-12-23 19:21:17 +03:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
flo_le(VALUE x, VALUE y)
|
1999-01-20 07:59:39 +03:00
|
|
|
{
|
|
|
|
double a, b;
|
|
|
|
|
* include/ruby/ruby.h: introduce 2 macros:
RFLOAT_VALUE(v), DOUBLE2NUM(dbl).
Rename RFloat#value -> RFloat#double_value.
Do not touch RFloat#double_value directly.
* bignum.c, insns.def, marshal.c, math.c, numeric.c, object.c,
pack.c, parse.y, process.c, random.c, sprintf.c, string.c,
time.c: apply above changes.
* ext/dl/mkcallback.rb, ext/json/ext/generator/generator.c:
ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13913 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-11-13 19:00:53 +03:00
|
|
|
a = RFLOAT_VALUE(x);
|
2021-09-11 07:45:22 +03:00
|
|
|
if (RB_INTEGER_TYPE_P(y)) {
|
2012-07-16 13:41:25 +04:00
|
|
|
VALUE rel = rb_integer_float_cmp(y, x);
|
2012-07-16 10:02:21 +04:00
|
|
|
if (FIXNUM_P(rel))
|
2021-08-02 06:06:44 +03:00
|
|
|
return RBOOL(-FIX2LONG(rel) <= 0);
|
2012-07-16 10:02:21 +04:00
|
|
|
return Qfalse;
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(y)) {
|
* include/ruby/ruby.h: introduce 2 macros:
RFLOAT_VALUE(v), DOUBLE2NUM(dbl).
Rename RFloat#value -> RFloat#double_value.
Do not touch RFloat#double_value directly.
* bignum.c, insns.def, marshal.c, math.c, numeric.c, object.c,
pack.c, parse.y, process.c, random.c, sprintf.c, string.c,
time.c: apply above changes.
* ext/dl/mkcallback.rb, ext/json/ext/generator/generator.c:
ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13913 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-11-13 19:00:53 +03:00
|
|
|
b = RFLOAT_VALUE(y);
|
2019-12-02 08:58:43 +03:00
|
|
|
#if MSC_VERSION_BEFORE(1300)
|
2009-02-27 08:42:06 +03:00
|
|
|
if (isnan(b)) return Qfalse;
|
|
|
|
#endif
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
|
|
|
else {
|
2015-10-12 03:08:58 +03:00
|
|
|
return rb_num_coerce_relop(x, y, idLE);
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
2019-12-02 08:58:43 +03:00
|
|
|
#if MSC_VERSION_BEFORE(1300)
|
2009-02-27 08:42:06 +03:00
|
|
|
if (isnan(a)) return Qfalse;
|
|
|
|
#endif
|
2021-09-15 02:11:05 +03:00
|
|
|
return RBOOL(a <= b);
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
|
|
|
|
2003-12-23 19:21:17 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-22 23:57:17 +03:00
|
|
|
* eql?(other) -> true or false
|
|
|
|
*
|
|
|
|
* Returns +true+ if +other+ is a \Float with the same value as +self+,
|
|
|
|
* +false+ otherwise:
|
2013-07-15 22:27:23 +04:00
|
|
|
*
|
2021-11-22 23:57:17 +03:00
|
|
|
* 2.0.eql?(2.0) # => true
|
|
|
|
* 2.0.eql?(1.0) # => false
|
|
|
|
* 2.0.eql?(1) # => false
|
|
|
|
* 2.0.eql?(Rational(2, 1)) # => false
|
|
|
|
* 2.0.eql?(Complex(2, 0)) # => false
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-11-22 23:57:17 +03:00
|
|
|
* <tt>Float::NAN.eql?(Float::NAN)</tt> returns an implementation-dependent value.
|
2017-05-06 10:17:41 +03:00
|
|
|
*
|
2021-11-22 23:57:17 +03:00
|
|
|
* Related: Float#== (performs type conversions).
|
2003-12-23 19:21:17 +03:00
|
|
|
*/
|
|
|
|
|
2018-02-08 16:54:37 +03:00
|
|
|
MJIT_FUNC_EXPORTED VALUE
|
2017-05-25 08:29:35 +03:00
|
|
|
rb_float_eql(VALUE x, VALUE y)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2021-09-11 03:56:59 +03:00
|
|
|
if (RB_FLOAT_TYPE_P(y)) {
|
2009-02-27 08:42:06 +03:00
|
|
|
double a = RFLOAT_VALUE(x);
|
|
|
|
double b = RFLOAT_VALUE(y);
|
2019-12-02 08:58:43 +03:00
|
|
|
#if MSC_VERSION_BEFORE(1300)
|
2009-02-27 08:42:06 +03:00
|
|
|
if (isnan(a) || isnan(b)) return Qfalse;
|
|
|
|
#endif
|
2021-09-15 02:11:05 +03:00
|
|
|
return RBOOL(a == b);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
1999-01-20 07:59:39 +03:00
|
|
|
return Qfalse;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2017-05-25 08:29:35 +03:00
|
|
|
#define flo_eql rb_float_eql
|
|
|
|
|
2021-01-19 01:52:07 +03:00
|
|
|
MJIT_FUNC_EXPORTED VALUE
|
2016-11-16 07:25:35 +03:00
|
|
|
rb_float_abs(VALUE flt)
|
2000-07-06 11:21:26 +04:00
|
|
|
{
|
* include/ruby/ruby.h: introduce 2 macros:
RFLOAT_VALUE(v), DOUBLE2NUM(dbl).
Rename RFloat#value -> RFloat#double_value.
Do not touch RFloat#double_value directly.
* bignum.c, insns.def, marshal.c, math.c, numeric.c, object.c,
pack.c, parse.y, process.c, random.c, sprintf.c, string.c,
time.c: apply above changes.
* ext/dl/mkcallback.rb, ext/json/ext/generator/generator.c:
ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13913 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-11-13 19:00:53 +03:00
|
|
|
double val = fabs(RFLOAT_VALUE(flt));
|
2008-09-05 22:24:21 +04:00
|
|
|
return DBL2NUM(val);
|
2000-07-06 11:21:26 +04:00
|
|
|
}
|
|
|
|
|
2003-12-23 19:21:17 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-22 23:57:17 +03:00
|
|
|
* nan? -> true or false
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-11-22 23:57:17 +03:00
|
|
|
* Returns +true+ if +self+ is a NaN, +false+ otherwise.
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-11-22 23:57:17 +03:00
|
|
|
* f = -1.0 #=> -1.0
|
|
|
|
* f.nan? #=> false
|
|
|
|
* f = 0.0/0.0 #=> NaN
|
|
|
|
* f.nan? #=> true
|
2003-12-23 19:21:17 +03:00
|
|
|
*/
|
|
|
|
|
2002-06-04 11:34:19 +04:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
flo_is_nan_p(VALUE num)
|
2007-05-09 08:11:41 +04:00
|
|
|
{
|
* include/ruby/ruby.h: introduce 2 macros:
RFLOAT_VALUE(v), DOUBLE2NUM(dbl).
Rename RFloat#value -> RFloat#double_value.
Do not touch RFloat#double_value directly.
* bignum.c, insns.def, marshal.c, math.c, numeric.c, object.c,
pack.c, parse.y, process.c, random.c, sprintf.c, string.c,
time.c: apply above changes.
* ext/dl/mkcallback.rb, ext/json/ext/generator/generator.c:
ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13913 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-11-13 19:00:53 +03:00
|
|
|
double value = RFLOAT_VALUE(num);
|
2000-07-06 11:21:26 +04:00
|
|
|
|
2021-08-02 06:06:44 +03:00
|
|
|
return RBOOL(isnan(value));
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
|
|
|
|
2003-12-23 19:21:17 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-22 23:57:17 +03:00
|
|
|
* infinite? -> -1, 1, or nil
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-11-22 23:57:17 +03:00
|
|
|
* Returns:
|
|
|
|
*
|
|
|
|
* - 1, if +self+ is <tt>Infinity</tt>.
|
|
|
|
* - -1 if +self+ is <tt>-Infinity</tt>.
|
|
|
|
* - +nil+, otherwise.
|
|
|
|
*
|
|
|
|
* Examples:
|
|
|
|
*
|
|
|
|
* f = 1.0/0.0 # => Infinity
|
|
|
|
* f.infinite? # => 1
|
|
|
|
* f = -1.0/0.0 # => -Infinity
|
|
|
|
* f.infinite? # => -1
|
|
|
|
* f = 1.0 # => 1.0
|
|
|
|
* f.infinite? # => nil
|
|
|
|
* f = 0.0/0.0 # => NaN
|
|
|
|
* f.infinite? # => nil
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2003-12-23 19:21:17 +03:00
|
|
|
*/
|
|
|
|
|
2017-09-27 05:55:03 +03:00
|
|
|
VALUE
|
|
|
|
rb_flo_is_infinite_p(VALUE num)
|
2007-05-09 08:11:41 +04:00
|
|
|
{
|
* include/ruby/ruby.h: introduce 2 macros:
RFLOAT_VALUE(v), DOUBLE2NUM(dbl).
Rename RFloat#value -> RFloat#double_value.
Do not touch RFloat#double_value directly.
* bignum.c, insns.def, marshal.c, math.c, numeric.c, object.c,
pack.c, parse.y, process.c, random.c, sprintf.c, string.c,
time.c: apply above changes.
* ext/dl/mkcallback.rb, ext/json/ext/generator/generator.c:
ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13913 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-11-13 19:00:53 +03:00
|
|
|
double value = RFLOAT_VALUE(num);
|
2000-07-06 11:21:26 +04:00
|
|
|
|
2003-04-11 10:37:48 +04:00
|
|
|
if (isinf(value)) {
|
|
|
|
return INT2FIX( value < 0 ? -1 : 1 );
|
|
|
|
}
|
2000-07-06 11:21:26 +04:00
|
|
|
|
2003-04-11 10:37:48 +04:00
|
|
|
return Qnil;
|
2000-07-06 11:21:26 +04:00
|
|
|
}
|
|
|
|
|
2003-12-23 19:21:17 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-22 23:57:17 +03:00
|
|
|
* finite? -> true or false
|
|
|
|
*
|
2022-04-13 21:29:14 +03:00
|
|
|
* Returns +true+ if +self+ is not +Infinity+, +-Infinity+, or +NaN+,
|
2021-11-22 23:57:17 +03:00
|
|
|
* +false+ otherwise:
|
|
|
|
*
|
|
|
|
* f = 2.0 # => 2.0
|
|
|
|
* f.finite? # => true
|
|
|
|
* f = 1.0/0.0 # => Infinity
|
|
|
|
* f.finite? # => false
|
|
|
|
* f = -1.0/0.0 # => -Infinity
|
|
|
|
* f.finite? # => false
|
|
|
|
* f = 0.0/0.0 # => NaN
|
|
|
|
* f.finite? # => false
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2003-12-23 19:21:17 +03:00
|
|
|
*/
|
|
|
|
|
2017-09-27 05:38:51 +03:00
|
|
|
VALUE
|
|
|
|
rb_flo_is_finite_p(VALUE num)
|
2007-05-09 08:11:41 +04:00
|
|
|
{
|
* include/ruby/ruby.h: introduce 2 macros:
RFLOAT_VALUE(v), DOUBLE2NUM(dbl).
Rename RFloat#value -> RFloat#double_value.
Do not touch RFloat#double_value directly.
* bignum.c, insns.def, marshal.c, math.c, numeric.c, object.c,
pack.c, parse.y, process.c, random.c, sprintf.c, string.c,
time.c: apply above changes.
* ext/dl/mkcallback.rb, ext/json/ext/generator/generator.c:
ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13913 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-11-13 19:00:53 +03:00
|
|
|
double value = RFLOAT_VALUE(num);
|
2000-07-06 11:21:26 +04:00
|
|
|
|
2021-08-27 04:52:02 +03:00
|
|
|
return RBOOL(isfinite(value));
|
2000-07-06 11:21:26 +04:00
|
|
|
}
|
|
|
|
|
2020-11-16 07:22:47 +03:00
|
|
|
static VALUE
|
2020-11-17 16:53:41 +03:00
|
|
|
flo_nextafter(VALUE flo, double value)
|
2020-11-16 07:22:47 +03:00
|
|
|
{
|
|
|
|
double x, y;
|
|
|
|
x = NUM2DBL(flo);
|
2020-11-17 12:41:21 +03:00
|
|
|
y = nextafter(x, value);
|
2020-11-16 07:22:47 +03:00
|
|
|
return DBL2NUM(y);
|
|
|
|
}
|
|
|
|
|
2014-05-18 04:37:10 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-22 23:57:17 +03:00
|
|
|
* next_float -> float
|
2014-05-18 04:37:10 +04:00
|
|
|
*
|
2021-11-24 00:38:28 +03:00
|
|
|
* Returns the next-larger representable \Float.
|
|
|
|
*
|
|
|
|
* These examples show the internally stored values (64-bit hexadecimal)
|
|
|
|
* for each \Float +f+ and for the corresponding <tt>f.next_float</tt>:
|
|
|
|
*
|
|
|
|
* f = 0.0 # 0x0000000000000000
|
|
|
|
* f.next_float # 0x0000000000000001
|
|
|
|
*
|
|
|
|
* f = 0.01 # 0x3f847ae147ae147b
|
|
|
|
* f.next_float # 0x3f847ae147ae147c
|
|
|
|
*
|
|
|
|
* In the remaining examples here, the output is shown in the usual way
|
2021-11-24 17:34:30 +03:00
|
|
|
* (result +to_s+):
|
2021-11-24 00:38:28 +03:00
|
|
|
*
|
|
|
|
* 0.01.next_float # => 0.010000000000000002
|
|
|
|
* 1.0.next_float # => 1.0000000000000002
|
|
|
|
* 100.0.next_float # => 100.00000000000001
|
|
|
|
*
|
|
|
|
* f = 0.01
|
2021-11-24 17:34:30 +03:00
|
|
|
* (0..3).each_with_index {|i| printf "%2d %-20a %s\n", i, f, f.to_s; f = f.next_float }
|
2021-11-24 00:38:28 +03:00
|
|
|
*
|
|
|
|
* Output:
|
|
|
|
*
|
|
|
|
* 0 0x1.47ae147ae147bp-7 0.01
|
|
|
|
* 1 0x1.47ae147ae147cp-7 0.010000000000000002
|
|
|
|
* 2 0x1.47ae147ae147dp-7 0.010000000000000004
|
|
|
|
* 3 0x1.47ae147ae147ep-7 0.010000000000000005
|
|
|
|
*
|
|
|
|
* f = 0.0; 100.times { f += 0.1 }
|
|
|
|
* f # => 9.99999999999998 # should be 10.0 in the ideal world.
|
|
|
|
* 10-f # => 1.9539925233402755e-14 # the floating point error.
|
|
|
|
* 10.0.next_float-10 # => 1.7763568394002505e-15 # 1 ulp (unit in the last place).
|
|
|
|
* (10-f)/(10.0.next_float-10) # => 11.0 # the error is 11 ulp.
|
|
|
|
* (10-f)/(10*Float::EPSILON) # => 8.8 # approximation of the above.
|
|
|
|
* "%a" % 10 # => "0x1.4p+3"
|
|
|
|
* "%a" % f # => "0x1.3fffffffffff5p+3" # the last hex digit is 5. 16 - 5 = 11 ulp.
|
|
|
|
*
|
2021-11-24 17:34:30 +03:00
|
|
|
* Related: Float#prev_float
|
|
|
|
*
|
2014-05-18 04:37:10 +04:00
|
|
|
*/
|
|
|
|
static VALUE
|
|
|
|
flo_next_float(VALUE vx)
|
|
|
|
{
|
2020-11-17 16:53:41 +03:00
|
|
|
return flo_nextafter(vx, HUGE_VAL);
|
2014-05-18 04:37:10 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* float.prev_float -> float
|
|
|
|
*
|
2021-11-24 17:34:30 +03:00
|
|
|
* Returns the next-smaller representable \Float.
|
|
|
|
*
|
|
|
|
* These examples show the internally stored values (64-bit hexadecimal)
|
|
|
|
* for each \Float +f+ and for the corresponding <tt>f.pev_float</tt>:
|
|
|
|
*
|
|
|
|
* f = 5e-324 # 0x0000000000000001
|
|
|
|
* f.prev_float # 0x0000000000000000
|
|
|
|
*
|
|
|
|
* f = 0.01 # 0x3f847ae147ae147b
|
|
|
|
* f.prev_float # 0x3f847ae147ae147a
|
|
|
|
*
|
|
|
|
* In the remaining examples here, the output is shown in the usual way
|
|
|
|
* (result +to_s+):
|
|
|
|
*
|
|
|
|
* 0.01.prev_float # => 0.009999999999999998
|
|
|
|
* 1.0.prev_float # => 0.9999999999999999
|
|
|
|
* 100.0.prev_float # => 99.99999999999999
|
|
|
|
*
|
|
|
|
* f = 0.01
|
|
|
|
* (0..3).each_with_index {|i| printf "%2d %-20a %s\n", i, f, f.to_s; f = f.prev_float }
|
|
|
|
*
|
|
|
|
* Output:
|
|
|
|
*
|
|
|
|
* 0 0x1.47ae147ae147bp-7 0.01
|
|
|
|
* 1 0x1.47ae147ae147ap-7 0.009999999999999998
|
|
|
|
* 2 0x1.47ae147ae1479p-7 0.009999999999999997
|
|
|
|
* 3 0x1.47ae147ae1478p-7 0.009999999999999995
|
|
|
|
*
|
|
|
|
* Related: Float#next_float.
|
|
|
|
*
|
2014-05-18 04:37:10 +04:00
|
|
|
*/
|
|
|
|
static VALUE
|
|
|
|
flo_prev_float(VALUE vx)
|
|
|
|
{
|
2020-11-17 16:53:41 +03:00
|
|
|
return flo_nextafter(vx, -HUGE_VAL);
|
2014-05-18 04:37:10 +04:00
|
|
|
}
|
|
|
|
|
2020-12-09 12:48:59 +03:00
|
|
|
VALUE
|
|
|
|
rb_float_floor(VALUE num, int ndigits)
|
|
|
|
{
|
2021-07-26 20:45:56 +03:00
|
|
|
double number;
|
2020-12-09 12:48:59 +03:00
|
|
|
number = RFLOAT_VALUE(num);
|
|
|
|
if (number == 0.0) {
|
|
|
|
return ndigits > 0 ? DBL2NUM(number) : INT2FIX(0);
|
|
|
|
}
|
|
|
|
if (ndigits > 0) {
|
|
|
|
int binexp;
|
2021-07-26 20:45:56 +03:00
|
|
|
double f, mul, res;
|
2020-12-09 12:48:59 +03:00
|
|
|
frexp(number, &binexp);
|
|
|
|
if (float_round_overflow(ndigits, binexp)) return num;
|
|
|
|
if (number > 0.0 && float_round_underflow(ndigits, binexp))
|
|
|
|
return DBL2NUM(0.0);
|
|
|
|
f = pow(10, ndigits);
|
2021-07-26 20:45:56 +03:00
|
|
|
mul = floor(number * f);
|
|
|
|
res = (mul + 1) / f;
|
|
|
|
if (res > number)
|
|
|
|
res = mul / f;
|
|
|
|
return DBL2NUM(res);
|
2020-12-09 12:48:59 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
num = dbl2ival(floor(number));
|
|
|
|
if (ndigits < 0) num = rb_int_floor(num, ndigits);
|
|
|
|
return num;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-25 00:15:12 +03:00
|
|
|
static int
|
|
|
|
flo_ndigits(int argc, VALUE *argv)
|
|
|
|
{
|
|
|
|
if (rb_check_arity(argc, 0, 1)) {
|
|
|
|
return NUM2INT(argv[0]);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-12-23 19:21:17 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-25 00:15:12 +03:00
|
|
|
* floor(ndigits = 0) -> float or integer
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-11-25 00:15:12 +03:00
|
|
|
* Returns the largest number less than or equal to +self+ with
|
|
|
|
* a precision of +ndigits+ decimal digits.
|
2017-04-03 22:23:13 +03:00
|
|
|
*
|
2021-11-25 00:15:12 +03:00
|
|
|
* When +ndigits+ is positive, returns a float with +ndigits+
|
|
|
|
* digits after the decimal point (as available):
|
2016-04-13 09:54:38 +03:00
|
|
|
*
|
2021-11-25 00:15:12 +03:00
|
|
|
* f = 12345.6789
|
|
|
|
* f.floor(1) # => 12345.6
|
|
|
|
* f.floor(3) # => 12345.678
|
|
|
|
* f = -12345.6789
|
|
|
|
* f.floor(1) # => -12345.7
|
|
|
|
* f.floor(3) # => -12345.679
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-11-25 00:15:12 +03:00
|
|
|
* When +ndigits+ is non-positive, returns an integer with at least
|
|
|
|
* <code>ndigits.abs</code> trailing zeros:
|
2016-04-13 09:54:38 +03:00
|
|
|
*
|
2021-11-25 00:15:12 +03:00
|
|
|
* f = 12345.6789
|
|
|
|
* f.floor(0) # => 12345
|
|
|
|
* f.floor(-3) # => 12000
|
|
|
|
* f = -12345.6789
|
|
|
|
* f.floor(0) # => -12346
|
|
|
|
* f.floor(-3) # => -13000
|
2017-04-03 22:23:13 +03:00
|
|
|
*
|
2021-11-25 00:15:12 +03:00
|
|
|
* Note that the limited precision of floating-point arithmetic
|
|
|
|
* may lead to surprising results:
|
2017-04-09 16:28:11 +03:00
|
|
|
*
|
|
|
|
* (0.3 / 0.1).floor #=> 2 (!)
|
2021-11-25 00:15:12 +03:00
|
|
|
*
|
|
|
|
* Related: Float#ceil.
|
|
|
|
*
|
2003-12-23 19:21:17 +03:00
|
|
|
*/
|
|
|
|
|
2021-10-03 11:16:58 +03:00
|
|
|
static VALUE
|
|
|
|
flo_floor(int argc, VALUE *argv, VALUE num)
|
|
|
|
{
|
|
|
|
int ndigits = flo_ndigits(argc, argv);
|
2020-12-09 12:48:59 +03:00
|
|
|
return rb_float_floor(num, ndigits);
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
|
|
|
|
2003-12-23 19:21:17 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-25 00:15:12 +03:00
|
|
|
* ceil(ndigits = 0) -> float or integer
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-11-25 00:15:12 +03:00
|
|
|
* Returns the smallest number greater than or equal to +self+ with
|
|
|
|
* a precision of +ndigits+ decimal digits.
|
2017-04-03 22:23:13 +03:00
|
|
|
*
|
2021-11-25 00:15:12 +03:00
|
|
|
* When +ndigits+ is positive, returns a float with +ndigits+
|
|
|
|
* digits after the decimal point (as available):
|
2016-04-13 09:56:36 +03:00
|
|
|
*
|
2021-11-25 00:15:12 +03:00
|
|
|
* f = 12345.6789
|
|
|
|
* f.ceil(1) # => 12345.7
|
|
|
|
* f.ceil(3) # => 12345.679
|
|
|
|
* f = -12345.6789
|
|
|
|
* f.ceil(1) # => -12345.6
|
|
|
|
* f.ceil(3) # => -12345.678
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-11-25 00:15:12 +03:00
|
|
|
* When +ndigits+ is non-positive, returns an integer with at least
|
|
|
|
* <code>ndigits.abs</code> trailing zeros:
|
2017-04-03 22:23:13 +03:00
|
|
|
*
|
2021-11-25 00:15:12 +03:00
|
|
|
* f = 12345.6789
|
|
|
|
* f.ceil(0) # => 12346
|
|
|
|
* f.ceil(-3) # => 13000
|
|
|
|
* f = -12345.6789
|
|
|
|
* f.ceil(0) # => -12345
|
|
|
|
* f.ceil(-3) # => -12000
|
2017-04-03 22:23:13 +03:00
|
|
|
*
|
2021-11-25 00:15:12 +03:00
|
|
|
* Note that the limited precision of floating-point arithmetic
|
|
|
|
* may lead to surprising results:
|
2017-04-09 16:28:11 +03:00
|
|
|
*
|
|
|
|
* (2.1 / 0.7).ceil #=> 4 (!)
|
2021-11-25 00:15:12 +03:00
|
|
|
*
|
|
|
|
* Related: Float#floor.
|
|
|
|
*
|
2003-12-23 19:21:17 +03:00
|
|
|
*/
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
static VALUE
|
2016-04-13 09:56:36 +03:00
|
|
|
flo_ceil(int argc, VALUE *argv, VALUE num)
|
1999-01-20 07:59:39 +03:00
|
|
|
{
|
2021-10-03 11:16:58 +03:00
|
|
|
int ndigits = flo_ndigits(argc, argv);
|
2019-08-02 05:25:41 +03:00
|
|
|
return rb_float_ceil(num, ndigits);
|
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
|
|
|
rb_float_ceil(VALUE num, int ndigits)
|
|
|
|
{
|
|
|
|
double number, f;
|
|
|
|
|
2016-04-13 09:56:36 +03:00
|
|
|
number = RFLOAT_VALUE(num);
|
2017-05-27 04:26:31 +03:00
|
|
|
if (number == 0.0) {
|
|
|
|
return ndigits > 0 ? DBL2NUM(number) : INT2FIX(0);
|
2016-04-13 09:56:36 +03:00
|
|
|
}
|
2017-05-27 04:26:31 +03:00
|
|
|
if (ndigits > 0) {
|
|
|
|
int binexp;
|
|
|
|
frexp(number, &binexp);
|
|
|
|
if (float_round_overflow(ndigits, binexp)) return num;
|
|
|
|
if (number < 0.0 && float_round_underflow(ndigits, binexp))
|
|
|
|
return DBL2NUM(0.0);
|
|
|
|
f = pow(10, ndigits);
|
|
|
|
f = ceil(number * f) / f;
|
|
|
|
return DBL2NUM(f);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
num = dbl2ival(ceil(number));
|
|
|
|
if (ndigits < 0) num = rb_int_ceil(num, ndigits);
|
|
|
|
return num;
|
2016-04-13 09:56:36 +03:00
|
|
|
}
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
|
|
|
|
2016-04-13 08:12:01 +03:00
|
|
|
static int
|
|
|
|
int_round_zero_p(VALUE num, int ndigits)
|
|
|
|
{
|
|
|
|
long bytes;
|
|
|
|
/* If 10**N / 2 > num, then return 0 */
|
|
|
|
/* We have log_256(10) > 0.415241 and log_256(1/2) = -0.125, so */
|
|
|
|
if (FIXNUM_P(num)) {
|
|
|
|
bytes = sizeof(long);
|
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(num)) {
|
2016-04-13 08:12:01 +03:00
|
|
|
bytes = rb_big_size(num);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
bytes = NUM2LONG(rb_funcall(num, idSize, 0));
|
|
|
|
}
|
|
|
|
return (-0.415241 * ndigits - 0.125 > bytes);
|
|
|
|
}
|
|
|
|
|
2016-11-05 12:49:39 +03:00
|
|
|
static SIGNED_VALUE
|
|
|
|
int_round_half_even(SIGNED_VALUE x, SIGNED_VALUE y)
|
|
|
|
{
|
|
|
|
SIGNED_VALUE z = +(x + y / 2) / y;
|
|
|
|
if ((z * y - x) * 2 == y) {
|
|
|
|
z &= ~1;
|
|
|
|
}
|
|
|
|
return z * y;
|
|
|
|
}
|
|
|
|
|
|
|
|
static SIGNED_VALUE
|
|
|
|
int_round_half_up(SIGNED_VALUE x, SIGNED_VALUE y)
|
|
|
|
{
|
|
|
|
return (x + y / 2) / y * y;
|
|
|
|
}
|
|
|
|
|
2016-11-25 09:28:00 +03:00
|
|
|
static SIGNED_VALUE
|
|
|
|
int_round_half_down(SIGNED_VALUE x, SIGNED_VALUE y)
|
|
|
|
{
|
|
|
|
return (x + y / 2 - 1) / y * y;
|
|
|
|
}
|
|
|
|
|
2016-11-18 09:29:51 +03:00
|
|
|
static int
|
|
|
|
int_half_p_half_even(VALUE num, VALUE n, VALUE f)
|
|
|
|
{
|
2017-12-04 05:35:40 +03:00
|
|
|
return (int)rb_int_odd_p(rb_int_idiv(n, f));
|
2016-11-18 09:29:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
int_half_p_half_up(VALUE num, VALUE n, VALUE f)
|
|
|
|
{
|
|
|
|
return int_pos_p(num);
|
|
|
|
}
|
|
|
|
|
2016-11-25 09:28:00 +03:00
|
|
|
static int
|
|
|
|
int_half_p_half_down(VALUE num, VALUE n, VALUE f)
|
|
|
|
{
|
|
|
|
return int_neg_p(num);
|
|
|
|
}
|
|
|
|
|
2011-09-05 00:14:00 +04:00
|
|
|
/*
|
|
|
|
* Assumes num is an Integer, ndigits <= 0
|
|
|
|
*/
|
2019-11-18 06:13:08 +03:00
|
|
|
static VALUE
|
2016-11-05 12:49:39 +03:00
|
|
|
rb_int_round(VALUE num, int ndigits, enum ruby_num_rounding_mode mode)
|
2011-09-05 00:14:00 +04:00
|
|
|
{
|
|
|
|
VALUE n, f, h, r;
|
2016-04-13 08:12:01 +03:00
|
|
|
|
|
|
|
if (int_round_zero_p(num, ndigits)) {
|
2011-09-05 00:14:00 +04:00
|
|
|
return INT2FIX(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
f = int_pow(10, -ndigits);
|
|
|
|
if (FIXNUM_P(num) && FIXNUM_P(f)) {
|
|
|
|
SIGNED_VALUE x = FIX2LONG(num), y = FIX2LONG(f);
|
|
|
|
int neg = x < 0;
|
|
|
|
if (neg) x = -x;
|
2016-11-18 09:29:51 +03:00
|
|
|
x = ROUND_CALL(mode, int_round, (x, y));
|
2011-09-05 00:14:00 +04:00
|
|
|
if (neg) x = -x;
|
|
|
|
return LONG2NUM(x);
|
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
if (RB_FLOAT_TYPE_P(f)) {
|
2011-09-05 00:14:00 +04:00
|
|
|
/* then int_pow overflow */
|
|
|
|
return INT2FIX(0);
|
|
|
|
}
|
2016-03-26 04:54:50 +03:00
|
|
|
h = rb_int_idiv(f, INT2FIX(2));
|
|
|
|
r = rb_int_modulo(num, f);
|
|
|
|
n = rb_int_minus(num, r);
|
2016-11-12 04:29:01 +03:00
|
|
|
r = rb_int_cmp(r, h);
|
2016-11-05 12:49:39 +03:00
|
|
|
if (FIXNUM_POSITIVE_P(r) ||
|
2016-11-18 09:29:51 +03:00
|
|
|
(FIXNUM_ZERO_P(r) && ROUND_CALL(mode, int_half_p, (num, n, f)))) {
|
2016-03-26 04:54:50 +03:00
|
|
|
n = rb_int_plus(n, f);
|
2011-09-05 00:14:00 +04:00
|
|
|
}
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2020-06-16 11:47:59 +03:00
|
|
|
static VALUE
|
2016-04-13 09:47:55 +03:00
|
|
|
rb_int_floor(VALUE num, int ndigits)
|
|
|
|
{
|
|
|
|
VALUE f;
|
|
|
|
|
|
|
|
if (int_round_zero_p(num, ndigits))
|
|
|
|
return INT2FIX(0);
|
|
|
|
f = int_pow(10, -ndigits);
|
|
|
|
if (FIXNUM_P(num) && FIXNUM_P(f)) {
|
|
|
|
SIGNED_VALUE x = FIX2LONG(num), y = FIX2LONG(f);
|
|
|
|
int neg = x < 0;
|
|
|
|
if (neg) x = -x + y - 1;
|
|
|
|
x = x / y * y;
|
|
|
|
if (neg) x = -x;
|
|
|
|
return LONG2NUM(x);
|
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
if (RB_FLOAT_TYPE_P(f)) {
|
2016-04-13 09:47:55 +03:00
|
|
|
/* then int_pow overflow */
|
|
|
|
return INT2FIX(0);
|
|
|
|
}
|
|
|
|
return rb_int_minus(num, rb_int_modulo(num, f));
|
|
|
|
}
|
2011-09-05 00:14:29 +04:00
|
|
|
|
2020-06-16 11:47:59 +03:00
|
|
|
static VALUE
|
2016-04-13 09:50:24 +03:00
|
|
|
rb_int_ceil(VALUE num, int ndigits)
|
|
|
|
{
|
|
|
|
VALUE f;
|
|
|
|
|
|
|
|
if (int_round_zero_p(num, ndigits))
|
|
|
|
return INT2FIX(0);
|
|
|
|
f = int_pow(10, -ndigits);
|
|
|
|
if (FIXNUM_P(num) && FIXNUM_P(f)) {
|
|
|
|
SIGNED_VALUE x = FIX2LONG(num), y = FIX2LONG(f);
|
|
|
|
int neg = x < 0;
|
|
|
|
if (neg) x = -x;
|
|
|
|
else x += y - 1;
|
|
|
|
x = (x / y) * y;
|
|
|
|
if (neg) x = -x;
|
|
|
|
return LONG2NUM(x);
|
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
if (RB_FLOAT_TYPE_P(f)) {
|
2016-04-13 09:50:24 +03:00
|
|
|
/* then int_pow overflow */
|
|
|
|
return INT2FIX(0);
|
|
|
|
}
|
|
|
|
return rb_int_plus(num, rb_int_minus(f, rb_int_modulo(num, f)));
|
|
|
|
}
|
|
|
|
|
2016-04-18 06:55:33 +03:00
|
|
|
VALUE
|
|
|
|
rb_int_truncate(VALUE num, int ndigits)
|
|
|
|
{
|
|
|
|
VALUE f;
|
|
|
|
VALUE m;
|
|
|
|
|
|
|
|
if (int_round_zero_p(num, ndigits))
|
|
|
|
return INT2FIX(0);
|
|
|
|
f = int_pow(10, -ndigits);
|
|
|
|
if (FIXNUM_P(num) && FIXNUM_P(f)) {
|
|
|
|
SIGNED_VALUE x = FIX2LONG(num), y = FIX2LONG(f);
|
|
|
|
int neg = x < 0;
|
|
|
|
if (neg) x = -x;
|
|
|
|
x = x / y * y;
|
|
|
|
if (neg) x = -x;
|
|
|
|
return LONG2NUM(x);
|
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
if (RB_FLOAT_TYPE_P(f)) {
|
2016-04-18 06:55:33 +03:00
|
|
|
/* then int_pow overflow */
|
|
|
|
return INT2FIX(0);
|
|
|
|
}
|
|
|
|
m = rb_int_modulo(num, f);
|
|
|
|
if (int_neg_p(num)) {
|
|
|
|
return rb_int_plus(num, rb_int_minus(f, m));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return rb_int_minus(num, m);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-12-23 19:21:17 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-25 00:15:12 +03:00
|
|
|
* round(ndigits = 0, half: :up]) -> integer or float
|
|
|
|
*
|
|
|
|
* Returns +self+ rounded to the nearest value with
|
|
|
|
* a precision of +ndigits+ decimal digits.
|
|
|
|
*
|
|
|
|
* When +ndigits+ is non-negative, returns a float with +ndigits+
|
|
|
|
* after the decimal point (as available):
|
|
|
|
*
|
|
|
|
* f = 12345.6789
|
|
|
|
* f.round(1) # => 12345.7
|
|
|
|
* f.round(3) # => 12345.679
|
|
|
|
* f = -12345.6789
|
|
|
|
* f.round(1) # => -12345.7
|
|
|
|
* f.round(3) # => -12345.679
|
|
|
|
*
|
|
|
|
* When +ndigits+ is negative, returns an integer
|
|
|
|
* with at least <tt>ndigits.abs</tt> trailing zeros:
|
|
|
|
*
|
|
|
|
* f = 12345.6789
|
|
|
|
* f.round(0) # => 12346
|
|
|
|
* f.round(-3) # => 12000
|
|
|
|
* f = -12345.6789
|
|
|
|
* f.round(0) # => -12346
|
|
|
|
* f.round(-3) # => -12000
|
|
|
|
*
|
|
|
|
* If keyword argument +half+ is given,
|
|
|
|
* and +self+ is equidistant from the two candidate values,
|
|
|
|
* the rounding is according to the given +half+ value:
|
|
|
|
*
|
|
|
|
* - +:up+ or +nil+: round away from zero:
|
|
|
|
*
|
|
|
|
* 2.5.round(half: :up) # => 3
|
|
|
|
* 3.5.round(half: :up) # => 4
|
|
|
|
* (-2.5).round(half: :up) # => -3
|
|
|
|
*
|
|
|
|
* - +:down+: round toward zero:
|
|
|
|
*
|
|
|
|
* 2.5.round(half: :down) # => 2
|
|
|
|
* 3.5.round(half: :down) # => 3
|
|
|
|
* (-2.5).round(half: :down) # => -2
|
|
|
|
*
|
|
|
|
* - +:even+: round toward the candidate whose last nonzero digit is even:
|
|
|
|
*
|
|
|
|
* 2.5.round(half: :even) # => 2
|
|
|
|
* 3.5.round(half: :even) # => 4
|
|
|
|
* (-2.5).round(half: :even) # => -2
|
|
|
|
*
|
|
|
|
* Raises and exception if the value for +half+ is invalid.
|
|
|
|
*
|
|
|
|
* Related: Float#truncate.
|
|
|
|
*
|
2003-12-23 19:21:17 +03:00
|
|
|
*/
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
static VALUE
|
2007-05-31 21:01:15 +04:00
|
|
|
flo_round(int argc, VALUE *argv, VALUE num)
|
1999-01-20 07:59:39 +03:00
|
|
|
{
|
2016-07-07 10:37:55 +03:00
|
|
|
double number, f, x;
|
2016-11-05 12:49:39 +03:00
|
|
|
VALUE nd, opt;
|
2011-03-22 04:08:49 +03:00
|
|
|
int ndigits = 0;
|
2016-11-05 12:49:39 +03:00
|
|
|
enum ruby_num_rounding_mode mode;
|
1999-01-20 07:59:39 +03:00
|
|
|
|
2016-11-05 12:49:39 +03:00
|
|
|
if (rb_scan_args(argc, argv, "01:", &nd, &opt)) {
|
|
|
|
ndigits = NUM2INT(nd);
|
2007-05-31 21:01:15 +04:00
|
|
|
}
|
2016-11-05 12:49:39 +03:00
|
|
|
mode = rb_num_get_rounding_option(opt);
|
2017-05-27 04:26:31 +03:00
|
|
|
number = RFLOAT_VALUE(num);
|
|
|
|
if (number == 0.0) {
|
|
|
|
return ndigits > 0 ? DBL2NUM(number) : INT2FIX(0);
|
|
|
|
}
|
2011-09-05 00:14:29 +04:00
|
|
|
if (ndigits < 0) {
|
2016-11-05 12:49:39 +03:00
|
|
|
return rb_int_round(flo_to_i(num), ndigits, mode);
|
2011-09-05 00:14:29 +04:00
|
|
|
}
|
|
|
|
if (ndigits == 0) {
|
2016-11-18 09:29:51 +03:00
|
|
|
x = ROUND_CALL(mode, round, (number, 1.0));
|
2016-11-05 12:49:39 +03:00
|
|
|
return dbl2ival(x);
|
2011-09-05 00:14:29 +04:00
|
|
|
}
|
2017-05-27 04:26:31 +03:00
|
|
|
if (isfinite(number)) {
|
|
|
|
int binexp;
|
|
|
|
frexp(number, &binexp);
|
|
|
|
if (float_round_overflow(ndigits, binexp)) return num;
|
|
|
|
if (float_round_underflow(ndigits, binexp)) return DBL2NUM(0);
|
2021-07-26 21:20:27 +03:00
|
|
|
if (ndigits > 14) {
|
|
|
|
/* In this case, pow(10, ndigits) may not be accurate. */
|
|
|
|
return rb_flo_round_by_rational(argc, argv, num);
|
|
|
|
}
|
2017-05-27 04:26:31 +03:00
|
|
|
f = pow(10, ndigits);
|
|
|
|
x = ROUND_CALL(mode, round, (number, f));
|
|
|
|
return DBL2NUM(x / f);
|
|
|
|
}
|
|
|
|
return num;
|
2016-04-13 05:41:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2017-05-27 04:26:31 +03:00
|
|
|
float_round_overflow(int ndigits, int binexp)
|
2016-04-13 05:41:24 +03:00
|
|
|
{
|
|
|
|
enum {float_dig = DBL_DIG+2};
|
2011-08-31 08:13:00 +04:00
|
|
|
|
|
|
|
/* Let `exp` be such that `number` is written as:"0.#{digits}e#{exp}",
|
|
|
|
i.e. such that 10 ** (exp - 1) <= |number| < 10 ** exp
|
2011-09-01 20:07:16 +04:00
|
|
|
Recall that up to float_dig digits can be needed to represent a double,
|
|
|
|
so if ndigits + exp >= float_dig, the intermediate value (number * 10 ** ndigits)
|
2011-08-31 08:13:00 +04:00
|
|
|
will be an integer and thus the result is the original number.
|
|
|
|
If ndigits + exp <= 0, the result is 0 or "1e#{exp}", so
|
|
|
|
if ndigits + exp < 0, the result is 0.
|
|
|
|
We have:
|
|
|
|
2 ** (binexp-1) <= |number| < 2 ** binexp
|
|
|
|
10 ** ((binexp-1)/log_2(10)) <= |number| < 10 ** (binexp/log_2(10))
|
|
|
|
If binexp >= 0, and since log_2(10) = 3.322259:
|
|
|
|
10 ** (binexp/4 - 1) < |number| < 10 ** (binexp/3)
|
2011-09-06 01:44:42 +04:00
|
|
|
floor(binexp/4) <= exp <= ceil(binexp/3)
|
2011-08-31 08:13:00 +04:00
|
|
|
If binexp <= 0, swap the /4 and the /3
|
2011-09-06 01:44:42 +04:00
|
|
|
So if ndigits + floor(binexp/(4 or 3)) >= float_dig, the result is number
|
|
|
|
If ndigits + ceil(binexp/(3 or 4)) < 0 the result is 0
|
2011-08-31 08:13:00 +04:00
|
|
|
*/
|
2017-05-27 04:26:31 +03:00
|
|
|
if (ndigits >= float_dig - (binexp > 0 ? binexp / 4 : binexp / 3 - 1)) {
|
2016-04-13 05:41:24 +03:00
|
|
|
return TRUE;
|
2011-08-31 08:13:00 +04:00
|
|
|
}
|
2017-05-27 04:26:31 +03:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
float_round_underflow(int ndigits, int binexp)
|
|
|
|
{
|
2011-09-06 01:44:42 +04:00
|
|
|
if (ndigits < - (binexp > 0 ? binexp / 3 + 1 : binexp / 4)) {
|
2016-04-13 05:41:24 +03:00
|
|
|
return TRUE;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2016-04-13 05:41:24 +03:00
|
|
|
return FALSE;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2003-12-23 19:21:17 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-25 00:15:12 +03:00
|
|
|
* to_i -> integer
|
2013-07-15 22:27:23 +04:00
|
|
|
*
|
2021-11-25 00:15:12 +03:00
|
|
|
* Returns +self+ truncated to an Integer.
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-11-25 00:15:12 +03:00
|
|
|
* 1.2.to_i # => 1
|
|
|
|
* (-1.2).to_i # => -1
|
2017-04-09 16:28:11 +03:00
|
|
|
*
|
2021-11-25 00:15:12 +03:00
|
|
|
* Note that the limited precision of floating-point arithmetic
|
|
|
|
* may lead to surprising results:
|
2017-04-09 16:28:11 +03:00
|
|
|
*
|
2021-11-25 00:15:12 +03:00
|
|
|
* (0.3 / 0.1).to_i # => 2 (!)
|
2017-05-06 10:17:41 +03:00
|
|
|
*
|
2021-11-25 00:15:12 +03:00
|
|
|
* Float#to_int is an alias for Float#to_i.
|
2003-12-23 19:21:17 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
2016-04-18 06:56:33 +03:00
|
|
|
flo_to_i(VALUE num)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
* include/ruby/ruby.h: introduce 2 macros:
RFLOAT_VALUE(v), DOUBLE2NUM(dbl).
Rename RFloat#value -> RFloat#double_value.
Do not touch RFloat#double_value directly.
* bignum.c, insns.def, marshal.c, math.c, numeric.c, object.c,
pack.c, parse.y, process.c, random.c, sprintf.c, string.c,
time.c: apply above changes.
* ext/dl/mkcallback.rb, ext/json/ext/generator/generator.c:
ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13913 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-11-13 19:00:53 +03:00
|
|
|
double f = RFLOAT_VALUE(num);
|
2000-07-06 11:21:26 +04:00
|
|
|
|
|
|
|
if (f > 0.0) f = floor(f);
|
|
|
|
if (f < 0.0) f = ceil(f);
|
|
|
|
|
2017-05-26 20:11:15 +03:00
|
|
|
return dbl2ival(f);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2016-04-18 06:56:33 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-25 00:15:12 +03:00
|
|
|
* truncate(ndigits = 0) -> float or integer
|
|
|
|
*
|
|
|
|
* Returns +self+ truncated (toward zero) to
|
|
|
|
* a precision of +ndigits+ decimal digits.
|
2016-04-18 06:56:33 +03:00
|
|
|
*
|
2021-11-25 00:15:12 +03:00
|
|
|
* When +ndigits+ is positive, returns a float with +ndigits+ digits
|
|
|
|
* after the decimal point (as available):
|
2017-04-03 22:23:13 +03:00
|
|
|
*
|
2021-11-25 00:15:12 +03:00
|
|
|
* f = 12345.6789
|
|
|
|
* f.truncate(1) # => 12345.6
|
|
|
|
* f.truncate(3) # => 12345.678
|
|
|
|
* f = -12345.6789
|
|
|
|
* f.truncate(1) # => -12345.6
|
|
|
|
* f.truncate(3) # => -12345.678
|
2017-04-03 22:23:13 +03:00
|
|
|
*
|
2021-11-25 00:15:12 +03:00
|
|
|
* When +ndigits+ is negative, returns an integer
|
|
|
|
* with at least <tt>ndigits.abs</tt> trailing zeros:
|
2016-04-18 06:56:33 +03:00
|
|
|
*
|
2021-11-25 00:15:12 +03:00
|
|
|
* f = 12345.6789
|
|
|
|
* f.truncate(0) # => 12345
|
|
|
|
* f.truncate(-3) # => 12000
|
|
|
|
* f = -12345.6789
|
|
|
|
* f.truncate(0) # => -12345
|
|
|
|
* f.truncate(-3) # => -12000
|
2017-04-09 16:28:11 +03:00
|
|
|
*
|
2021-11-25 00:15:12 +03:00
|
|
|
* Note that the limited precision of floating-point arithmetic
|
|
|
|
* may lead to surprising results:
|
2017-04-09 16:28:11 +03:00
|
|
|
*
|
|
|
|
* (0.3 / 0.1).truncate #=> 2 (!)
|
2021-11-25 00:15:12 +03:00
|
|
|
*
|
|
|
|
* Related: Float#round.
|
|
|
|
*
|
2016-04-18 06:56:33 +03:00
|
|
|
*/
|
|
|
|
static VALUE
|
|
|
|
flo_truncate(int argc, VALUE *argv, VALUE num)
|
|
|
|
{
|
|
|
|
if (signbit(RFLOAT_VALUE(num)))
|
|
|
|
return flo_ceil(argc, argv, num);
|
|
|
|
else
|
|
|
|
return flo_floor(argc, argv, num);
|
|
|
|
}
|
|
|
|
|
2003-12-27 08:46:46 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-10-28 23:11:11 +03:00
|
|
|
* floor(digits = 0) -> integer or float
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-10-28 23:11:11 +03:00
|
|
|
* Returns the largest number that is less than or equal to +self+ with
|
|
|
|
* a precision of +digits+ decimal digits.
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-10-28 23:11:11 +03:00
|
|
|
* \Numeric implements this by converting +self+ to a Float and
|
2017-04-03 22:23:13 +03:00
|
|
|
* invoking Float#floor.
|
2003-12-27 08:46:46 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
2016-04-18 06:57:34 +03:00
|
|
|
num_floor(int argc, VALUE *argv, VALUE num)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2016-04-18 06:57:34 +03:00
|
|
|
return flo_floor(argc, argv, rb_Float(num));
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
|
|
|
|
2003-12-27 08:46:46 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-10-28 23:11:11 +03:00
|
|
|
* ceil(digits = 0) -> integer or float
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-10-28 23:11:11 +03:00
|
|
|
* Returns the smallest number that is greater than or equal to +self+ with
|
|
|
|
* a precision of +digits+ decimal digits.
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-10-28 23:11:11 +03:00
|
|
|
* \Numeric implements this by converting +self+ to a Float and
|
2017-04-03 22:23:13 +03:00
|
|
|
* invoking Float#ceil.
|
2003-12-27 08:46:46 +03:00
|
|
|
*/
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
static VALUE
|
2016-04-18 06:57:34 +03:00
|
|
|
num_ceil(int argc, VALUE *argv, VALUE num)
|
1999-01-20 07:59:39 +03:00
|
|
|
{
|
2016-04-18 06:57:34 +03:00
|
|
|
return flo_ceil(argc, argv, rb_Float(num));
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2003-12-27 08:46:46 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-10-28 23:11:11 +03:00
|
|
|
* round(digits = 0) -> integer or float
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-10-28 23:11:11 +03:00
|
|
|
* Returns +self+ rounded to the nearest value with
|
|
|
|
* a precision of +digits+ decimal digits.
|
2013-07-15 22:27:23 +04:00
|
|
|
*
|
2021-10-28 23:11:11 +03:00
|
|
|
* \Numeric implements this by converting +self+ to a Float and
|
2017-04-03 22:19:20 +03:00
|
|
|
* invoking Float#round.
|
2003-12-27 08:46:46 +03:00
|
|
|
*/
|
|
|
|
|
2000-07-06 11:21:26 +04:00
|
|
|
static VALUE
|
2007-05-31 21:01:15 +04:00
|
|
|
num_round(int argc, VALUE* argv, VALUE num)
|
2000-07-06 11:21:26 +04:00
|
|
|
{
|
2007-06-01 06:32:17 +04:00
|
|
|
return flo_round(argc, argv, rb_Float(num));
|
2000-06-12 11:48:31 +04:00
|
|
|
}
|
|
|
|
|
2003-12-27 08:46:46 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-10-28 23:11:11 +03:00
|
|
|
* truncate(digits = 0) -> integer or float
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-10-28 23:11:11 +03:00
|
|
|
* Returns +self+ truncated (toward zero) to
|
|
|
|
* a precision of +digits+ decimal digits.
|
2013-07-15 22:27:23 +04:00
|
|
|
*
|
2021-10-28 23:11:11 +03:00
|
|
|
* \Numeric implements this by converting +self+ to a Float and
|
2017-04-03 22:23:13 +03:00
|
|
|
* invoking Float#truncate.
|
2003-12-27 08:46:46 +03:00
|
|
|
*/
|
|
|
|
|
2000-07-06 11:21:26 +04:00
|
|
|
static VALUE
|
2016-04-18 06:57:34 +03:00
|
|
|
num_truncate(int argc, VALUE *argv, VALUE num)
|
2000-07-06 11:21:26 +04:00
|
|
|
{
|
2016-04-18 06:57:34 +03:00
|
|
|
return flo_truncate(argc, argv, rb_Float(num));
|
2000-06-12 11:48:31 +04:00
|
|
|
}
|
|
|
|
|
2019-01-30 09:05:57 +03:00
|
|
|
double
|
2012-11-07 02:50:30 +04:00
|
|
|
ruby_float_step_size(double beg, double end, double unit, int excl)
|
|
|
|
{
|
2012-11-06 21:14:16 +04:00
|
|
|
const double epsilon = DBL_EPSILON;
|
2021-11-08 10:05:04 +03:00
|
|
|
double d, n, err;
|
2012-11-06 21:14:16 +04:00
|
|
|
|
2018-11-16 04:52:39 +03:00
|
|
|
if (unit == 0) {
|
|
|
|
return HUGE_VAL;
|
|
|
|
}
|
2012-11-06 21:14:16 +04:00
|
|
|
if (isinf(unit)) {
|
|
|
|
return unit > 0 ? beg <= end : beg >= end;
|
|
|
|
}
|
2021-04-29 22:51:05 +03:00
|
|
|
n= (end - beg)/unit;
|
|
|
|
err = (fabs(beg) + fabs(end) + fabs(end-beg)) / fabs(unit) * epsilon;
|
2012-11-06 21:14:16 +04:00
|
|
|
if (err>0.5) err=0.5;
|
|
|
|
if (excl) {
|
|
|
|
if (n<=0) return 0;
|
|
|
|
if (n<1)
|
|
|
|
n = 0;
|
|
|
|
else
|
|
|
|
n = floor(n - err);
|
2021-11-08 10:05:04 +03:00
|
|
|
d = +((n + 1) * unit) + beg;
|
2021-04-29 22:51:05 +03:00
|
|
|
if (beg < end) {
|
2021-11-08 10:05:04 +03:00
|
|
|
if (d < end)
|
2021-04-29 22:51:05 +03:00
|
|
|
n++;
|
|
|
|
}
|
|
|
|
else if (beg > end) {
|
2021-11-08 10:05:04 +03:00
|
|
|
if (d > end)
|
2021-04-29 22:51:05 +03:00
|
|
|
n++;
|
|
|
|
}
|
2012-11-06 21:14:16 +04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (n<0) return 0;
|
|
|
|
n = floor(n + err);
|
2021-11-08 10:05:04 +03:00
|
|
|
d = +((n + 1) * unit) + beg;
|
2021-04-29 22:51:05 +03:00
|
|
|
if (beg < end) {
|
2021-11-08 10:05:04 +03:00
|
|
|
if (d <= end)
|
2021-04-29 22:51:05 +03:00
|
|
|
n++;
|
|
|
|
}
|
|
|
|
else if (beg > end) {
|
2021-11-08 10:05:04 +03:00
|
|
|
if (d >= end)
|
2021-04-29 22:51:05 +03:00
|
|
|
n++;
|
|
|
|
}
|
2012-11-06 21:14:16 +04:00
|
|
|
}
|
|
|
|
return n+1;
|
|
|
|
}
|
2003-12-27 08:46:46 +03:00
|
|
|
|
2009-01-04 05:58:45 +03:00
|
|
|
int
|
2018-04-19 18:18:50 +03:00
|
|
|
ruby_float_step(VALUE from, VALUE to, VALUE step, int excl, int allow_endless)
|
2009-01-04 05:58:45 +03:00
|
|
|
{
|
2021-09-11 03:56:59 +03:00
|
|
|
if (RB_FLOAT_TYPE_P(from) || RB_FLOAT_TYPE_P(to) || RB_FLOAT_TYPE_P(step)) {
|
2019-01-24 08:30:45 +03:00
|
|
|
double unit = NUM2DBL(step);
|
2019-01-24 08:30:42 +03:00
|
|
|
double beg = NUM2DBL(from);
|
2019-01-24 08:30:45 +03:00
|
|
|
double end = (allow_endless && NIL_P(to)) ? (unit < 0 ? -1 : 1)*HUGE_VAL : NUM2DBL(to);
|
2012-11-06 21:14:16 +04:00
|
|
|
double n = ruby_float_step_size(beg, end, unit, excl);
|
2009-01-04 05:58:45 +03:00
|
|
|
long i;
|
2022-07-21 19:23:58 +03:00
|
|
|
|
2012-11-07 11:03:50 +04:00
|
|
|
if (isinf(unit)) {
|
|
|
|
/* if unit is infinity, i*unit+beg is NaN */
|
|
|
|
if (n) rb_yield(DBL2NUM(beg));
|
|
|
|
}
|
2014-02-28 06:04:59 +04:00
|
|
|
else if (unit == 0) {
|
|
|
|
VALUE val = DBL2NUM(beg);
|
|
|
|
for (;;)
|
|
|
|
rb_yield(val);
|
|
|
|
}
|
2012-11-07 11:03:50 +04:00
|
|
|
else {
|
|
|
|
for (i=0; i<n; i++) {
|
|
|
|
double d = i*unit+beg;
|
|
|
|
if (unit >= 0 ? end < d : d < end) d = end;
|
|
|
|
rb_yield(DBL2NUM(d));
|
|
|
|
}
|
2009-01-04 05:58:45 +03:00
|
|
|
}
|
2009-07-18 12:05:32 +04:00
|
|
|
return TRUE;
|
2009-01-04 05:58:45 +03:00
|
|
|
}
|
2009-07-18 12:05:32 +04:00
|
|
|
return FALSE;
|
2009-01-04 05:58:45 +03:00
|
|
|
}
|
|
|
|
|
2012-11-06 21:14:31 +04:00
|
|
|
VALUE
|
2013-03-06 10:30:03 +04:00
|
|
|
ruby_num_interval_step_size(VALUE from, VALUE to, VALUE step, int excl)
|
2012-11-07 02:50:30 +04:00
|
|
|
{
|
2012-11-06 21:14:31 +04:00
|
|
|
if (FIXNUM_P(from) && FIXNUM_P(to) && FIXNUM_P(step)) {
|
2014-02-28 06:03:30 +04:00
|
|
|
long delta, diff;
|
2022-07-21 19:23:58 +03:00
|
|
|
|
2012-11-06 21:14:31 +04:00
|
|
|
diff = FIX2LONG(step);
|
2014-02-28 06:04:59 +04:00
|
|
|
if (diff == 0) {
|
2018-01-19 04:45:36 +03:00
|
|
|
return DBL2NUM(HUGE_VAL);
|
2014-02-28 06:04:59 +04:00
|
|
|
}
|
2012-11-06 21:14:31 +04:00
|
|
|
delta = FIX2LONG(to) - FIX2LONG(from);
|
2014-02-28 06:03:30 +04:00
|
|
|
if (diff < 0) {
|
|
|
|
diff = -diff;
|
|
|
|
delta = -delta;
|
|
|
|
}
|
2012-11-06 21:14:31 +04:00
|
|
|
if (excl) {
|
2014-02-28 06:03:30 +04:00
|
|
|
delta--;
|
2012-11-06 21:14:31 +04:00
|
|
|
}
|
2014-02-28 06:03:30 +04:00
|
|
|
if (delta < 0) {
|
|
|
|
return INT2FIX(0);
|
2014-02-27 07:10:12 +04:00
|
|
|
}
|
2014-02-28 08:59:49 +04:00
|
|
|
return ULONG2NUM(delta / diff + 1UL);
|
2012-11-06 21:14:31 +04:00
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(from) || RB_FLOAT_TYPE_P(to) || RB_FLOAT_TYPE_P(step)) {
|
2012-11-06 21:14:31 +04:00
|
|
|
double n = ruby_float_step_size(NUM2DBL(from), NUM2DBL(to), NUM2DBL(step), excl);
|
|
|
|
|
|
|
|
if (isinf(n)) return DBL2NUM(n);
|
2020-04-08 12:03:46 +03:00
|
|
|
if (POSFIXABLE(n)) return LONG2FIX((long)n);
|
2014-02-28 09:11:44 +04:00
|
|
|
return rb_dbl2big(n);
|
2012-11-06 21:14:31 +04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
VALUE result;
|
2014-02-28 06:04:59 +04:00
|
|
|
ID cmp = '>';
|
|
|
|
switch (rb_cmpint(rb_num_coerce_cmp(step, INT2FIX(0), id_cmp), step, INT2FIX(0))) {
|
2018-01-19 04:45:36 +03:00
|
|
|
case 0: return DBL2NUM(HUGE_VAL);
|
2014-05-07 11:34:33 +04:00
|
|
|
case -1: cmp = '<'; break;
|
2014-02-28 06:04:59 +04:00
|
|
|
}
|
2012-11-06 21:14:31 +04:00
|
|
|
if (RTEST(rb_funcall(from, cmp, 1, to))) return INT2FIX(0);
|
|
|
|
result = rb_funcall(rb_funcall(to, '-', 1, from), id_div, 1, step);
|
|
|
|
if (!excl || RTEST(rb_funcall(rb_funcall(from, '+', 1, rb_funcall(result, '*', 1, step)), cmp, 1, to))) {
|
|
|
|
result = rb_funcall(result, '+', 1, INT2FIX(1));
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-26 08:41:37 +03:00
|
|
|
static int
|
|
|
|
num_step_negative_p(VALUE num)
|
|
|
|
{
|
|
|
|
const ID mid = '<';
|
2017-04-25 14:42:31 +03:00
|
|
|
VALUE zero = INT2FIX(0);
|
2016-02-26 08:41:37 +03:00
|
|
|
VALUE r;
|
|
|
|
|
|
|
|
if (FIXNUM_P(num)) {
|
Use Integer instead of Fixnum and Bignum.
* object.c, numeric.c, enum.c, ext/-test-/bignum/mul.c,
lib/rexml/quickpath.rb, lib/rexml/text.rb, lib/rexml/xpath_parser.rb,
lib/rubygems/specification.rb, lib/uri/generic.rb,
bootstraptest/test_eval.rb, basictest/test.rb,
test/-ext-/bignum/test_big2str.rb, test/-ext-/bignum/test_div.rb,
test/-ext-/bignum/test_mul.rb, test/-ext-/bignum/test_str2big.rb,
test/csv/test_data_converters.rb, test/date/test_date.rb,
test/json/test_json_generate.rb, test/minitest/test_minitest_mock.rb,
test/openssl/test_cipher.rb, test/rexml/test_jaxen.rb,
test/ruby/test_array.rb, test/ruby/test_basicinstructions.rb,
test/ruby/test_bignum.rb, test/ruby/test_case.rb,
test/ruby/test_class.rb, test/ruby/test_complex.rb,
test/ruby/test_enum.rb, test/ruby/test_eval.rb,
test/ruby/test_iseq.rb, test/ruby/test_literal.rb,
test/ruby/test_math.rb, test/ruby/test_module.rb,
test/ruby/test_numeric.rb, test/ruby/test_range.rb,
test/ruby/test_rational.rb, test/ruby/test_refinement.rb,
test/ruby/test_rubyvm.rb, test/ruby/test_struct.rb,
test/ruby/test_variable.rb, test/rubygems/test_gem_specification.rb,
test/thread/test_queue.rb: Use Integer instead of Fixnum and Bignum.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@55029 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2016-05-17 16:15:57 +03:00
|
|
|
if (method_basic_p(rb_cInteger))
|
2016-02-26 08:41:37 +03:00
|
|
|
return (SIGNED_VALUE)num < 0;
|
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(num)) {
|
Use Integer instead of Fixnum and Bignum.
* object.c, numeric.c, enum.c, ext/-test-/bignum/mul.c,
lib/rexml/quickpath.rb, lib/rexml/text.rb, lib/rexml/xpath_parser.rb,
lib/rubygems/specification.rb, lib/uri/generic.rb,
bootstraptest/test_eval.rb, basictest/test.rb,
test/-ext-/bignum/test_big2str.rb, test/-ext-/bignum/test_div.rb,
test/-ext-/bignum/test_mul.rb, test/-ext-/bignum/test_str2big.rb,
test/csv/test_data_converters.rb, test/date/test_date.rb,
test/json/test_json_generate.rb, test/minitest/test_minitest_mock.rb,
test/openssl/test_cipher.rb, test/rexml/test_jaxen.rb,
test/ruby/test_array.rb, test/ruby/test_basicinstructions.rb,
test/ruby/test_bignum.rb, test/ruby/test_case.rb,
test/ruby/test_class.rb, test/ruby/test_complex.rb,
test/ruby/test_enum.rb, test/ruby/test_eval.rb,
test/ruby/test_iseq.rb, test/ruby/test_literal.rb,
test/ruby/test_math.rb, test/ruby/test_module.rb,
test/ruby/test_numeric.rb, test/ruby/test_range.rb,
test/ruby/test_rational.rb, test/ruby/test_refinement.rb,
test/ruby/test_rubyvm.rb, test/ruby/test_struct.rb,
test/ruby/test_variable.rb, test/rubygems/test_gem_specification.rb,
test/thread/test_queue.rb: Use Integer instead of Fixnum and Bignum.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@55029 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2016-05-17 16:15:57 +03:00
|
|
|
if (method_basic_p(rb_cInteger))
|
2016-02-26 08:41:37 +03:00
|
|
|
return BIGNUM_NEGATIVE_P(num);
|
|
|
|
}
|
2017-04-25 14:42:31 +03:00
|
|
|
|
|
|
|
r = rb_check_funcall(num, '>', 1, &zero);
|
2016-02-26 08:41:37 +03:00
|
|
|
if (r == Qundef) {
|
|
|
|
coerce_failed(num, INT2FIX(0));
|
|
|
|
}
|
|
|
|
return !RTEST(r);
|
|
|
|
}
|
|
|
|
|
2014-05-07 12:05:00 +04:00
|
|
|
static int
|
2018-08-06 12:08:28 +03:00
|
|
|
num_step_extract_args(int argc, const VALUE *argv, VALUE *to, VALUE *step, VALUE *by)
|
2014-05-07 12:05:00 +04:00
|
|
|
{
|
|
|
|
VALUE hash;
|
|
|
|
|
|
|
|
argc = rb_scan_args(argc, argv, "02:", to, step, &hash);
|
|
|
|
if (!NIL_P(hash)) {
|
2014-05-07 12:24:09 +04:00
|
|
|
ID keys[2];
|
|
|
|
VALUE values[2];
|
2014-07-01 18:36:03 +04:00
|
|
|
keys[0] = id_to;
|
|
|
|
keys[1] = id_by;
|
2014-05-07 12:24:09 +04:00
|
|
|
rb_get_kwargs(hash, keys, 0, 2, values);
|
|
|
|
if (values[0] != Qundef) {
|
|
|
|
if (argc > 0) rb_raise(rb_eArgError, "to is given twice");
|
|
|
|
*to = values[0];
|
|
|
|
}
|
|
|
|
if (values[1] != Qundef) {
|
|
|
|
if (argc > 1) rb_raise(rb_eArgError, "step is given twice");
|
2018-08-06 12:08:28 +03:00
|
|
|
*by = values[1];
|
2014-05-07 12:24:09 +04:00
|
|
|
}
|
2014-05-07 12:05:00 +04:00
|
|
|
}
|
2018-08-06 12:08:28 +03:00
|
|
|
|
|
|
|
return argc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
num_step_check_fix_args(int argc, VALUE *to, VALUE *step, VALUE by, int fix_nil, int allow_zero_step)
|
|
|
|
{
|
|
|
|
int desc;
|
|
|
|
if (by != Qundef) {
|
|
|
|
*step = by;
|
|
|
|
}
|
2014-05-07 12:05:00 +04:00
|
|
|
else {
|
2018-08-06 12:08:28 +03:00
|
|
|
/* compatibility */
|
|
|
|
if (argc > 1 && NIL_P(*step)) {
|
|
|
|
rb_raise(rb_eTypeError, "step must be numeric");
|
|
|
|
}
|
2020-10-23 09:26:51 +03:00
|
|
|
}
|
|
|
|
if (!allow_zero_step && rb_equal(*step, INT2FIX(0))) {
|
|
|
|
rb_raise(rb_eArgError, "step can't be 0");
|
2014-05-07 12:05:00 +04:00
|
|
|
}
|
|
|
|
if (NIL_P(*step)) {
|
|
|
|
*step = INT2FIX(1);
|
|
|
|
}
|
2016-02-26 08:41:37 +03:00
|
|
|
desc = num_step_negative_p(*step);
|
2018-08-06 12:08:28 +03:00
|
|
|
if (fix_nil && NIL_P(*to)) {
|
|
|
|
*to = desc ? DBL2NUM(-HUGE_VAL) : DBL2NUM(HUGE_VAL);
|
2014-05-07 12:05:00 +04:00
|
|
|
}
|
|
|
|
return desc;
|
|
|
|
}
|
2013-09-04 17:57:02 +04:00
|
|
|
|
2018-08-06 12:08:28 +03:00
|
|
|
static int
|
|
|
|
num_step_scan_args(int argc, const VALUE *argv, VALUE *to, VALUE *step, int fix_nil, int allow_zero_step)
|
|
|
|
{
|
|
|
|
VALUE by = Qundef;
|
|
|
|
argc = num_step_extract_args(argc, argv, to, step, &by);
|
|
|
|
return num_step_check_fix_args(argc, to, step, by, fix_nil, allow_zero_step);
|
|
|
|
}
|
|
|
|
|
2012-11-06 21:14:31 +04:00
|
|
|
static VALUE
|
2013-06-26 17:43:22 +04:00
|
|
|
num_step_size(VALUE from, VALUE args, VALUE eobj)
|
2012-11-07 02:50:30 +04:00
|
|
|
{
|
2014-05-07 12:05:00 +04:00
|
|
|
VALUE to, step;
|
2013-09-02 18:56:06 +04:00
|
|
|
int argc = args ? RARRAY_LENINT(args) : 0;
|
2014-03-17 08:20:16 +04:00
|
|
|
const VALUE *argv = args ? RARRAY_CONST_PTR(args) : 0;
|
2013-09-02 18:56:06 +04:00
|
|
|
|
2018-08-06 12:08:28 +03:00
|
|
|
num_step_scan_args(argc, argv, &to, &step, TRUE, FALSE);
|
2013-09-02 18:56:06 +04:00
|
|
|
|
2013-03-06 10:30:03 +04:00
|
|
|
return ruby_num_interval_step_size(from, to, step, FALSE);
|
2012-11-06 21:14:31 +04:00
|
|
|
}
|
2017-05-06 10:17:41 +03:00
|
|
|
|
2003-12-27 08:46:46 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-10-28 23:11:11 +03:00
|
|
|
* step(to = nil, by = 1) {|n| ... } -> self
|
|
|
|
* step(to = nil, by = 1) -> enumerator
|
|
|
|
* step(to = nil, by: 1) {|n| ... } -> self
|
|
|
|
* step(to = nil, by: 1) -> enumerator
|
|
|
|
* step(by: 1, to: ) {|n| ... } -> self
|
|
|
|
* step(by: 1, to: ) -> enumerator
|
|
|
|
* step(by: , to: nil) {|n| ... } -> self
|
|
|
|
* step(by: , to: nil) -> enumerator
|
|
|
|
*
|
|
|
|
* Generates a sequence of numbers; with a block given, traverses the sequence.
|
|
|
|
*
|
|
|
|
* Of the Core and Standard Library classes,
|
|
|
|
* Integer, Float, and Rational use this implementation.
|
|
|
|
*
|
|
|
|
* A quick example:
|
|
|
|
*
|
|
|
|
* squares = []
|
|
|
|
* 1.step(by: 2, to: 10) {|i| squares.push(i*i) }
|
|
|
|
* squares # => [1, 9, 25, 49, 81]
|
|
|
|
*
|
|
|
|
* The generated sequence:
|
|
|
|
*
|
|
|
|
* - Begins with +self+.
|
|
|
|
* - Continues at intervals of +step+ (which may not be zero).
|
|
|
|
* - Ends with the last number that is within or equal to +limit+;
|
|
|
|
* that is, less than or equal to +limit+ if +step+ is positive,
|
|
|
|
* greater than or equal to +limit+ if +step+ is negative.
|
|
|
|
* If +limit+ is not given, the sequence is of infinite length.
|
|
|
|
*
|
|
|
|
* If a block is given, calls the block with each number in the sequence;
|
|
|
|
* returns +self+. If no block is given, returns an Enumerator::ArithmeticSequence.
|
|
|
|
*
|
|
|
|
* <b>Keyword Arguments</b>
|
|
|
|
*
|
|
|
|
* With keyword arguments +by+ and +to+,
|
|
|
|
* their values (or defaults) determine the step and limit:
|
|
|
|
*
|
|
|
|
* # Both keywords given.
|
|
|
|
* squares = []
|
|
|
|
* 4.step(by: 2, to: 10) {|i| squares.push(i*i) } # => 4
|
|
|
|
* squares # => [16, 36, 64, 100]
|
|
|
|
* cubes = []
|
|
|
|
* 3.step(by: -1.5, to: -3) {|i| cubes.push(i*i*i) } # => 3
|
|
|
|
* cubes # => [27.0, 3.375, 0.0, -3.375, -27.0]
|
|
|
|
* squares = []
|
|
|
|
* 1.2.step(by: 0.2, to: 2.0) {|f| squares.push(f*f) }
|
|
|
|
* squares # => [1.44, 1.9599999999999997, 2.5600000000000005, 3.24, 4.0]
|
|
|
|
*
|
|
|
|
* squares = []
|
|
|
|
* Rational(6/5).step(by: 0.2, to: 2.0) {|r| squares.push(r*r) }
|
|
|
|
* squares # => [1.0, 1.44, 1.9599999999999997, 2.5600000000000005, 3.24, 4.0]
|
|
|
|
*
|
|
|
|
* # Only keyword to given.
|
|
|
|
* squares = []
|
|
|
|
* 4.step(to: 10) {|i| squares.push(i*i) } # => 4
|
|
|
|
* squares # => [16, 25, 36, 49, 64, 81, 100]
|
|
|
|
* # Only by given.
|
|
|
|
*
|
|
|
|
* # Only keyword by given
|
|
|
|
* squares = []
|
|
|
|
* 4.step(by:2) {|i| squares.push(i*i); break if i > 10 }
|
|
|
|
* squares # => [16, 36, 64, 100, 144]
|
|
|
|
*
|
|
|
|
* # No block given.
|
|
|
|
* e = 3.step(by: -1.5, to: -3) # => (3.step(by: -1.5, to: -3))
|
|
|
|
* e.class # => Enumerator::ArithmeticSequence
|
|
|
|
*
|
|
|
|
* <b>Positional Arguments</b>
|
|
|
|
*
|
|
|
|
* With optional positional arguments +limit+ and +step+,
|
|
|
|
* their values (or defaults) determine the step and limit:
|
|
|
|
*
|
|
|
|
* squares = []
|
|
|
|
* 4.step(10, 2) {|i| squares.push(i*i) } # => 4
|
|
|
|
* squares # => [16, 36, 64, 100]
|
|
|
|
* squares = []
|
|
|
|
* 4.step(10) {|i| squares.push(i*i) }
|
|
|
|
* squares # => [16, 25, 36, 49, 64, 81, 100]
|
|
|
|
* squares = []
|
|
|
|
* 4.step {|i| squares.push(i*i); break if i > 10 } # => nil
|
|
|
|
* squares # => [16, 25, 36, 49, 64, 81, 100, 121]
|
|
|
|
*
|
|
|
|
* <b>Implementation Notes</b>
|
2013-07-15 22:27:23 +04:00
|
|
|
*
|
|
|
|
* If all the arguments are integers, the loop operates using an integer
|
|
|
|
* counter.
|
|
|
|
*
|
2017-05-06 10:17:41 +03:00
|
|
|
* If any of the arguments are floating point numbers, all are converted
|
|
|
|
* to floats, and the loop is executed
|
|
|
|
* <i>floor(n + n*Float::EPSILON) + 1</i> times,
|
2021-10-28 23:11:11 +03:00
|
|
|
* where <i>n = (limit - self)/step</i>.
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2003-12-27 08:46:46 +03:00
|
|
|
*/
|
|
|
|
|
2002-04-24 08:54:16 +04:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
num_step(int argc, VALUE *argv, VALUE from)
|
2002-04-24 08:54:16 +04:00
|
|
|
{
|
2014-05-07 12:05:00 +04:00
|
|
|
VALUE to, step;
|
2013-09-02 18:56:06 +04:00
|
|
|
int desc, inf;
|
2002-04-24 08:54:16 +04:00
|
|
|
|
2018-08-06 12:08:28 +03:00
|
|
|
if (!rb_block_given_p()) {
|
|
|
|
VALUE by = Qundef;
|
|
|
|
|
|
|
|
num_step_extract_args(argc, argv, &to, &step, &by);
|
|
|
|
if (by != Qundef) {
|
|
|
|
step = by;
|
|
|
|
}
|
|
|
|
if (NIL_P(step)) {
|
|
|
|
step = INT2FIX(1);
|
|
|
|
}
|
2020-10-23 09:26:51 +03:00
|
|
|
else if (rb_equal(step, INT2FIX(0))) {
|
|
|
|
rb_raise(rb_eArgError, "step can't be 0");
|
|
|
|
}
|
2018-08-06 12:08:28 +03:00
|
|
|
if ((NIL_P(to) || rb_obj_is_kind_of(to, rb_cNumeric)) &&
|
|
|
|
rb_obj_is_kind_of(step, rb_cNumeric)) {
|
|
|
|
return rb_arith_seq_new(from, ID2SYM(rb_frame_this_func()), argc, argv,
|
|
|
|
num_step_size, from, to, step, FALSE);
|
|
|
|
}
|
|
|
|
|
2019-09-29 19:08:32 +03:00
|
|
|
return SIZED_ENUMERATOR(from, 2, ((VALUE [2]){to, step}), num_step_size);
|
2018-08-06 12:08:28 +03:00
|
|
|
}
|
2002-04-24 08:54:16 +04:00
|
|
|
|
2018-08-06 12:08:28 +03:00
|
|
|
desc = num_step_scan_args(argc, argv, &to, &step, TRUE, FALSE);
|
2016-03-17 18:18:59 +03:00
|
|
|
if (rb_equal(step, INT2FIX(0))) {
|
2014-02-28 06:04:59 +04:00
|
|
|
inf = 1;
|
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(to)) {
|
2014-02-28 06:04:43 +04:00
|
|
|
double f = RFLOAT_VALUE(to);
|
|
|
|
inf = isinf(f) && (signbit(f) ? desc : !desc);
|
|
|
|
}
|
|
|
|
else inf = 0;
|
2002-04-24 08:54:16 +04:00
|
|
|
|
2013-09-02 18:56:06 +04:00
|
|
|
if (FIXNUM_P(from) && (inf || FIXNUM_P(to)) && FIXNUM_P(step)) {
|
|
|
|
long i = FIX2LONG(from);
|
|
|
|
long diff = FIX2LONG(step);
|
2022-07-21 19:23:58 +03:00
|
|
|
|
2013-09-02 18:56:06 +04:00
|
|
|
if (inf) {
|
|
|
|
for (;; i += diff)
|
2002-08-21 19:47:54 +04:00
|
|
|
rb_yield(LONG2FIX(i));
|
2002-04-24 08:54:16 +04:00
|
|
|
}
|
|
|
|
else {
|
2013-09-02 18:56:06 +04:00
|
|
|
long end = FIX2LONG(to);
|
2022-07-21 19:23:58 +03:00
|
|
|
|
2013-09-02 18:56:06 +04:00
|
|
|
if (desc) {
|
|
|
|
for (; i >= end; i += diff)
|
|
|
|
rb_yield(LONG2FIX(i));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
for (; i <= end; i += diff)
|
|
|
|
rb_yield(LONG2FIX(i));
|
2002-04-24 08:54:16 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-04-19 18:18:50 +03:00
|
|
|
else if (!ruby_float_step(from, to, step, FALSE, FALSE)) {
|
2002-04-24 09:08:04 +04:00
|
|
|
VALUE i = from;
|
|
|
|
|
2013-09-02 18:56:06 +04:00
|
|
|
if (inf) {
|
|
|
|
for (;; i = rb_funcall(i, '+', 1, step))
|
|
|
|
rb_yield(i);
|
2002-04-24 09:08:04 +04:00
|
|
|
}
|
|
|
|
else {
|
2013-09-02 18:56:06 +04:00
|
|
|
ID cmp = desc ? '<' : '>';
|
|
|
|
|
|
|
|
for (; !RTEST(rb_funcall(i, cmp, 1, to)); i = rb_funcall(i, '+', 1, step))
|
|
|
|
rb_yield(i);
|
2002-04-24 09:08:04 +04:00
|
|
|
}
|
2002-04-24 08:54:16 +04:00
|
|
|
}
|
|
|
|
return from;
|
|
|
|
}
|
|
|
|
|
2014-01-15 12:16:38 +04:00
|
|
|
static char *
|
|
|
|
out_of_range_float(char (*pbuf)[24], VALUE val)
|
|
|
|
{
|
|
|
|
char *const buf = *pbuf;
|
|
|
|
char *s;
|
|
|
|
|
|
|
|
snprintf(buf, sizeof(*pbuf), "%-.10g", RFLOAT_VALUE(val));
|
|
|
|
if ((s = strchr(buf, ' ')) != 0) *s = '\0';
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define FLOAT_OUT_OF_RANGE(val, type) do { \
|
|
|
|
char buf[24]; \
|
|
|
|
rb_raise(rb_eRangeError, "float %s out of range of "type, \
|
|
|
|
out_of_range_float(&buf, (val))); \
|
|
|
|
} while (0)
|
|
|
|
|
2010-07-02 00:39:32 +04:00
|
|
|
#define LONG_MIN_MINUS_ONE ((double)LONG_MIN-1)
|
|
|
|
#define LONG_MAX_PLUS_ONE (2*(double)(LONG_MAX/2+1))
|
|
|
|
#define ULONG_MAX_PLUS_ONE (2*(double)(ULONG_MAX/2+1))
|
2013-03-27 17:12:27 +04:00
|
|
|
#define LONG_MIN_MINUS_ONE_IS_LESS_THAN(n) \
|
|
|
|
(LONG_MIN_MINUS_ONE == (double)LONG_MIN ? \
|
|
|
|
LONG_MIN <= (n): \
|
|
|
|
LONG_MIN_MINUS_ONE < (n))
|
2010-07-02 00:39:32 +04:00
|
|
|
|
2014-04-18 19:46:32 +04:00
|
|
|
long
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
rb_num2long(VALUE val)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2008-03-11 13:48:12 +03:00
|
|
|
again:
|
1999-01-20 07:59:39 +03:00
|
|
|
if (NIL_P(val)) {
|
2002-07-29 10:14:10 +04:00
|
|
|
rb_raise(rb_eTypeError, "no implicit conversion from nil to integer");
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
if (FIXNUM_P(val)) return FIX2LONG(val);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(val)) {
|
2010-07-02 00:39:32 +04:00
|
|
|
if (RFLOAT_VALUE(val) < LONG_MAX_PLUS_ONE
|
2013-03-27 17:12:27 +04:00
|
|
|
&& LONG_MIN_MINUS_ONE_IS_LESS_THAN(RFLOAT_VALUE(val))) {
|
2013-04-01 15:08:44 +04:00
|
|
|
return (long)RFLOAT_VALUE(val);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
else {
|
2014-01-15 12:16:38 +04:00
|
|
|
FLOAT_OUT_OF_RANGE(val, "integer");
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(val)) {
|
1999-01-20 07:59:39 +03:00
|
|
|
return rb_big2long(val);
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
|
|
|
else {
|
2000-11-14 10:10:31 +03:00
|
|
|
val = rb_to_int(val);
|
2008-03-11 13:48:12 +03:00
|
|
|
goto again;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-31 08:51:29 +04:00
|
|
|
static unsigned long
|
|
|
|
rb_num2ulong_internal(VALUE val, int *wrap_p)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2010-05-19 13:22:59 +04:00
|
|
|
again:
|
|
|
|
if (NIL_P(val)) {
|
|
|
|
rb_raise(rb_eTypeError, "no implicit conversion from nil to integer");
|
|
|
|
}
|
|
|
|
|
2013-03-31 08:51:29 +04:00
|
|
|
if (FIXNUM_P(val)) {
|
2016-11-01 15:35:30 +03:00
|
|
|
long l = FIX2LONG(val); /* this is FIX2LONG, intended */
|
2013-03-31 08:51:29 +04:00
|
|
|
if (wrap_p)
|
|
|
|
*wrap_p = l < 0;
|
2013-04-01 15:08:44 +04:00
|
|
|
return (unsigned long)l;
|
2013-03-31 08:51:29 +04:00
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(val)) {
|
2016-11-01 15:35:31 +03:00
|
|
|
double d = RFLOAT_VALUE(val);
|
|
|
|
if (d < ULONG_MAX_PLUS_ONE && LONG_MIN_MINUS_ONE_IS_LESS_THAN(d)) {
|
|
|
|
if (wrap_p)
|
|
|
|
*wrap_p = d <= -1.0; /* NUM2ULONG(v) uses v.to_int conceptually. */
|
|
|
|
if (0 <= d)
|
|
|
|
return (unsigned long)d;
|
|
|
|
return (unsigned long)(long)d;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
FLOAT_OUT_OF_RANGE(val, "integer");
|
|
|
|
}
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(val)) {
|
2013-03-31 08:51:29 +04:00
|
|
|
{
|
|
|
|
unsigned long ul = rb_big2ulong(val);
|
|
|
|
if (wrap_p)
|
2014-02-16 01:17:34 +04:00
|
|
|
*wrap_p = BIGNUM_NEGATIVE_P(val);
|
2013-03-31 08:51:29 +04:00
|
|
|
return ul;
|
|
|
|
}
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
|
|
|
else {
|
2013-04-01 15:08:44 +04:00
|
|
|
val = rb_to_int(val);
|
|
|
|
goto again;
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2014-04-18 19:46:32 +04:00
|
|
|
unsigned long
|
2013-03-31 08:51:29 +04:00
|
|
|
rb_num2ulong(VALUE val)
|
|
|
|
{
|
|
|
|
return rb_num2ulong_internal(val, NULL);
|
|
|
|
}
|
|
|
|
|
2009-05-20 20:43:41 +04:00
|
|
|
void
|
|
|
|
rb_out_of_int(SIGNED_VALUE num)
|
|
|
|
{
|
|
|
|
rb_raise(rb_eRangeError, "integer %"PRIdVALUE " too %s to convert to `int'",
|
|
|
|
num, num < 0 ? "small" : "big");
|
|
|
|
}
|
|
|
|
|
2020-04-08 07:28:13 +03:00
|
|
|
#if SIZEOF_INT < SIZEOF_LONG
|
2003-05-30 17:28:10 +04:00
|
|
|
static void
|
2013-04-01 15:08:44 +04:00
|
|
|
check_int(long num)
|
2003-05-30 17:28:10 +04:00
|
|
|
{
|
2013-04-01 15:08:44 +04:00
|
|
|
if ((long)(int)num != num) {
|
2009-05-20 20:43:41 +04:00
|
|
|
rb_out_of_int(num);
|
2003-05-30 17:28:10 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2013-04-01 07:06:09 +04:00
|
|
|
check_uint(unsigned long num, int sign)
|
2003-05-30 17:28:10 +04:00
|
|
|
{
|
2012-06-20 10:31:32 +04:00
|
|
|
if (sign) {
|
2008-07-18 19:29:17 +04:00
|
|
|
/* minus */
|
2013-04-01 07:06:09 +04:00
|
|
|
if (num < (unsigned long)INT_MIN)
|
|
|
|
rb_raise(rb_eRangeError, "integer %ld too small to convert to `unsigned int'", (long)num);
|
2008-07-18 19:29:17 +04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* plus */
|
2013-04-01 07:06:09 +04:00
|
|
|
if (UINT_MAX < num)
|
|
|
|
rb_raise(rb_eRangeError, "integer %lu too big to convert to `unsigned int'", num);
|
2003-05-30 17:28:10 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-12-01 11:42:53 +03:00
|
|
|
long
|
2006-07-11 10:47:09 +04:00
|
|
|
rb_num2int(VALUE val)
|
1999-01-20 07:59:39 +03:00
|
|
|
{
|
|
|
|
long num = rb_num2long(val);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2003-05-30 17:28:10 +04:00
|
|
|
check_int(num);
|
2003-12-01 11:42:53 +03:00
|
|
|
return num;
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
|
|
|
|
2003-12-01 11:42:53 +03:00
|
|
|
long
|
2006-07-11 10:47:09 +04:00
|
|
|
rb_fix2int(VALUE val)
|
1999-01-20 07:59:39 +03:00
|
|
|
{
|
|
|
|
long num = FIXNUM_P(val)?FIX2LONG(val):rb_num2long(val);
|
|
|
|
|
2003-05-30 17:28:10 +04:00
|
|
|
check_int(num);
|
2003-12-01 11:42:53 +03:00
|
|
|
return num;
|
2003-05-30 17:28:10 +04:00
|
|
|
}
|
|
|
|
|
2003-12-01 11:42:53 +03:00
|
|
|
unsigned long
|
2006-07-11 10:47:09 +04:00
|
|
|
rb_num2uint(VALUE val)
|
2003-05-30 17:28:10 +04:00
|
|
|
{
|
2013-03-31 08:51:29 +04:00
|
|
|
int wrap;
|
|
|
|
unsigned long num = rb_num2ulong_internal(val, &wrap);
|
2003-05-30 17:28:10 +04:00
|
|
|
|
2013-03-31 08:51:29 +04:00
|
|
|
check_uint(num, wrap);
|
|
|
|
return num;
|
2003-05-30 17:28:10 +04:00
|
|
|
}
|
|
|
|
|
2003-12-01 11:42:53 +03:00
|
|
|
unsigned long
|
2006-07-11 10:47:09 +04:00
|
|
|
rb_fix2uint(VALUE val)
|
2003-05-30 17:28:10 +04:00
|
|
|
{
|
2003-12-01 11:42:53 +03:00
|
|
|
unsigned long num;
|
2003-05-30 17:28:10 +04:00
|
|
|
|
2003-12-01 11:42:53 +03:00
|
|
|
if (!FIXNUM_P(val)) {
|
2007-06-29 10:43:24 +04:00
|
|
|
return rb_num2uint(val);
|
2003-12-01 11:42:53 +03:00
|
|
|
}
|
|
|
|
num = FIX2ULONG(val);
|
2008-07-17 05:23:35 +04:00
|
|
|
|
2021-08-16 22:51:11 +03:00
|
|
|
check_uint(num, FIXNUM_NEGATIVE_P(val));
|
2003-12-01 11:42:53 +03:00
|
|
|
return num;
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
|
|
|
#else
|
2003-12-01 11:42:53 +03:00
|
|
|
long
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
rb_num2int(VALUE val)
|
1999-01-20 07:59:39 +03:00
|
|
|
{
|
|
|
|
return rb_num2long(val);
|
|
|
|
}
|
|
|
|
|
2003-12-01 11:42:53 +03:00
|
|
|
long
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
rb_fix2int(VALUE val)
|
1999-01-20 07:59:39 +03:00
|
|
|
{
|
|
|
|
return FIX2INT(val);
|
|
|
|
}
|
2020-04-08 07:28:13 +03:00
|
|
|
|
|
|
|
unsigned long
|
|
|
|
rb_num2uint(VALUE val)
|
|
|
|
{
|
|
|
|
return rb_num2ulong(val);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long
|
|
|
|
rb_fix2uint(VALUE val)
|
|
|
|
{
|
|
|
|
return RB_FIX2ULONG(val);
|
|
|
|
}
|
1999-01-20 07:59:39 +03:00
|
|
|
#endif
|
|
|
|
|
2016-05-08 03:55:28 +03:00
|
|
|
NORETURN(static void rb_out_of_short(SIGNED_VALUE num));
|
|
|
|
static void
|
2011-11-14 07:54:34 +04:00
|
|
|
rb_out_of_short(SIGNED_VALUE num)
|
|
|
|
{
|
|
|
|
rb_raise(rb_eRangeError, "integer %"PRIdVALUE " too %s to convert to `short'",
|
|
|
|
num, num < 0 ? "small" : "big");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2013-04-01 15:08:44 +04:00
|
|
|
check_short(long num)
|
2011-11-14 07:54:34 +04:00
|
|
|
{
|
2013-04-01 15:08:44 +04:00
|
|
|
if ((long)(short)num != num) {
|
2011-11-14 07:54:34 +04:00
|
|
|
rb_out_of_short(num);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2013-04-01 07:06:09 +04:00
|
|
|
check_ushort(unsigned long num, int sign)
|
2011-11-14 07:54:34 +04:00
|
|
|
{
|
2012-06-20 10:31:32 +04:00
|
|
|
if (sign) {
|
2011-11-14 07:54:34 +04:00
|
|
|
/* minus */
|
2013-04-01 07:06:09 +04:00
|
|
|
if (num < (unsigned long)SHRT_MIN)
|
|
|
|
rb_raise(rb_eRangeError, "integer %ld too small to convert to `unsigned short'", (long)num);
|
2011-11-14 07:54:34 +04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* plus */
|
2013-04-01 07:06:09 +04:00
|
|
|
if (USHRT_MAX < num)
|
|
|
|
rb_raise(rb_eRangeError, "integer %lu too big to convert to `unsigned short'", num);
|
2011-11-14 07:54:34 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
short
|
|
|
|
rb_num2short(VALUE val)
|
|
|
|
{
|
|
|
|
long num = rb_num2long(val);
|
|
|
|
|
|
|
|
check_short(num);
|
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
|
|
|
short
|
|
|
|
rb_fix2short(VALUE val)
|
|
|
|
{
|
|
|
|
long num = FIXNUM_P(val)?FIX2LONG(val):rb_num2long(val);
|
|
|
|
|
|
|
|
check_short(num);
|
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned short
|
|
|
|
rb_num2ushort(VALUE val)
|
|
|
|
{
|
2013-03-31 08:51:29 +04:00
|
|
|
int wrap;
|
|
|
|
unsigned long num = rb_num2ulong_internal(val, &wrap);
|
2011-11-14 07:54:34 +04:00
|
|
|
|
2013-03-31 08:51:29 +04:00
|
|
|
check_ushort(num, wrap);
|
|
|
|
return num;
|
2011-11-14 07:54:34 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned short
|
|
|
|
rb_fix2ushort(VALUE val)
|
|
|
|
{
|
|
|
|
unsigned long num;
|
|
|
|
|
|
|
|
if (!FIXNUM_P(val)) {
|
2011-11-14 09:53:59 +04:00
|
|
|
return rb_num2ushort(val);
|
2011-11-14 07:54:34 +04:00
|
|
|
}
|
|
|
|
num = FIX2ULONG(val);
|
|
|
|
|
2021-08-16 22:51:11 +03:00
|
|
|
check_ushort(num, FIXNUM_NEGATIVE_P(val));
|
2011-11-14 07:54:34 +04:00
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
rb_num2fix(VALUE val)
|
1999-01-20 07:59:39 +03:00
|
|
|
{
|
2013-04-01 15:08:44 +04:00
|
|
|
long v;
|
1999-01-20 07:59:39 +03:00
|
|
|
|
2017-03-09 05:31:23 +03:00
|
|
|
if (FIXNUM_P(val)) return val;
|
|
|
|
|
|
|
|
v = rb_num2long(val);
|
|
|
|
if (!FIXABLE(v))
|
2017-03-08 07:50:22 +03:00
|
|
|
rb_raise(rb_eRangeError, "integer %ld out of range of fixnum", v);
|
2017-03-09 05:31:23 +03:00
|
|
|
return LONG2FIX(v);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2002-03-14 09:23:46 +03:00
|
|
|
#if HAVE_LONG_LONG
|
|
|
|
|
2010-07-02 00:39:32 +04:00
|
|
|
#define LLONG_MIN_MINUS_ONE ((double)LLONG_MIN-1)
|
|
|
|
#define LLONG_MAX_PLUS_ONE (2*(double)(LLONG_MAX/2+1))
|
|
|
|
#define ULLONG_MAX_PLUS_ONE (2*(double)(ULLONG_MAX/2+1))
|
2011-07-09 11:54:38 +04:00
|
|
|
#ifndef ULLONG_MAX
|
|
|
|
#define ULLONG_MAX ((unsigned LONG_LONG)LLONG_MAX*2+1)
|
|
|
|
#endif
|
2013-03-27 17:12:27 +04:00
|
|
|
#define LLONG_MIN_MINUS_ONE_IS_LESS_THAN(n) \
|
|
|
|
(LLONG_MIN_MINUS_ONE == (double)LLONG_MIN ? \
|
|
|
|
LLONG_MIN <= (n): \
|
|
|
|
LLONG_MIN_MINUS_ONE < (n))
|
2010-07-02 00:39:32 +04:00
|
|
|
|
* bignum.c, intern.h (rb_ull2big, rb_ll2big, rb_ull2inum, rb_ll2inum,
big2ull, rb_big2ull, rb_big2ll): use LONG_LONG macro instead of
long long.
* numeric.c, intern.h, ruby.h (rb_num2ll, rb_num2ull): ditto.
* ruby.h: use _I64_MAX and _I64_MIN if they are defined (for VC++).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@2207 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2002-03-15 11:51:31 +03:00
|
|
|
LONG_LONG
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
rb_num2ll(VALUE val)
|
2002-03-14 09:23:46 +03:00
|
|
|
{
|
|
|
|
if (NIL_P(val)) {
|
|
|
|
rb_raise(rb_eTypeError, "no implicit conversion from nil");
|
|
|
|
}
|
|
|
|
|
* bignum.c, intern.h (rb_ull2big, rb_ll2big, rb_ull2inum, rb_ll2inum,
big2ull, rb_big2ull, rb_big2ll): use LONG_LONG macro instead of
long long.
* numeric.c, intern.h, ruby.h (rb_num2ll, rb_num2ull): ditto.
* ruby.h: use _I64_MAX and _I64_MIN if they are defined (for VC++).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@2207 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2002-03-15 11:51:31 +03:00
|
|
|
if (FIXNUM_P(val)) return (LONG_LONG)FIX2LONG(val);
|
2002-03-14 09:23:46 +03:00
|
|
|
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(val)) {
|
2017-09-22 07:56:24 +03:00
|
|
|
double d = RFLOAT_VALUE(val);
|
|
|
|
if (d < LLONG_MAX_PLUS_ONE && (LLONG_MIN_MINUS_ONE_IS_LESS_THAN(d))) {
|
|
|
|
return (LONG_LONG)d;
|
2002-03-14 09:23:46 +03:00
|
|
|
}
|
|
|
|
else {
|
2014-01-15 12:16:38 +04:00
|
|
|
FLOAT_OUT_OF_RANGE(val, "long long");
|
2002-03-14 09:23:46 +03:00
|
|
|
}
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(val)) {
|
2002-03-14 09:23:46 +03:00
|
|
|
return rb_big2ll(val);
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
|
|
|
else if (RB_TYPE_P(val, T_STRING)) {
|
2002-03-14 09:23:46 +03:00
|
|
|
rb_raise(rb_eTypeError, "no implicit conversion from string");
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
|
|
|
else if (RB_TYPE_P(val, T_TRUE) || RB_TYPE_P(val, T_FALSE)) {
|
2002-03-14 09:23:46 +03:00
|
|
|
rb_raise(rb_eTypeError, "no implicit conversion from boolean");
|
|
|
|
}
|
2012-04-14 04:36:26 +04:00
|
|
|
|
2012-04-15 04:06:13 +04:00
|
|
|
val = rb_to_int(val);
|
|
|
|
return NUM2LL(val);
|
2002-03-14 09:23:46 +03:00
|
|
|
}
|
|
|
|
|
* bignum.c, intern.h (rb_ull2big, rb_ll2big, rb_ull2inum, rb_ll2inum,
big2ull, rb_big2ull, rb_big2ll): use LONG_LONG macro instead of
long long.
* numeric.c, intern.h, ruby.h (rb_num2ll, rb_num2ull): ditto.
* ruby.h: use _I64_MAX and _I64_MIN if they are defined (for VC++).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@2207 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2002-03-15 11:51:31 +03:00
|
|
|
unsigned LONG_LONG
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
rb_num2ull(VALUE val)
|
2002-03-14 09:23:46 +03:00
|
|
|
{
|
2021-09-03 19:25:36 +03:00
|
|
|
if (NIL_P(val)) {
|
2011-07-07 10:23:40 +04:00
|
|
|
rb_raise(rb_eTypeError, "no implicit conversion from nil");
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-11 07:45:22 +03:00
|
|
|
else if (FIXNUM_P(val)) {
|
2016-11-01 15:35:30 +03:00
|
|
|
return (LONG_LONG)FIX2LONG(val); /* this is FIX2LONG, intended */
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(val)) {
|
2017-09-22 07:56:24 +03:00
|
|
|
double d = RFLOAT_VALUE(val);
|
|
|
|
if (d < ULLONG_MAX_PLUS_ONE && LLONG_MIN_MINUS_ONE_IS_LESS_THAN(d)) {
|
|
|
|
if (0 <= d)
|
|
|
|
return (unsigned LONG_LONG)d;
|
|
|
|
return (unsigned LONG_LONG)(LONG_LONG)d;
|
2011-07-07 10:23:40 +04:00
|
|
|
}
|
|
|
|
else {
|
2014-01-15 12:16:38 +04:00
|
|
|
FLOAT_OUT_OF_RANGE(val, "unsigned long long");
|
2011-07-07 10:23:40 +04:00
|
|
|
}
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(val)) {
|
2002-03-14 09:23:46 +03:00
|
|
|
return rb_big2ull(val);
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
|
|
|
else if (RB_TYPE_P(val, T_STRING)) {
|
2011-07-07 10:23:40 +04:00
|
|
|
rb_raise(rb_eTypeError, "no implicit conversion from string");
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
|
|
|
else if (RB_TYPE_P(val, T_TRUE) || RB_TYPE_P(val, T_FALSE)) {
|
2011-07-07 10:23:40 +04:00
|
|
|
rb_raise(rb_eTypeError, "no implicit conversion from boolean");
|
2002-03-14 09:23:46 +03:00
|
|
|
}
|
2012-04-14 04:36:26 +04:00
|
|
|
|
2012-04-15 04:06:13 +04:00
|
|
|
val = rb_to_int(val);
|
|
|
|
return NUM2ULL(val);
|
2002-03-14 09:23:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* HAVE_LONG_LONG */
|
|
|
|
|
2016-10-26 09:11:23 +03:00
|
|
|
/********************************************************************
|
|
|
|
*
|
2021-11-25 22:14:10 +03:00
|
|
|
* Document-class: Integer
|
2003-12-27 08:46:46 +03:00
|
|
|
*
|
2021-11-25 22:14:10 +03:00
|
|
|
* An \Integer object represents an integer value.
|
2021-11-23 04:04:25 +03:00
|
|
|
*
|
2021-11-27 22:07:37 +03:00
|
|
|
* You can create an \Integer object explicitly with:
|
|
|
|
*
|
2022-02-07 19:26:39 +03:00
|
|
|
* - An {integer literal}[rdoc-ref:syntax/literals.rdoc@Integer+Literals].
|
2021-11-27 22:07:37 +03:00
|
|
|
*
|
2021-12-03 16:12:28 +03:00
|
|
|
* You can convert certain objects to Integers with:
|
|
|
|
*
|
2022-02-07 19:18:56 +03:00
|
|
|
* - \Method #Integer.
|
2021-12-03 16:12:28 +03:00
|
|
|
*
|
2021-11-25 22:14:10 +03:00
|
|
|
* An attempt to add a singleton method to an instance of this class
|
|
|
|
* causes an exception to be raised.
|
2021-11-23 04:04:25 +03:00
|
|
|
*
|
|
|
|
* == What's Here
|
|
|
|
*
|
|
|
|
* First, what's elsewhere. \Class \Integer:
|
|
|
|
*
|
2022-02-06 18:30:11 +03:00
|
|
|
* - Inherits from {class Numeric}[rdoc-ref:Numeric@What-27s+Here].
|
2021-11-23 04:04:25 +03:00
|
|
|
*
|
|
|
|
* Here, class \Integer provides methods for:
|
|
|
|
*
|
2022-02-06 18:37:06 +03:00
|
|
|
* - {Querying}[rdoc-ref:Integer@Querying]
|
|
|
|
* - {Comparing}[rdoc-ref:Integer@Comparing]
|
|
|
|
* - {Converting}[rdoc-ref:Integer@Converting]
|
|
|
|
* - {Other}[rdoc-ref:Integer@Other]
|
2021-11-23 04:04:25 +03:00
|
|
|
*
|
|
|
|
* === Querying
|
|
|
|
*
|
2022-03-25 23:43:46 +03:00
|
|
|
* - #allbits?: Returns whether all bits in +self+ are set.
|
|
|
|
* - #anybits?: Returns whether any bits in +self+ are set.
|
|
|
|
* - #nobits?: Returns whether no bits in +self+ are set.
|
2021-11-23 04:04:25 +03:00
|
|
|
*
|
|
|
|
* === Comparing
|
|
|
|
*
|
2022-03-26 15:07:06 +03:00
|
|
|
* - #<: Returns whether +self+ is less than the given value.
|
|
|
|
* - #<=: Returns whether +self+ is less than or equal to the given value.
|
|
|
|
* - #<=>: Returns a number indicating whether +self+ is less than, equal
|
2022-03-25 23:43:46 +03:00
|
|
|
* to, or greater than the given value.
|
|
|
|
* - #== (aliased as #===): Returns whether +self+ is equal to the given
|
2022-02-11 04:30:28 +03:00
|
|
|
* value.
|
2022-03-26 15:07:06 +03:00
|
|
|
* - #>: Returns whether +self+ is greater than the given value.
|
|
|
|
* - #>=: Returns whether +self+ is greater than or equal to the given value.
|
2021-11-23 04:04:25 +03:00
|
|
|
*
|
|
|
|
* === Converting
|
|
|
|
*
|
2022-03-25 23:43:46 +03:00
|
|
|
* - ::sqrt: Returns the integer square root of the given value.
|
|
|
|
* - ::try_convert: Returns the given value converted to an \Integer.
|
|
|
|
* - #% (aliased as #modulo): Returns +self+ modulo the given value.
|
2022-03-26 15:07:06 +03:00
|
|
|
* - #&: Returns the bitwise AND of +self+ and the given value.
|
2022-03-25 23:43:46 +03:00
|
|
|
* - #*: Returns the product of +self+ and the given value.
|
|
|
|
* - #**: Returns the value of +self+ raised to the power of the given value.
|
|
|
|
* - #+: Returns the sum of +self+ and the given value.
|
|
|
|
* - #-: Returns the difference of +self+ and the given value.
|
2022-03-26 15:07:06 +03:00
|
|
|
* - #/: Returns the quotient of +self+ and the given value.
|
2022-03-25 23:43:46 +03:00
|
|
|
* - #<<: Returns the value of +self+ after a leftward bit-shift.
|
|
|
|
* - #>>: Returns the value of +self+ after a rightward bit-shift.
|
|
|
|
* - #[]: Returns a slice of bits from +self+.
|
2022-03-26 15:07:06 +03:00
|
|
|
* - #^: Returns the bitwise EXCLUSIVE OR of +self+ and the given value.
|
2022-03-25 23:43:46 +03:00
|
|
|
* - #ceil: Returns the smallest number greater than or equal to +self+.
|
|
|
|
* - #chr: Returns a 1-character string containing the character
|
|
|
|
* represented by the value of +self+.
|
|
|
|
* - #digits: Returns an array of integers representing the base-radix digits
|
|
|
|
* of +self+.
|
|
|
|
* - #div: Returns the integer result of dividing +self+ by the given value.
|
|
|
|
* - #divmod: Returns a 2-element array containing the quotient and remainder
|
|
|
|
* results of dividing +self+ by the given value.
|
|
|
|
* - #fdiv: Returns the Float result of dividing +self+ by the given value.
|
|
|
|
* - #floor: Returns the greatest number smaller than or equal to +self+.
|
|
|
|
* - #pow: Returns the modular exponentiation of +self+.
|
|
|
|
* - #pred: Returns the integer predecessor of +self+.
|
|
|
|
* - #remainder: Returns the remainder after dividing +self+ by the given value.
|
|
|
|
* - #round: Returns +self+ rounded to the nearest value with the given precision.
|
|
|
|
* - #succ (aliased as #next): Returns the integer successor of +self+.
|
|
|
|
* - #to_f: Returns +self+ converted to a Float.
|
|
|
|
* - #to_s (aliased as #inspect): Returns a string containing the place-value
|
|
|
|
* representation of +self+ in the given radix.
|
|
|
|
* - #truncate: Returns +self+ truncated to the given precision.
|
2022-03-26 15:07:06 +03:00
|
|
|
* - #|: Returns the bitwise OR of +self+ and the given value.
|
2021-11-23 04:04:25 +03:00
|
|
|
*
|
|
|
|
* === Other
|
|
|
|
*
|
2022-03-25 23:43:46 +03:00
|
|
|
* - #downto: Calls the given block with each integer value from +self+
|
|
|
|
* down to the given value.
|
|
|
|
* - #times: Calls the given block +self+ times with each integer
|
|
|
|
* in <tt>(0..self-1)</tt>.
|
|
|
|
* - #upto: Calls the given block with each integer value from +self+
|
|
|
|
* up to the given value.
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2003-12-27 08:46:46 +03:00
|
|
|
*/
|
|
|
|
|
2017-12-04 05:35:40 +03:00
|
|
|
VALUE
|
|
|
|
rb_int_odd_p(VALUE num)
|
2006-09-21 10:09:26 +04:00
|
|
|
{
|
2016-03-17 20:11:42 +03:00
|
|
|
if (FIXNUM_P(num)) {
|
2021-08-02 06:06:44 +03:00
|
|
|
return RBOOL(num & 2);
|
2016-03-17 20:11:42 +03:00
|
|
|
}
|
2020-06-16 20:13:54 +03:00
|
|
|
else {
|
2021-09-03 14:50:12 +03:00
|
|
|
assert(RB_BIGNUM_TYPE_P(num));
|
2016-03-17 20:11:42 +03:00
|
|
|
return rb_big_odd_p(num);
|
|
|
|
}
|
2006-09-21 10:09:26 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
int_even_p(VALUE num)
|
|
|
|
{
|
2016-03-17 20:15:33 +03:00
|
|
|
if (FIXNUM_P(num)) {
|
2021-08-02 06:06:44 +03:00
|
|
|
return RBOOL((num & 2) == 0);
|
2016-03-17 20:15:33 +03:00
|
|
|
}
|
2020-06-16 20:13:54 +03:00
|
|
|
else {
|
2021-09-03 14:50:12 +03:00
|
|
|
assert(RB_BIGNUM_TYPE_P(num));
|
2016-03-17 20:15:33 +03:00
|
|
|
return rb_big_even_p(num);
|
|
|
|
}
|
2006-09-21 10:09:26 +04:00
|
|
|
}
|
|
|
|
|
2020-07-10 05:49:50 +03:00
|
|
|
VALUE
|
|
|
|
rb_int_even_p(VALUE num)
|
|
|
|
{
|
|
|
|
return int_even_p(num);
|
|
|
|
}
|
|
|
|
|
2017-12-12 12:12:14 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-15 22:52:23 +03:00
|
|
|
* allbits?(mask) -> true or false
|
|
|
|
*
|
|
|
|
* Returns +true+ if all bits that are set (=1) in +mask+
|
|
|
|
* are also set in +self+; returns +false+ otherwise.
|
|
|
|
*
|
|
|
|
* Example values:
|
|
|
|
*
|
|
|
|
* 0b1010101 self
|
|
|
|
* 0b1010100 mask
|
|
|
|
* 0b1010100 self & mask
|
|
|
|
* true self.allbits?(mask)
|
|
|
|
*
|
|
|
|
* 0b1010100 self
|
|
|
|
* 0b1010101 mask
|
|
|
|
* 0b1010100 self & mask
|
|
|
|
* false self.allbits?(mask)
|
|
|
|
*
|
|
|
|
* Related: Integer#anybits?, Integer#nobits?.
|
2017-12-12 12:12:14 +03:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
int_allbits_p(VALUE num, VALUE mask)
|
|
|
|
{
|
2017-12-17 21:19:41 +03:00
|
|
|
mask = rb_to_int(mask);
|
2017-12-12 12:12:14 +03:00
|
|
|
return rb_int_equal(rb_int_and(num, mask), mask);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-15 22:52:23 +03:00
|
|
|
* anybits?(mask) -> true or false
|
|
|
|
*
|
|
|
|
* Returns +true+ if any bit that is set (=1) in +mask+
|
|
|
|
* is also set in +self+; returns +false+ otherwise.
|
|
|
|
*
|
|
|
|
* Example values:
|
|
|
|
*
|
|
|
|
* 0b10000010 self
|
|
|
|
* 0b11111111 mask
|
|
|
|
* 0b10000010 self & mask
|
|
|
|
* true self.anybits?(mask)
|
|
|
|
*
|
|
|
|
* 0b00000000 self
|
|
|
|
* 0b11111111 mask
|
|
|
|
* 0b00000000 self & mask
|
|
|
|
* false self.anybits?(mask)
|
|
|
|
*
|
|
|
|
* Related: Integer#allbits?, Integer#nobits?.
|
2017-12-12 12:12:14 +03:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
int_anybits_p(VALUE num, VALUE mask)
|
|
|
|
{
|
2017-12-17 21:19:41 +03:00
|
|
|
mask = rb_to_int(mask);
|
2022-01-01 09:41:00 +03:00
|
|
|
return RBOOL(!int_zero_p(rb_int_and(num, mask)));
|
2017-12-12 12:12:14 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-15 22:52:23 +03:00
|
|
|
* nobits?(mask) -> true or false
|
|
|
|
*
|
|
|
|
* Returns +true+ if no bit that is set (=1) in +mask+
|
|
|
|
* is also set in +self+; returns +false+ otherwise.
|
|
|
|
*
|
|
|
|
* Example values:
|
|
|
|
*
|
|
|
|
* 0b11110000 self
|
|
|
|
* 0b00001111 mask
|
|
|
|
* 0b00000000 self & mask
|
|
|
|
* true self.nobits?(mask)
|
|
|
|
*
|
|
|
|
* 0b00000001 self
|
|
|
|
* 0b11111111 mask
|
|
|
|
* 0b00000001 self & mask
|
|
|
|
* false self.nobits?(mask)
|
|
|
|
*
|
|
|
|
* Related: Integer#allbits?, Integer#anybits?.
|
2017-12-12 12:12:14 +03:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
int_nobits_p(VALUE num, VALUE mask)
|
|
|
|
{
|
2017-12-17 21:19:41 +03:00
|
|
|
mask = rb_to_int(mask);
|
2022-01-01 10:06:07 +03:00
|
|
|
return RBOOL(int_zero_p(rb_int_and(num, mask)));
|
2017-12-12 12:12:14 +03:00
|
|
|
}
|
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-15 22:52:23 +03:00
|
|
|
* succ -> next_integer
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-11-15 22:52:23 +03:00
|
|
|
* Returns the successor integer of +self+ (equivalent to <tt>self + 1</tt>):
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-11-15 22:52:23 +03:00
|
|
|
* 1.succ #=> 2
|
|
|
|
* -1.succ #=> 0
|
|
|
|
*
|
|
|
|
* Integer#next is an alias for Integer#succ.
|
|
|
|
*
|
|
|
|
* Related: Integer#pred (predecessor value).
|
2006-12-31 18:02:22 +03:00
|
|
|
*/
|
|
|
|
|
2013-03-05 05:20:20 +04:00
|
|
|
VALUE
|
|
|
|
rb_int_succ(VALUE num)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2002-03-22 10:26:42 +03:00
|
|
|
if (FIXNUM_P(num)) {
|
|
|
|
long i = FIX2LONG(num) + 1;
|
2002-08-28 12:05:23 +04:00
|
|
|
return LONG2NUM(i);
|
2002-03-22 10:26:42 +03:00
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
if (RB_BIGNUM_TYPE_P(num)) {
|
2013-03-05 05:18:55 +04:00
|
|
|
return rb_big_plus(num, INT2FIX(1));
|
|
|
|
}
|
2016-08-13 17:08:03 +03:00
|
|
|
return num_funcall1(num, '+', INT2FIX(1));
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2013-03-05 05:20:20 +04:00
|
|
|
#define int_succ rb_int_succ
|
|
|
|
|
2007-01-30 07:27:04 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-15 22:52:23 +03:00
|
|
|
* pred -> next_integer
|
|
|
|
*
|
|
|
|
* Returns the predecessor of +self+ (equivalent to <tt>self - 1</tt>):
|
|
|
|
*
|
|
|
|
* 1.pred #=> 0
|
|
|
|
* -1.pred #=> -2
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-11-15 22:52:23 +03:00
|
|
|
* Related: Integer#succ (successor value).
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2007-01-30 07:27:04 +03:00
|
|
|
*/
|
|
|
|
|
2019-11-18 06:13:08 +03:00
|
|
|
static VALUE
|
2013-03-05 05:20:20 +04:00
|
|
|
rb_int_pred(VALUE num)
|
2007-01-30 07:27:04 +03:00
|
|
|
{
|
|
|
|
if (FIXNUM_P(num)) {
|
|
|
|
long i = FIX2LONG(num) - 1;
|
|
|
|
return LONG2NUM(i);
|
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
if (RB_BIGNUM_TYPE_P(num)) {
|
2013-03-05 05:18:55 +04:00
|
|
|
return rb_big_minus(num, INT2FIX(1));
|
|
|
|
}
|
2016-08-13 17:08:03 +03:00
|
|
|
return num_funcall1(num, '-', INT2FIX(1));
|
2007-01-30 07:27:04 +03:00
|
|
|
}
|
|
|
|
|
2013-03-05 05:20:20 +04:00
|
|
|
#define int_pred rb_int_pred
|
|
|
|
|
2010-10-12 10:18:08 +04:00
|
|
|
VALUE
|
2014-06-03 00:23:47 +04:00
|
|
|
rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
|
2010-10-12 10:18:08 +04:00
|
|
|
{
|
|
|
|
int n;
|
|
|
|
VALUE str;
|
2012-01-09 00:42:45 +04:00
|
|
|
switch (n = rb_enc_codelen(code, enc)) {
|
|
|
|
case ONIGERR_INVALID_CODE_POINT_VALUE:
|
|
|
|
rb_raise(rb_eRangeError, "invalid codepoint 0x%X in %s", code, rb_enc_name(enc));
|
|
|
|
break;
|
|
|
|
case ONIGERR_TOO_BIG_WIDE_CHAR_VALUE:
|
|
|
|
case 0:
|
2011-06-11 11:52:34 +04:00
|
|
|
rb_raise(rb_eRangeError, "%u out of char range", code);
|
2012-01-09 00:42:45 +04:00
|
|
|
break;
|
2010-10-12 10:18:08 +04:00
|
|
|
}
|
|
|
|
str = rb_enc_str_new(0, n, enc);
|
|
|
|
rb_enc_mbcput(code, RSTRING_PTR(str), enc);
|
2012-01-09 00:42:45 +04:00
|
|
|
if (rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_END(str), enc) != n) {
|
|
|
|
rb_raise(rb_eRangeError, "invalid codepoint 0x%X in %s", code, rb_enc_name(enc));
|
|
|
|
}
|
2010-10-12 10:18:08 +04:00
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2021-11-15 22:52:23 +03:00
|
|
|
/* call-seq:
|
|
|
|
* chr -> string
|
|
|
|
* chr(encoding) -> string
|
|
|
|
*
|
|
|
|
* Returns a 1-character string containing the character
|
|
|
|
* represented by the value of +self+, according to the given +encoding+.
|
|
|
|
*
|
|
|
|
* 65.chr # => "A"
|
2022-02-13 06:17:18 +03:00
|
|
|
* 0.chr # => "\x00"
|
2021-11-15 22:52:23 +03:00
|
|
|
* 255.chr # => "\xFF"
|
|
|
|
* string = 255.chr(Encoding::UTF_8)
|
|
|
|
* string.encoding # => Encoding::UTF_8
|
|
|
|
*
|
|
|
|
* Raises an exception if +self+ is negative.
|
|
|
|
*
|
|
|
|
* Related: Integer#ord.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
static VALUE
|
2007-10-26 12:38:14 +04:00
|
|
|
int_chr(int argc, VALUE *argv, VALUE num)
|
1999-01-20 07:59:39 +03:00
|
|
|
{
|
|
|
|
char c;
|
2010-10-13 16:13:53 +04:00
|
|
|
unsigned int i;
|
2007-10-26 12:38:14 +04:00
|
|
|
rb_encoding *enc;
|
|
|
|
|
2010-10-13 16:13:53 +04:00
|
|
|
if (rb_num_to_uint(num, &i) == 0) {
|
|
|
|
}
|
|
|
|
else if (FIXNUM_P(num)) {
|
|
|
|
rb_raise(rb_eRangeError, "%ld out of char range", FIX2LONG(num));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
rb_raise(rb_eRangeError, "bignum out of char range");
|
|
|
|
}
|
|
|
|
|
2007-10-26 12:38:14 +04:00
|
|
|
switch (argc) {
|
|
|
|
case 0:
|
2009-06-26 22:18:12 +04:00
|
|
|
if (0xff < i) {
|
|
|
|
enc = rb_default_internal_encoding();
|
2010-10-12 12:50:30 +04:00
|
|
|
if (!enc) {
|
2020-09-29 00:35:27 +03:00
|
|
|
rb_raise(rb_eRangeError, "%u out of char range", i);
|
2010-10-12 12:50:30 +04:00
|
|
|
}
|
2009-06-26 22:18:12 +04:00
|
|
|
goto decode;
|
|
|
|
}
|
* array.c, bignum.c, dln.c, error.c, gc.c, io.c, marshal.c,
numeric.c, pack.c, strftime.c, string.c, thread.c, transcode.c,
transcode_data.h, util.c, variable.c, vm_dump.c,
include/ruby/encoding.h, missing/crypt.c, missing/vsnprintf.c:
suppress VC type warnings. [ruby-core:22726]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@22914 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2009-03-12 12:16:15 +03:00
|
|
|
c = (char)i;
|
* string.c (rb_str_usascii_new{,2}: defined.
(rb_str_new): set US-ASCII and ENC_CODERANGE_7BIT when empty
string.
* encoding.c (rb_usascii_encoding, rb_usascii_encindex): defined.
(rb_enc_inspect, enc_name, rb_locale_charmap, rb_enc_name_list_i):
use rb_str_ascii_new.
* array.c (recursive_join, inspect_ary): ditto.
* object.c (nil_to_s, nil_inspect, true_to_s, false_to_s,
rb_mod_to_s): ditto.
* hash.c (inspect_hash, rb_hash_inspect, rb_f_getenv, env_fetch,
env_clear, env_to_s, env_inspect): ditto.
* numeric.c (flo_to_s, int_chr, rb_fix2str): ditto.
* bignum.c (rb_big2str): ditto.
* file.c (rb_file_ftype, rb_file_s_dirname, rb_file_s_extname,
file_inspect_join, Init_file): ditto.
* test/ruby/test_ruby_m17n.rb: add checks for encoding of string.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@15244 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-01-25 19:40:02 +03:00
|
|
|
if (i < 0x80) {
|
|
|
|
return rb_usascii_str_new(&c, 1);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return rb_str_new(&c, 1);
|
|
|
|
}
|
2007-10-26 12:38:14 +04:00
|
|
|
case 1:
|
|
|
|
break;
|
|
|
|
default:
|
2019-07-14 11:16:35 +03:00
|
|
|
rb_error_arity(argc, 0, 1);
|
2007-10-26 12:38:14 +04:00
|
|
|
}
|
|
|
|
enc = rb_to_encoding(argv[0]);
|
2007-12-23 02:47:18 +03:00
|
|
|
if (!enc) enc = rb_ascii8bit_encoding();
|
2009-06-26 22:18:12 +04:00
|
|
|
decode:
|
2010-10-12 10:18:08 +04:00
|
|
|
return rb_enc_uint_chr(i, enc);
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
|
|
|
|
2016-10-26 09:11:23 +03:00
|
|
|
/*
|
|
|
|
* Fixnum
|
2003-12-23 19:21:17 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
fix_uminus(VALUE num)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2002-08-28 12:05:23 +04:00
|
|
|
return LONG2NUM(-FIX2LONG(num));
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2016-03-26 04:54:16 +03:00
|
|
|
VALUE
|
|
|
|
rb_int_uminus(VALUE num)
|
|
|
|
{
|
|
|
|
if (FIXNUM_P(num)) {
|
|
|
|
return fix_uminus(num);
|
|
|
|
}
|
2020-12-23 09:23:45 +03:00
|
|
|
else {
|
2021-09-03 14:50:12 +03:00
|
|
|
assert(RB_BIGNUM_TYPE_P(num));
|
2016-03-26 04:54:16 +03:00
|
|
|
return rb_big_uminus(num);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
rb_fix2str(VALUE x, int base)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2016-02-24 05:20:45 +03:00
|
|
|
char buf[SIZEOF_VALUE*CHAR_BIT + 1], *const e = buf + sizeof buf, *b = e;
|
2002-01-11 12:18:54 +03:00
|
|
|
long val = FIX2LONG(x);
|
2016-03-14 07:41:16 +03:00
|
|
|
unsigned long u;
|
2003-04-14 10:54:27 +04:00
|
|
|
int neg = 0;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2003-04-14 10:54:27 +04:00
|
|
|
if (base < 2 || 36 < base) {
|
* regerror.c, string.c, io.c, lib/getoptlong.rb, lib/net/imap.rb,
compile.c, sprintf.c, parse.y, ext/win32ole/win32ole.c,
ext/tk/sample/demos-en/entry3.rb, ext/tk/lib/tcltk.rb,
ext/openssl/ossl_bn.c, numeric.c, vm.c,
benchmark/bm_so_meteor_contest.rb, bignum.c, ruby.c: don't "illegal"
for non law violation context.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@14377 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-12-21 05:31:11 +03:00
|
|
|
rb_raise(rb_eArgError, "invalid radix %d", base);
|
2003-04-14 10:54:27 +04:00
|
|
|
}
|
2016-10-01 20:04:04 +03:00
|
|
|
#if SIZEOF_LONG < SIZEOF_VOIDP
|
|
|
|
# if SIZEOF_VOIDP == SIZEOF_LONG_LONG
|
|
|
|
if ((val >= 0 && (x & 0xFFFFFFFF00000000ull)) ||
|
|
|
|
(val < 0 && (x & 0xFFFFFFFF00000000ull) != 0xFFFFFFFF00000000ull)) {
|
2016-10-02 06:32:07 +03:00
|
|
|
rb_bug("Unnormalized Fixnum value %p", (void *)x);
|
2016-10-01 20:04:04 +03:00
|
|
|
}
|
2016-11-17 11:50:36 +03:00
|
|
|
# else
|
2016-10-01 20:04:04 +03:00
|
|
|
/* should do something like above code, but currently ruby does not know */
|
|
|
|
/* such platforms */
|
|
|
|
# endif
|
|
|
|
#endif
|
2003-04-14 10:54:27 +04:00
|
|
|
if (val == 0) {
|
* string.c (rb_str_usascii_new{,2}: defined.
(rb_str_new): set US-ASCII and ENC_CODERANGE_7BIT when empty
string.
* encoding.c (rb_usascii_encoding, rb_usascii_encindex): defined.
(rb_enc_inspect, enc_name, rb_locale_charmap, rb_enc_name_list_i):
use rb_str_ascii_new.
* array.c (recursive_join, inspect_ary): ditto.
* object.c (nil_to_s, nil_inspect, true_to_s, false_to_s,
rb_mod_to_s): ditto.
* hash.c (inspect_hash, rb_hash_inspect, rb_f_getenv, env_fetch,
env_clear, env_to_s, env_inspect): ditto.
* numeric.c (flo_to_s, int_chr, rb_fix2str): ditto.
* bignum.c (rb_big2str): ditto.
* file.c (rb_file_ftype, rb_file_s_dirname, rb_file_s_extname,
file_inspect_join, Init_file): ditto.
* test/ruby/test_ruby_m17n.rb: add checks for encoding of string.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@15244 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-01-25 19:40:02 +03:00
|
|
|
return rb_usascii_str_new2("0");
|
2003-04-14 10:54:27 +04:00
|
|
|
}
|
2002-01-11 12:18:54 +03:00
|
|
|
if (val < 0) {
|
2016-03-14 07:41:16 +03:00
|
|
|
u = 1 + (unsigned long)(-(val + 1)); /* u = -val avoiding overflow */
|
2003-04-14 10:54:27 +04:00
|
|
|
neg = 1;
|
|
|
|
}
|
2016-03-14 07:41:16 +03:00
|
|
|
else {
|
|
|
|
u = val;
|
|
|
|
}
|
2003-04-14 10:54:27 +04:00
|
|
|
do {
|
2016-03-14 07:41:16 +03:00
|
|
|
*--b = ruby_digitmap[(int)(u % base)];
|
|
|
|
} while (u /= base);
|
2003-04-14 10:54:27 +04:00
|
|
|
if (neg) {
|
|
|
|
*--b = '-';
|
2002-01-11 12:18:54 +03:00
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2016-02-24 05:20:45 +03:00
|
|
|
return rb_usascii_str_new(b, e - b);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
Optimize dynamic string interpolation for symbol/true/false/nil/0-9
This provides a significant speedup for symbol, true, false,
nil, and 0-9, class/module, and a small speedup in most other cases.
Speedups (using included benchmarks):
:symbol :: 60%
0-9 :: 50%
Class/Module :: 50%
nil/true/false :: 20%
integer :: 10%
[] :: 10%
"" :: 3%
One reason this approach is faster is it reduces the number of
VM instructions for each interpolated value.
Initial idea, approach, and benchmarks from Eric Wong. I applied
the same approach against the master branch, updating it to handle
the significant internal changes since this was first proposed 4
years ago (such as CALL_INFO/CALL_CACHE -> CALL_DATA). I also
expanded it to optimize true/false/nil/0-9/class/module, and added
handling of missing methods, refined methods, and RUBY_DEBUG.
This renames the tostring insn to anytostring, and adds an
objtostring insn that implements the optimization. This requires
making a few functions non-static, and adding some non-static
functions.
This disables 4 YJIT tests. Those tests should be reenabled after
YJIT optimizes the new objtostring insn.
Implements [Feature #13715]
Co-authored-by: Eric Wong <e@80x24.org>
Co-authored-by: Alan Wu <XrXr@users.noreply.github.com>
Co-authored-by: Yusuke Endoh <mame@ruby-lang.org>
Co-authored-by: Koichi Sasada <ko1@atdot.net>
2021-11-19 02:10:20 +03:00
|
|
|
static VALUE rb_fix_to_s_static[10];
|
|
|
|
|
|
|
|
MJIT_FUNC_EXPORTED VALUE
|
|
|
|
rb_fix_to_s(VALUE x)
|
|
|
|
{
|
|
|
|
long i = FIX2LONG(x);
|
|
|
|
if (i >= 0 && i < 10) {
|
|
|
|
return rb_fix_to_s_static[i];
|
|
|
|
}
|
|
|
|
return rb_fix2str(x, 10);
|
|
|
|
}
|
|
|
|
|
2021-11-15 22:52:23 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* to_s(base = 10) -> string
|
|
|
|
*
|
|
|
|
* Returns a string containing the place-value representation of +self+
|
|
|
|
* in radix +base+ (in 2..36).
|
|
|
|
*
|
|
|
|
* 12345.to_s # => "12345"
|
|
|
|
* 12345.to_s(2) # => "11000000111001"
|
|
|
|
* 12345.to_s(8) # => "30071"
|
|
|
|
* 12345.to_s(10) # => "12345"
|
|
|
|
* 12345.to_s(16) # => "3039"
|
|
|
|
* 12345.to_s(36) # => "9ix"
|
|
|
|
* 78546939656932.to_s(36) # => "rubyrules"
|
|
|
|
*
|
|
|
|
* Raises an exception if +base+ is out of range.
|
|
|
|
*
|
|
|
|
* Integer#inspect is an alias for Integer#to_s.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
Optimize dynamic string interpolation for symbol/true/false/nil/0-9
This provides a significant speedup for symbol, true, false,
nil, and 0-9, class/module, and a small speedup in most other cases.
Speedups (using included benchmarks):
:symbol :: 60%
0-9 :: 50%
Class/Module :: 50%
nil/true/false :: 20%
integer :: 10%
[] :: 10%
"" :: 3%
One reason this approach is faster is it reduces the number of
VM instructions for each interpolated value.
Initial idea, approach, and benchmarks from Eric Wong. I applied
the same approach against the master branch, updating it to handle
the significant internal changes since this was first proposed 4
years ago (such as CALL_INFO/CALL_CACHE -> CALL_DATA). I also
expanded it to optimize true/false/nil/0-9/class/module, and added
handling of missing methods, refined methods, and RUBY_DEBUG.
This renames the tostring insn to anytostring, and adds an
objtostring insn that implements the optimization. This requires
making a few functions non-static, and adding some non-static
functions.
This disables 4 YJIT tests. Those tests should be reenabled after
YJIT optimizes the new objtostring insn.
Implements [Feature #13715]
Co-authored-by: Eric Wong <e@80x24.org>
Co-authored-by: Alan Wu <XrXr@users.noreply.github.com>
Co-authored-by: Yusuke Endoh <mame@ruby-lang.org>
Co-authored-by: Koichi Sasada <ko1@atdot.net>
2021-11-19 02:10:20 +03:00
|
|
|
MJIT_FUNC_EXPORTED VALUE
|
|
|
|
rb_int_to_s(int argc, VALUE *argv, VALUE x)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2001-11-19 08:03:03 +03:00
|
|
|
int base;
|
|
|
|
|
2016-04-02 09:33:26 +03:00
|
|
|
if (rb_check_arity(argc, 0, 1))
|
|
|
|
base = NUM2INT(argv[0]);
|
|
|
|
else
|
|
|
|
base = 10;
|
2016-03-26 04:55:14 +03:00
|
|
|
return rb_int2str(x, base);
|
|
|
|
}
|
2001-11-19 08:03:03 +03:00
|
|
|
|
2016-03-26 04:55:14 +03:00
|
|
|
VALUE
|
|
|
|
rb_int2str(VALUE x, int base)
|
|
|
|
{
|
2016-03-18 15:57:40 +03:00
|
|
|
if (FIXNUM_P(x)) {
|
|
|
|
return rb_fix2str(x, base);
|
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(x)) {
|
2016-03-18 15:57:40 +03:00
|
|
|
return rb_big2str(x, base);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rb_any_to_s(x);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
fix_plus(VALUE x, VALUE y)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
1999-01-20 07:59:39 +03:00
|
|
|
if (FIXNUM_P(y)) {
|
2017-02-02 18:54:51 +03:00
|
|
|
return rb_fix_plus_fix(x, y);
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(y)) {
|
2005-08-03 11:09:48 +04:00
|
|
|
return rb_big_plus(y, x);
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(y)) {
|
2008-09-05 22:24:21 +04:00
|
|
|
return DBL2NUM((double)FIX2LONG(x) + RFLOAT_VALUE(y));
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2015-02-24 16:59:06 +03:00
|
|
|
else if (RB_TYPE_P(y, T_COMPLEX)) {
|
2016-07-12 16:17:04 +03:00
|
|
|
return rb_complex_plus(y, x);
|
2015-02-24 16:59:06 +03:00
|
|
|
}
|
2013-09-11 12:23:06 +04:00
|
|
|
else {
|
2008-02-12 05:46:21 +03:00
|
|
|
return rb_num_coerce_bin(x, y, '+');
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-17 12:50:19 +03:00
|
|
|
VALUE
|
|
|
|
rb_fix_plus(VALUE x, VALUE y)
|
|
|
|
{
|
|
|
|
return fix_plus(x, y);
|
|
|
|
}
|
|
|
|
|
2021-11-15 22:52:23 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-16 22:42:05 +03:00
|
|
|
* self + numeric -> numeric_result
|
2021-11-15 22:52:23 +03:00
|
|
|
*
|
|
|
|
* Performs addition:
|
|
|
|
*
|
|
|
|
* 2 + 2 # => 4
|
|
|
|
* -2 + 2 # => 0
|
|
|
|
* -2 + -2 # => -4
|
|
|
|
* 2 + 2.0 # => 4.0
|
|
|
|
* 2 + Rational(2, 1) # => (4/1)
|
|
|
|
* 2 + Complex(2, 0) # => (4+0i)
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2016-03-26 04:54:16 +03:00
|
|
|
VALUE
|
|
|
|
rb_int_plus(VALUE x, VALUE y)
|
|
|
|
{
|
|
|
|
if (FIXNUM_P(x)) {
|
|
|
|
return fix_plus(x, y);
|
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(x)) {
|
2016-03-26 04:54:16 +03:00
|
|
|
return rb_big_plus(x, y);
|
|
|
|
}
|
|
|
|
return rb_num_coerce_bin(x, y, '+');
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
fix_minus(VALUE x, VALUE y)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
1999-01-20 07:59:39 +03:00
|
|
|
if (FIXNUM_P(y)) {
|
2017-02-02 18:54:51 +03:00
|
|
|
return rb_fix_minus_fix(x, y);
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(y)) {
|
2005-08-03 11:09:48 +04:00
|
|
|
x = rb_int2big(FIX2LONG(x));
|
|
|
|
return rb_big_minus(x, y);
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(y)) {
|
2008-09-05 22:24:21 +04:00
|
|
|
return DBL2NUM((double)FIX2LONG(x) - RFLOAT_VALUE(y));
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
|
|
|
else {
|
2008-02-12 05:46:21 +03:00
|
|
|
return rb_num_coerce_bin(x, y, '-');
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-15 22:52:23 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-18 17:28:04 +03:00
|
|
|
* self - numeric -> numeric_result
|
2021-11-15 22:52:23 +03:00
|
|
|
*
|
|
|
|
* Performs subtraction:
|
|
|
|
*
|
|
|
|
* 4 - 2 # => 2
|
|
|
|
* -4 - 2 # => -6
|
|
|
|
* -4 - -2 # => -2
|
|
|
|
* 4 - 2.0 # => 2.0
|
|
|
|
* 4 - Rational(2, 1) # => (2/1)
|
|
|
|
* 4 - Complex(2, 0) # => (2+0i)
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2016-03-26 04:54:16 +03:00
|
|
|
VALUE
|
|
|
|
rb_int_minus(VALUE x, VALUE y)
|
|
|
|
{
|
|
|
|
if (FIXNUM_P(x)) {
|
|
|
|
return fix_minus(x, y);
|
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(x)) {
|
2016-03-26 04:54:16 +03:00
|
|
|
return rb_big_minus(x, y);
|
|
|
|
}
|
|
|
|
return rb_num_coerce_bin(x, y, '-');
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-12-04 05:35:40 +03:00
|
|
|
#define SQRT_LONG_MAX HALF_LONG_MSB
|
2007-12-24 10:52:39 +03:00
|
|
|
/*tests if N*N would overflow*/
|
|
|
|
#define FIT_SQRT_LONG(n) (((n)<SQRT_LONG_MAX)&&((n)>=-SQRT_LONG_MAX))
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
fix_mul(VALUE x, VALUE y)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
1999-01-20 07:59:39 +03:00
|
|
|
if (FIXNUM_P(y)) {
|
2016-03-20 14:10:43 +03:00
|
|
|
return rb_fix_mul_fix(x, y);
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(y)) {
|
2017-01-10 15:18:21 +03:00
|
|
|
switch (x) {
|
|
|
|
case INT2FIX(0): return x;
|
|
|
|
case INT2FIX(1): return y;
|
|
|
|
}
|
2005-08-03 11:09:48 +04:00
|
|
|
return rb_big_mul(y, x);
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(y)) {
|
2008-09-05 22:24:21 +04:00
|
|
|
return DBL2NUM((double)FIX2LONG(x) * RFLOAT_VALUE(y));
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2015-02-24 16:59:06 +03:00
|
|
|
else if (RB_TYPE_P(y, T_COMPLEX)) {
|
2016-07-12 16:17:04 +03:00
|
|
|
return rb_complex_mul(y, x);
|
2015-02-24 16:59:06 +03:00
|
|
|
}
|
2013-09-11 12:23:06 +04:00
|
|
|
else {
|
2008-02-12 05:46:21 +03:00
|
|
|
return rb_num_coerce_bin(x, y, '*');
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-16 22:42:05 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* self * numeric -> numeric_result
|
|
|
|
*
|
|
|
|
* Performs multiplication:
|
|
|
|
*
|
|
|
|
* 4 * 2 # => 8
|
|
|
|
* 4 * -2 # => -8
|
|
|
|
* -4 * 2 # => -8
|
|
|
|
* 4 * 2.0 # => 8.0
|
|
|
|
* 4 * Rational(1, 3) # => (4/3)
|
|
|
|
* 4 * Complex(2, 0) # => (8+0i)
|
|
|
|
*/
|
|
|
|
|
2016-03-26 04:54:16 +03:00
|
|
|
VALUE
|
|
|
|
rb_int_mul(VALUE x, VALUE y)
|
|
|
|
{
|
|
|
|
if (FIXNUM_P(x)) {
|
|
|
|
return fix_mul(x, y);
|
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(x)) {
|
2016-03-26 04:54:16 +03:00
|
|
|
return rb_big_mul(x, y);
|
|
|
|
}
|
|
|
|
return rb_num_coerce_bin(x, y, '*');
|
|
|
|
}
|
|
|
|
|
2016-11-11 18:55:30 +03:00
|
|
|
static double
|
|
|
|
fix_fdiv_double(VALUE x, VALUE y)
|
|
|
|
{
|
|
|
|
if (FIXNUM_P(y)) {
|
2018-11-16 07:05:53 +03:00
|
|
|
return double_div_double(FIX2LONG(x), FIX2LONG(y));
|
2016-11-11 18:55:30 +03:00
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(y)) {
|
2016-11-11 18:55:30 +03:00
|
|
|
return rb_big_fdiv_double(rb_int2big(FIX2LONG(x)), y);
|
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(y)) {
|
2018-11-16 04:52:39 +03:00
|
|
|
return double_div_double(FIX2LONG(x), RFLOAT_VALUE(y));
|
2016-11-11 18:55:30 +03:00
|
|
|
}
|
|
|
|
else {
|
2019-08-03 02:37:08 +03:00
|
|
|
return NUM2DBL(rb_num_coerce_bin(x, y, idFdiv));
|
2016-11-11 18:55:30 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
double
|
|
|
|
rb_int_fdiv_double(VALUE x, VALUE y)
|
|
|
|
{
|
2016-12-28 07:40:58 +03:00
|
|
|
if (RB_INTEGER_TYPE_P(y) && !FIXNUM_ZERO_P(y)) {
|
|
|
|
VALUE gcd = rb_gcd(x, y);
|
|
|
|
if (!FIXNUM_ZERO_P(gcd)) {
|
|
|
|
x = rb_int_idiv(x, gcd);
|
|
|
|
y = rb_int_idiv(y, gcd);
|
|
|
|
}
|
|
|
|
}
|
2016-11-11 18:55:30 +03:00
|
|
|
if (FIXNUM_P(x)) {
|
|
|
|
return fix_fdiv_double(x, y);
|
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(x)) {
|
2016-11-11 18:55:30 +03:00
|
|
|
return rb_big_fdiv_double(x, y);
|
|
|
|
}
|
2018-01-19 04:45:36 +03:00
|
|
|
else {
|
|
|
|
return nan("");
|
|
|
|
}
|
2016-11-11 18:55:30 +03:00
|
|
|
}
|
|
|
|
|
2003-12-23 19:21:17 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-16 22:42:05 +03:00
|
|
|
* fdiv(numeric) -> float
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-11-16 22:42:05 +03:00
|
|
|
* Returns the Float result of dividing +self+ by +numeric+:
|
|
|
|
*
|
|
|
|
* 4.fdiv(2) # => 2.0
|
|
|
|
* 4.fdiv(-2) # => -2.0
|
|
|
|
* -4.fdiv(2) # => -2.0
|
|
|
|
* 4.fdiv(2.0) # => 2.0
|
|
|
|
* 4.fdiv(Rational(3, 4)) # => 5.333333333333333
|
|
|
|
*
|
|
|
|
* Raises an exception if +numeric+ cannot be converted to a Float.
|
2016-04-30 07:20:56 +03:00
|
|
|
*
|
2003-12-23 19:21:17 +03:00
|
|
|
*/
|
|
|
|
|
2016-11-10 18:23:33 +03:00
|
|
|
VALUE
|
|
|
|
rb_int_fdiv(VALUE x, VALUE y)
|
2016-04-30 07:20:56 +03:00
|
|
|
{
|
2016-11-11 18:55:30 +03:00
|
|
|
if (RB_INTEGER_TYPE_P(x)) {
|
|
|
|
return DBL2NUM(rb_int_fdiv_double(x, y));
|
2016-04-30 07:20:56 +03:00
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
2008-05-01 19:00:01 +04:00
|
|
|
fix_divide(VALUE x, VALUE y, ID op)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
1999-01-20 07:59:39 +03:00
|
|
|
if (FIXNUM_P(y)) {
|
2016-11-11 17:39:25 +03:00
|
|
|
if (FIXNUM_ZERO_P(y)) rb_num_zerodiv();
|
2016-03-21 16:36:03 +03:00
|
|
|
return rb_fix_div_fix(x, y);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(y)) {
|
2005-08-03 11:09:48 +04:00
|
|
|
x = rb_int2big(FIX2LONG(x));
|
|
|
|
return rb_big_div(x, y);
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(y)) {
|
2008-05-01 19:00:01 +04:00
|
|
|
if (op == '/') {
|
2018-11-16 04:52:39 +03:00
|
|
|
double d = FIX2LONG(x);
|
|
|
|
return rb_flo_div_flo(DBL2NUM(d), y);
|
2008-05-01 19:00:01 +04:00
|
|
|
}
|
|
|
|
else {
|
2018-11-16 04:52:39 +03:00
|
|
|
VALUE v;
|
2008-05-27 16:51:28 +04:00
|
|
|
if (RFLOAT_VALUE(y) == 0) rb_num_zerodiv();
|
2018-11-16 04:52:39 +03:00
|
|
|
v = fix_divide(x, y, '/');
|
|
|
|
return flo_floor(0, 0, v);
|
2008-05-01 19:00:01 +04:00
|
|
|
}
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (RB_TYPE_P(y, T_RATIONAL) &&
|
|
|
|
op == '/' && FIX2LONG(x) == 1)
|
2009-07-12 15:46:40 +04:00
|
|
|
return rb_rational_reciprocal(y);
|
2008-05-01 19:00:01 +04:00
|
|
|
return rb_num_coerce_bin(x, y, op);
|
2005-08-03 11:09:48 +04:00
|
|
|
}
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
|
|
|
|
2005-10-05 20:15:16 +04:00
|
|
|
static VALUE
|
|
|
|
fix_div(VALUE x, VALUE y)
|
|
|
|
{
|
2008-05-01 19:00:01 +04:00
|
|
|
return fix_divide(x, y, '/');
|
2005-10-05 20:15:16 +04:00
|
|
|
}
|
|
|
|
|
2021-11-16 22:42:05 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* self / numeric -> numeric_result
|
|
|
|
*
|
2021-11-17 21:51:32 +03:00
|
|
|
* Performs division; for integer +numeric+, truncates the result to an integer:
|
2021-11-16 22:42:05 +03:00
|
|
|
*
|
|
|
|
* 4 / 3 # => 1
|
|
|
|
* 4 / -3 # => -2
|
|
|
|
* -4 / 3 # => -2
|
|
|
|
* -4 / -3 # => 1
|
2021-11-17 21:51:32 +03:00
|
|
|
*
|
|
|
|
* For other +numeric+, returns non-integer result:
|
|
|
|
*
|
2021-11-16 22:42:05 +03:00
|
|
|
* 4 / 3.0 # => 1.3333333333333333
|
|
|
|
* 4 / Rational(3, 1) # => (4/3)
|
|
|
|
* 4 / Complex(3, 0) # => ((4/3)+0i)
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2016-04-30 15:39:53 +03:00
|
|
|
VALUE
|
|
|
|
rb_int_div(VALUE x, VALUE y)
|
|
|
|
{
|
|
|
|
if (FIXNUM_P(x)) {
|
|
|
|
return fix_div(x, y);
|
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(x)) {
|
2016-04-30 15:39:53 +03:00
|
|
|
return rb_big_div(x, y);
|
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
2005-10-05 20:15:16 +04:00
|
|
|
static VALUE
|
|
|
|
fix_idiv(VALUE x, VALUE y)
|
|
|
|
{
|
2015-10-12 03:08:58 +03:00
|
|
|
return fix_divide(x, y, id_div);
|
2005-10-05 20:15:16 +04:00
|
|
|
}
|
|
|
|
|
2021-11-16 22:42:05 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* div(numeric) -> integer
|
|
|
|
*
|
|
|
|
* Performs integer division; returns the integer result of dividing +self+
|
|
|
|
* by +numeric+:
|
|
|
|
*
|
|
|
|
* 4.div(3) # => 1
|
|
|
|
* 4.div(-3) # => -2
|
|
|
|
* -4.div(3) # => -2
|
|
|
|
* -4.div(-3) # => 1
|
|
|
|
* 4.div(3.0) # => 1
|
|
|
|
* 4.div(Rational(3, 1)) # => 1
|
|
|
|
*
|
|
|
|
* Raises an exception if +numeric+ does not have method +div+.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2016-03-26 04:54:16 +03:00
|
|
|
VALUE
|
|
|
|
rb_int_idiv(VALUE x, VALUE y)
|
|
|
|
{
|
|
|
|
if (FIXNUM_P(x)) {
|
|
|
|
return fix_idiv(x, y);
|
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(x)) {
|
2016-03-26 04:54:16 +03:00
|
|
|
return rb_big_idiv(x, y);
|
|
|
|
}
|
|
|
|
return num_div(x, y);
|
|
|
|
}
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
fix_mod(VALUE x, VALUE y)
|
1999-01-20 07:59:39 +03:00
|
|
|
{
|
2000-07-03 09:46:36 +04:00
|
|
|
if (FIXNUM_P(y)) {
|
2016-11-11 17:39:25 +03:00
|
|
|
if (FIXNUM_ZERO_P(y)) rb_num_zerodiv();
|
2016-03-21 16:36:03 +03:00
|
|
|
return rb_fix_mod_fix(x, y);
|
2000-07-03 09:46:36 +04:00
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(y)) {
|
2005-08-03 11:09:48 +04:00
|
|
|
x = rb_int2big(FIX2LONG(x));
|
|
|
|
return rb_big_modulo(x, y);
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(y)) {
|
2012-03-14 10:10:01 +04:00
|
|
|
return DBL2NUM(ruby_float_mod((double)FIX2LONG(x), RFLOAT_VALUE(y)));
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
|
|
|
else {
|
2008-02-12 05:46:21 +03:00
|
|
|
return rb_num_coerce_bin(x, y, '%');
|
2005-08-03 11:09:48 +04:00
|
|
|
}
|
1999-01-20 07:59:39 +03:00
|
|
|
}
|
|
|
|
|
2021-10-15 19:57:49 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* self % other -> real_number
|
|
|
|
*
|
|
|
|
* Returns +self+ modulo +other+ as a real number.
|
|
|
|
*
|
|
|
|
* For integer +n+ and real number +r+, these expressions are equivalent:
|
|
|
|
*
|
|
|
|
* n % r
|
|
|
|
* n-r*(n/r).floor
|
|
|
|
* n.divmod(r)[1]
|
|
|
|
*
|
|
|
|
* See Numeric#divmod.
|
|
|
|
*
|
|
|
|
* Examples:
|
|
|
|
*
|
|
|
|
* 10 % 2 # => 0
|
|
|
|
* 10 % 3 # => 1
|
|
|
|
* 10 % 4 # => 2
|
|
|
|
*
|
|
|
|
* 10 % -2 # => 0
|
|
|
|
* 10 % -3 # => -2
|
|
|
|
* 10 % -4 # => -2
|
|
|
|
*
|
|
|
|
* 10 % 3.0 # => 1.0
|
|
|
|
* 10 % Rational(3, 1) # => (1/1)
|
|
|
|
*
|
|
|
|
* Integer#modulo is an alias for Integer#%.
|
|
|
|
*
|
|
|
|
*/
|
2016-03-26 04:54:16 +03:00
|
|
|
VALUE
|
|
|
|
rb_int_modulo(VALUE x, VALUE y)
|
|
|
|
{
|
|
|
|
if (FIXNUM_P(x)) {
|
|
|
|
return fix_mod(x, y);
|
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(x)) {
|
2016-03-26 04:54:16 +03:00
|
|
|
return rb_big_modulo(x, y);
|
|
|
|
}
|
|
|
|
return num_modulo(x, y);
|
|
|
|
}
|
|
|
|
|
2016-04-30 11:27:30 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-10-16 00:20:52 +03:00
|
|
|
* remainder(other) -> real_number
|
|
|
|
*
|
|
|
|
* Returns the remainder after dividing +self+ by +other+.
|
2016-04-30 11:27:30 +03:00
|
|
|
*
|
2021-10-16 00:20:52 +03:00
|
|
|
* Examples:
|
2016-04-30 11:27:30 +03:00
|
|
|
*
|
2021-10-16 00:20:52 +03:00
|
|
|
* 11.remainder(4) # => 3
|
|
|
|
* 11.remainder(-4) # => 3
|
|
|
|
* -11.remainder(4) # => -3
|
|
|
|
* -11.remainder(-4) # => -3
|
2016-04-30 11:27:30 +03:00
|
|
|
*
|
2021-10-16 00:20:52 +03:00
|
|
|
* 12.remainder(4) # => 0
|
|
|
|
* 12.remainder(-4) # => 0
|
|
|
|
* -12.remainder(4) # => 0
|
|
|
|
* -12.remainder(-4) # => 0
|
|
|
|
*
|
|
|
|
* 13.remainder(4.0) # => 1.0
|
|
|
|
* 13.remainder(Rational(4, 1)) # => (1/1)
|
2016-04-30 11:27:30 +03:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2018-11-16 09:52:00 +03:00
|
|
|
static VALUE
|
2016-04-30 11:27:30 +03:00
|
|
|
int_remainder(VALUE x, VALUE y)
|
|
|
|
{
|
|
|
|
if (FIXNUM_P(x)) {
|
|
|
|
return num_remainder(x, y);
|
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(x)) {
|
2016-04-30 11:27:30 +03:00
|
|
|
return rb_big_remainder(x, y);
|
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
fix_divmod(VALUE x, VALUE y)
|
1999-01-20 07:59:39 +03:00
|
|
|
{
|
2000-07-03 09:46:36 +04:00
|
|
|
if (FIXNUM_P(y)) {
|
2016-03-21 16:36:03 +03:00
|
|
|
VALUE div, mod;
|
2016-11-11 17:39:25 +03:00
|
|
|
if (FIXNUM_ZERO_P(y)) rb_num_zerodiv();
|
2016-03-21 16:36:03 +03:00
|
|
|
rb_fix_divmod_fix(x, y, &div, &mod);
|
|
|
|
return rb_assoc_new(div, mod);
|
2000-07-03 09:46:36 +04:00
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(y)) {
|
2005-08-03 11:09:48 +04:00
|
|
|
x = rb_int2big(FIX2LONG(x));
|
|
|
|
return rb_big_divmod(x, y);
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(y)) {
|
2005-08-03 11:09:48 +04:00
|
|
|
{
|
|
|
|
double div, mod;
|
|
|
|
volatile VALUE a, b;
|
|
|
|
|
* include/ruby/ruby.h: introduce 2 macros:
RFLOAT_VALUE(v), DOUBLE2NUM(dbl).
Rename RFloat#value -> RFloat#double_value.
Do not touch RFloat#double_value directly.
* bignum.c, insns.def, marshal.c, math.c, numeric.c, object.c,
pack.c, parse.y, process.c, random.c, sprintf.c, string.c,
time.c: apply above changes.
* ext/dl/mkcallback.rb, ext/json/ext/generator/generator.c:
ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13913 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-11-13 19:00:53 +03:00
|
|
|
flodivmod((double)FIX2LONG(x), RFLOAT_VALUE(y), &div, &mod);
|
2008-03-13 19:37:54 +03:00
|
|
|
a = dbl2ival(div);
|
2008-09-05 22:24:21 +04:00
|
|
|
b = DBL2NUM(mod);
|
2005-08-03 11:09:48 +04:00
|
|
|
return rb_assoc_new(a, b);
|
|
|
|
}
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
|
|
|
else {
|
2015-10-12 03:08:58 +03:00
|
|
|
return rb_num_coerce_bin(x, y, id_divmod);
|
2005-08-03 11:09:48 +04:00
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2021-10-15 20:51:37 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* divmod(other) -> array
|
|
|
|
*
|
|
|
|
* Returns a 2-element array <tt>[q, r]</tt>, where
|
|
|
|
*
|
|
|
|
* q = (self/other).floor # Quotient
|
|
|
|
* r = self % other # Remainder
|
|
|
|
*
|
|
|
|
* Examples:
|
|
|
|
*
|
|
|
|
* 11.divmod(4) # => [2, 3]
|
|
|
|
* 11.divmod(-4) # => [-3, -1]
|
|
|
|
* -11.divmod(4) # => [-3, 1]
|
|
|
|
* -11.divmod(-4) # => [2, -3]
|
|
|
|
*
|
|
|
|
* 12.divmod(4) # => [3, 0]
|
|
|
|
* 12.divmod(-4) # => [-3, 0]
|
|
|
|
* -12.divmod(4) # => [-3, 0]
|
|
|
|
* -12.divmod(-4) # => [3, 0]
|
|
|
|
*
|
|
|
|
* 13.divmod(4.0) # => [3, 1.0]
|
|
|
|
* 13.divmod(Rational(4, 1)) # => [3, (1/1)]
|
|
|
|
*
|
|
|
|
*/
|
rational.c: optimize Rational#{floor,ceil,round,truncate}
* rational.c (f_{expt10,round_common},nurat_{floor,ceil,round_half_{up,even}}):
optimize Rational#{floor,ceil,round,truncate}.
Author: Tadashi Saito <tad.a.digger@gmail.com>
* numeric.c (rb_int_divmod): rename from int_divmod to be exported.
* numeric.c (rb_int_and): rename from int_and to be exported.
* intern.h (rb_int_{divmod,and}): exported.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@56742 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2016-11-12 09:45:11 +03:00
|
|
|
VALUE
|
|
|
|
rb_int_divmod(VALUE x, VALUE y)
|
2016-04-30 08:05:54 +03:00
|
|
|
{
|
|
|
|
if (FIXNUM_P(x)) {
|
|
|
|
return fix_divmod(x, y);
|
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(x)) {
|
2016-04-30 08:05:54 +03:00
|
|
|
return rb_big_divmod(x, y);
|
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
2016-04-27 15:46:46 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-16 22:42:05 +03:00
|
|
|
* self ** numeric -> numeric_result
|
2016-04-27 15:46:46 +03:00
|
|
|
*
|
2021-11-16 22:42:05 +03:00
|
|
|
* Raises +self+ to the power of +numeric+:
|
2016-04-30 06:59:02 +03:00
|
|
|
*
|
2021-11-16 22:42:05 +03:00
|
|
|
* 2 ** 3 # => 8
|
|
|
|
* 2 ** -3 # => (1/8)
|
|
|
|
* -2 ** 3 # => -8
|
|
|
|
* -2 ** -3 # => (-1/8)
|
|
|
|
* 2 ** 3.3 # => 9.849155306759329
|
|
|
|
* 2 ** Rational(3, 1) # => (8/1)
|
|
|
|
* 2 ** Complex(3, 0) # => (8+0i)
|
2016-04-30 06:59:02 +03:00
|
|
|
*
|
2016-04-27 15:46:46 +03:00
|
|
|
*/
|
|
|
|
|
2007-04-26 12:30:10 +04:00
|
|
|
static VALUE
|
|
|
|
int_pow(long x, unsigned long y)
|
|
|
|
{
|
|
|
|
int neg = x < 0;
|
|
|
|
long z = 1;
|
|
|
|
|
2017-01-05 10:27:19 +03:00
|
|
|
if (y == 0) return INT2FIX(1);
|
2019-03-11 04:37:16 +03:00
|
|
|
if (y == 1) return LONG2NUM(x);
|
2007-04-26 12:30:10 +04:00
|
|
|
if (neg) x = -x;
|
2007-07-05 11:38:41 +04:00
|
|
|
if (y & 1)
|
|
|
|
z = x;
|
|
|
|
else
|
|
|
|
neg = 0;
|
2007-04-26 12:30:10 +04:00
|
|
|
y &= ~1;
|
|
|
|
do {
|
|
|
|
while (y % 2 == 0) {
|
2007-07-13 21:29:24 +04:00
|
|
|
if (!FIT_SQRT_LONG(x)) {
|
2020-06-16 04:05:46 +03:00
|
|
|
goto bignum;
|
2007-04-26 12:30:10 +04:00
|
|
|
}
|
2007-07-13 21:29:24 +04:00
|
|
|
x = x * x;
|
2007-04-26 12:30:10 +04:00
|
|
|
y >>= 1;
|
|
|
|
}
|
|
|
|
{
|
2013-04-09 15:39:53 +04:00
|
|
|
if (MUL_OVERFLOW_FIXNUM_P(x, z)) {
|
2007-04-26 12:30:10 +04:00
|
|
|
goto bignum;
|
|
|
|
}
|
2013-04-09 15:39:53 +04:00
|
|
|
z = x * z;
|
2007-04-26 12:30:10 +04:00
|
|
|
}
|
|
|
|
} while (--y);
|
2007-07-05 11:38:41 +04:00
|
|
|
if (neg) z = -z;
|
2007-04-26 12:30:10 +04:00
|
|
|
return LONG2NUM(z);
|
2020-06-16 04:05:46 +03:00
|
|
|
|
|
|
|
VALUE v;
|
|
|
|
bignum:
|
|
|
|
v = rb_big_pow(rb_int2big(x), LONG2NUM(y));
|
|
|
|
if (RB_FLOAT_TYPE_P(v)) /* infinity due to overflow */
|
|
|
|
return v;
|
|
|
|
if (z != 1) v = rb_big_mul(rb_int2big(neg ? -z : z), v);
|
|
|
|
return v;
|
2007-04-26 12:30:10 +04:00
|
|
|
}
|
|
|
|
|
2013-08-02 18:48:55 +04:00
|
|
|
VALUE
|
|
|
|
rb_int_positive_pow(long x, unsigned long y)
|
|
|
|
{
|
|
|
|
return int_pow(x, y);
|
|
|
|
}
|
|
|
|
|
2020-06-16 04:39:07 +03:00
|
|
|
static VALUE
|
|
|
|
fix_pow_inverted(VALUE x, VALUE minusb)
|
|
|
|
{
|
|
|
|
if (x == INT2FIX(0)) {
|
|
|
|
rb_num_zerodiv();
|
2020-06-24 10:23:59 +03:00
|
|
|
UNREACHABLE_RETURN(Qundef);
|
2020-06-16 04:39:07 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
VALUE y = rb_int_pow(x, minusb);
|
|
|
|
|
|
|
|
if (RB_FLOAT_TYPE_P(y)) {
|
|
|
|
double d = pow((double)FIX2LONG(x), RFLOAT_VALUE(y));
|
|
|
|
return DBL2NUM(1.0 / d);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return rb_rational_raw(INT2FIX(1), y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
fix_pow(VALUE x, VALUE y)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2007-07-14 18:31:21 +04:00
|
|
|
long a = FIX2LONG(x);
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
if (FIXNUM_P(y)) {
|
2007-07-14 18:31:21 +04:00
|
|
|
long b = FIX2LONG(y);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2013-02-05 09:39:49 +04:00
|
|
|
if (a == 1) return INT2FIX(1);
|
2020-06-16 04:39:07 +03:00
|
|
|
if (a == -1) return INT2FIX(b % 2 ? -1 : 1);
|
|
|
|
if (b < 0) return fix_pow_inverted(x, fix_uminus(y));
|
1998-01-16 15:13:05 +03:00
|
|
|
if (b == 0) return INT2FIX(1);
|
1999-08-13 09:45:20 +04:00
|
|
|
if (b == 1) return x;
|
2020-04-09 03:14:02 +03:00
|
|
|
if (a == 0) return INT2FIX(0);
|
2008-03-16 03:23:43 +03:00
|
|
|
return int_pow(a, b);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(y)) {
|
2007-07-14 18:31:21 +04:00
|
|
|
if (a == 1) return INT2FIX(1);
|
2020-06-16 04:39:07 +03:00
|
|
|
if (a == -1) return INT2FIX(int_even_p(y) ? 1 : -1);
|
|
|
|
if (BIGNUM_NEGATIVE_P(y)) return fix_pow_inverted(x, rb_big_uminus(y));
|
2013-02-05 09:39:49 +04:00
|
|
|
if (a == 0) return INT2FIX(0);
|
2005-08-03 11:09:48 +04:00
|
|
|
x = rb_int2big(FIX2LONG(x));
|
|
|
|
return rb_big_pow(x, y);
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(y)) {
|
2017-09-22 07:56:24 +03:00
|
|
|
double dy = RFLOAT_VALUE(y);
|
|
|
|
if (dy == 0.0) return DBL2NUM(1.0);
|
2007-10-26 12:01:41 +04:00
|
|
|
if (a == 0) {
|
2018-01-19 04:45:36 +03:00
|
|
|
return DBL2NUM(dy < 0 ? HUGE_VAL : 0.0);
|
2007-10-26 12:01:41 +04:00
|
|
|
}
|
2008-09-05 22:24:21 +04:00
|
|
|
if (a == 1) return DBL2NUM(1.0);
|
2020-06-16 04:39:07 +03:00
|
|
|
if (a < 0 && dy != round(dy))
|
|
|
|
return rb_dbl_complex_new_polar_pi(pow(-(double)a, dy), dy);
|
|
|
|
return DBL2NUM(pow((double)a, dy));
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
|
|
|
else {
|
2015-10-12 03:08:58 +03:00
|
|
|
return rb_num_coerce_bin(x, y, idPow);
|
2005-08-03 11:09:48 +04:00
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2021-11-18 17:28:04 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* self ** numeric -> numeric_result
|
|
|
|
*
|
|
|
|
* Raises +self+ to the power of +numeric+:
|
|
|
|
*
|
|
|
|
* 2 ** 3 # => 8
|
|
|
|
* 2 ** -3 # => (1/8)
|
|
|
|
* -2 ** 3 # => -8
|
|
|
|
* -2 ** -3 # => (-1/8)
|
|
|
|
* 2 ** 3.3 # => 9.849155306759329
|
|
|
|
* 2 ** Rational(3, 1) # => (8/1)
|
|
|
|
* 2 ** Complex(3, 0) # => (8+0i)
|
|
|
|
*
|
|
|
|
*/
|
2016-11-11 19:38:28 +03:00
|
|
|
VALUE
|
2016-04-30 06:59:02 +03:00
|
|
|
rb_int_pow(VALUE x, VALUE y)
|
|
|
|
{
|
|
|
|
if (FIXNUM_P(x)) {
|
|
|
|
return fix_pow(x, y);
|
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(x)) {
|
2016-04-30 06:59:02 +03:00
|
|
|
return rb_big_pow(x, y);
|
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
2018-10-20 05:49:18 +03:00
|
|
|
VALUE
|
|
|
|
rb_num_pow(VALUE x, VALUE y)
|
|
|
|
{
|
|
|
|
VALUE z = rb_int_pow(x, y);
|
|
|
|
if (!NIL_P(z)) return z;
|
|
|
|
if (RB_FLOAT_TYPE_P(x)) return rb_float_pow(x, y);
|
|
|
|
if (SPECIAL_CONST_P(x)) return Qnil;
|
|
|
|
switch (BUILTIN_TYPE(x)) {
|
|
|
|
case T_COMPLEX:
|
|
|
|
return rb_complex_pow(x, y);
|
|
|
|
case T_RATIONAL:
|
|
|
|
return rb_rational_pow(x, y);
|
2020-04-08 09:13:37 +03:00
|
|
|
default:
|
|
|
|
break;
|
2018-10-20 05:49:18 +03:00
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
fix_equal(VALUE x, VALUE y)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2007-02-21 16:30:17 +03:00
|
|
|
if (x == y) return Qtrue;
|
|
|
|
if (FIXNUM_P(y)) return Qfalse;
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(y)) {
|
2005-08-12 12:13:28 +04:00
|
|
|
return rb_big_eq(y, x);
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(y)) {
|
2012-07-16 14:39:42 +04:00
|
|
|
return rb_integer_float_eq(x, y);
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
|
|
|
else {
|
1998-01-16 15:13:05 +03:00
|
|
|
return num_equal(x, y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-17 21:51:32 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* self == other -> true or false
|
|
|
|
*
|
|
|
|
* Returns +true+ if +self+ is numerically equal to +other+; +false+ otherwise.
|
|
|
|
*
|
|
|
|
* 1 == 2 #=> false
|
|
|
|
* 1 == 1.0 #=> true
|
|
|
|
*
|
|
|
|
* Related: Integer#eql? (requires +other+ to be an \Integer).
|
|
|
|
*
|
|
|
|
* Integer#=== is an alias for Integer#==.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2016-11-12 05:24:32 +03:00
|
|
|
VALUE
|
|
|
|
rb_int_equal(VALUE x, VALUE y)
|
2016-04-30 14:18:00 +03:00
|
|
|
{
|
|
|
|
if (FIXNUM_P(x)) {
|
|
|
|
return fix_equal(x, y);
|
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(x)) {
|
2016-04-30 14:18:00 +03:00
|
|
|
return rb_big_eq(x, y);
|
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
2016-03-19 12:28:12 +03:00
|
|
|
static VALUE
|
|
|
|
fix_cmp(VALUE x, VALUE y)
|
|
|
|
{
|
|
|
|
if (x == y) return INT2FIX(0);
|
|
|
|
if (FIXNUM_P(y)) {
|
|
|
|
if (FIX2LONG(x) > FIX2LONG(y)) return INT2FIX(1);
|
|
|
|
return INT2FIX(-1);
|
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(y)) {
|
2016-03-19 15:53:36 +03:00
|
|
|
VALUE cmp = rb_big_cmp(y, x);
|
|
|
|
switch (cmp) {
|
|
|
|
case INT2FIX(+1): return INT2FIX(-1);
|
|
|
|
case INT2FIX(-1): return INT2FIX(+1);
|
|
|
|
}
|
|
|
|
return cmp;
|
2016-03-19 12:28:12 +03:00
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(y)) {
|
2016-03-19 12:28:12 +03:00
|
|
|
return rb_integer_float_cmp(x, y);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return rb_num_coerce_cmp(x, y, id_cmp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-17 21:51:32 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* self <=> other -> -1, 0, +1, or nil
|
|
|
|
*
|
|
|
|
* Returns:
|
|
|
|
*
|
|
|
|
* - -1, if +self+ is less than +other+.
|
|
|
|
* - 0, if +self+ is equal to +other+.
|
|
|
|
* - 1, if +self+ is greater then +other+.
|
|
|
|
* - +nil+, if +self+ and +other+ are incomparable.
|
|
|
|
*
|
|
|
|
* Examples:
|
|
|
|
*
|
|
|
|
* 1 <=> 2 # => -1
|
|
|
|
* 1 <=> 1 # => 0
|
|
|
|
* 1 <=> 0 # => 1
|
|
|
|
* 1 <=> 'foo' # => nil
|
|
|
|
*
|
|
|
|
* 1 <=> 1.0 # => 0
|
|
|
|
* 1 <=> Rational(1, 1) # => 0
|
|
|
|
* 1 <=> Complex(1, 0) # => 0
|
|
|
|
*
|
|
|
|
* This method is the basis for comparisons in module Comparable.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2016-11-12 04:29:01 +03:00
|
|
|
VALUE
|
|
|
|
rb_int_cmp(VALUE x, VALUE y)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2016-03-19 12:28:12 +03:00
|
|
|
if (FIXNUM_P(x)) {
|
|
|
|
return fix_cmp(x, y);
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(x)) {
|
2016-03-19 12:28:12 +03:00
|
|
|
return rb_big_cmp(x, y);
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
|
|
|
else {
|
2016-03-19 12:28:12 +03:00
|
|
|
rb_raise(rb_eNotImpError, "need to define `<=>' in %s", rb_obj_classname(x));
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
fix_gt(VALUE x, VALUE y)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
|
|
|
if (FIXNUM_P(y)) {
|
2021-09-15 02:11:05 +03:00
|
|
|
return RBOOL(FIX2LONG(x) > FIX2LONG(y));
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(y)) {
|
2021-08-02 06:06:44 +03:00
|
|
|
return RBOOL(rb_big_cmp(y, x) == INT2FIX(-1));
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(y)) {
|
2021-08-02 06:06:44 +03:00
|
|
|
return RBOOL(rb_integer_float_cmp(x, y) == INT2FIX(1));
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
|
|
|
else {
|
2008-02-12 05:46:21 +03:00
|
|
|
return rb_num_coerce_relop(x, y, '>');
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-17 21:51:32 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* self > other -> true or false
|
|
|
|
*
|
|
|
|
* Returns +true+ if the value of +self+ is greater than that of +other+:
|
|
|
|
*
|
|
|
|
* 1 > 0 # => true
|
|
|
|
* 1 > 1 # => false
|
|
|
|
* 1 > 2 # => false
|
|
|
|
* 1 > 0.5 # => true
|
|
|
|
* 1 > Rational(1, 2) # => true
|
|
|
|
*
|
|
|
|
* Raises an exception if the comparison cannot be made.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2016-11-22 08:21:12 +03:00
|
|
|
VALUE
|
|
|
|
rb_int_gt(VALUE x, VALUE y)
|
2016-04-30 13:42:06 +03:00
|
|
|
{
|
|
|
|
if (FIXNUM_P(x)) {
|
|
|
|
return fix_gt(x, y);
|
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(x)) {
|
2016-04-30 13:42:06 +03:00
|
|
|
return rb_big_gt(x, y);
|
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
fix_ge(VALUE x, VALUE y)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
|
|
|
if (FIXNUM_P(y)) {
|
2021-09-15 02:11:05 +03:00
|
|
|
return RBOOL(FIX2LONG(x) >= FIX2LONG(y));
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(y)) {
|
2021-08-02 06:06:44 +03:00
|
|
|
return RBOOL(rb_big_cmp(y, x) != INT2FIX(+1));
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(y)) {
|
2013-09-11 12:23:06 +04:00
|
|
|
VALUE rel = rb_integer_float_cmp(x, y);
|
2021-08-02 06:06:44 +03:00
|
|
|
return RBOOL(rel == INT2FIX(1) || rel == INT2FIX(0));
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
|
|
|
else {
|
2015-10-12 03:08:58 +03:00
|
|
|
return rb_num_coerce_relop(x, y, idGE);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-17 21:51:32 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* self >= real -> true or false
|
|
|
|
*
|
|
|
|
* Returns +true+ if the value of +self+ is greater than or equal to
|
|
|
|
* that of +other+:
|
|
|
|
*
|
|
|
|
* 1 >= 0 # => true
|
|
|
|
* 1 >= 1 # => true
|
|
|
|
* 1 >= 2 # => false
|
|
|
|
* 1 >= 0.5 # => true
|
|
|
|
* 1 >= Rational(1, 2) # => true
|
|
|
|
*
|
|
|
|
* Raises an exception if the comparison cannot be made.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2016-05-17 18:08:33 +03:00
|
|
|
VALUE
|
|
|
|
rb_int_ge(VALUE x, VALUE y)
|
2016-04-30 13:26:17 +03:00
|
|
|
{
|
|
|
|
if (FIXNUM_P(x)) {
|
|
|
|
return fix_ge(x, y);
|
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(x)) {
|
2016-04-30 13:26:17 +03:00
|
|
|
return rb_big_ge(x, y);
|
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
fix_lt(VALUE x, VALUE y)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
|
|
|
if (FIXNUM_P(y)) {
|
2021-09-15 02:11:05 +03:00
|
|
|
return RBOOL(FIX2LONG(x) < FIX2LONG(y));
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(y)) {
|
2021-08-02 06:06:44 +03:00
|
|
|
return RBOOL(rb_big_cmp(y, x) == INT2FIX(+1));
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(y)) {
|
2021-08-02 06:06:44 +03:00
|
|
|
return RBOOL(rb_integer_float_cmp(x, y) == INT2FIX(-1));
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
|
|
|
else {
|
2008-02-12 05:46:21 +03:00
|
|
|
return rb_num_coerce_relop(x, y, '<');
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-17 21:51:32 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* self < other -> true or false
|
|
|
|
*
|
|
|
|
* Returns +true+ if the value of +self+ is less than that of +other+:
|
|
|
|
*
|
|
|
|
* 1 < 0 # => false
|
|
|
|
* 1 < 1 # => false
|
|
|
|
* 1 < 2 # => true
|
|
|
|
* 1 < 0.5 # => false
|
|
|
|
* 1 < Rational(1, 2) # => false
|
|
|
|
*
|
|
|
|
* Raises an exception if the comparison cannot be made.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2016-04-30 13:10:23 +03:00
|
|
|
static VALUE
|
|
|
|
int_lt(VALUE x, VALUE y)
|
|
|
|
{
|
|
|
|
if (FIXNUM_P(x)) {
|
|
|
|
return fix_lt(x, y);
|
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(x)) {
|
2016-04-30 13:10:23 +03:00
|
|
|
return rb_big_lt(x, y);
|
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
fix_le(VALUE x, VALUE y)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
|
|
|
if (FIXNUM_P(y)) {
|
2021-09-15 02:11:05 +03:00
|
|
|
return RBOOL(FIX2LONG(x) <= FIX2LONG(y));
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(y)) {
|
2021-08-02 06:06:44 +03:00
|
|
|
return RBOOL(rb_big_cmp(y, x) != INT2FIX(-1));
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
2021-09-11 03:56:59 +03:00
|
|
|
else if (RB_FLOAT_TYPE_P(y)) {
|
2013-09-11 12:23:06 +04:00
|
|
|
VALUE rel = rb_integer_float_cmp(x, y);
|
2021-08-02 06:06:44 +03:00
|
|
|
return RBOOL(rel == INT2FIX(-1) || rel == INT2FIX(0));
|
2013-09-11 12:23:06 +04:00
|
|
|
}
|
|
|
|
else {
|
2015-10-12 03:08:58 +03:00
|
|
|
return rb_num_coerce_relop(x, y, idLE);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-17 21:51:32 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* self <= real -> true or false
|
|
|
|
*
|
|
|
|
* Returns +true+ if the value of +self+ is less than or equal to
|
|
|
|
* that of +other+:
|
|
|
|
*
|
|
|
|
* 1 <= 0 # => false
|
|
|
|
* 1 <= 1 # => true
|
|
|
|
* 1 <= 2 # => true
|
|
|
|
* 1 <= 0.5 # => false
|
|
|
|
* 1 <= Rational(1, 2) # => false
|
|
|
|
*
|
|
|
|
* Raises an exception if the comparison cannot be made.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2016-04-30 12:48:25 +03:00
|
|
|
static VALUE
|
|
|
|
int_le(VALUE x, VALUE y)
|
|
|
|
{
|
|
|
|
if (FIXNUM_P(x)) {
|
|
|
|
return fix_le(x, y);
|
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(x)) {
|
2016-04-30 12:48:25 +03:00
|
|
|
return rb_big_le(x, y);
|
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
2016-04-30 06:30:53 +03:00
|
|
|
fix_comp(VALUE num)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2010-07-07 14:59:44 +04:00
|
|
|
return ~num | FIXNUM_FLAG;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2020-12-23 09:23:45 +03:00
|
|
|
VALUE
|
|
|
|
rb_int_comp(VALUE num)
|
2016-04-30 06:27:20 +03:00
|
|
|
{
|
|
|
|
if (FIXNUM_P(num)) {
|
2016-04-30 06:30:53 +03:00
|
|
|
return fix_comp(num);
|
2016-04-30 06:27:20 +03:00
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(num)) {
|
2016-04-30 06:30:53 +03:00
|
|
|
return rb_big_comp(num);
|
2016-04-30 06:27:20 +03:00
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
2016-11-02 01:34:30 +03:00
|
|
|
static VALUE
|
|
|
|
num_funcall_bit_1(VALUE y, VALUE arg, int recursive)
|
2012-12-22 19:06:22 +04:00
|
|
|
{
|
2016-11-02 01:34:30 +03:00
|
|
|
ID func = (ID)((VALUE *)arg)[0];
|
|
|
|
VALUE x = ((VALUE *)arg)[1];
|
|
|
|
if (recursive) {
|
|
|
|
num_funcall_op_1_recursion(x, func, y);
|
2008-03-11 13:48:12 +03:00
|
|
|
}
|
2016-11-02 01:34:30 +03:00
|
|
|
return rb_check_funcall(x, func, 1, &y);
|
2012-12-22 19:06:22 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
|
|
|
rb_num_coerce_bit(VALUE x, VALUE y, ID func)
|
|
|
|
{
|
2016-11-02 01:34:30 +03:00
|
|
|
VALUE ret, args[3];
|
|
|
|
|
|
|
|
args[0] = (VALUE)func;
|
|
|
|
args[1] = x;
|
|
|
|
args[2] = y;
|
|
|
|
do_coerce(&args[1], &args[2], TRUE);
|
|
|
|
ret = rb_exec_recursive_paired(num_funcall_bit_1,
|
|
|
|
args[2], args[1], (VALUE)args);
|
|
|
|
if (ret == Qundef) {
|
|
|
|
/* show the original object, not coerced object */
|
|
|
|
coerce_failed(x, y);
|
|
|
|
}
|
|
|
|
return ret;
|
2008-03-11 13:48:12 +03:00
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
fix_and(VALUE x, VALUE y)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2012-12-22 19:06:22 +04:00
|
|
|
if (FIXNUM_P(y)) {
|
|
|
|
long val = FIX2LONG(x) & FIX2LONG(y);
|
|
|
|
return LONG2NUM(val);
|
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2021-09-03 14:50:12 +03:00
|
|
|
if (RB_BIGNUM_TYPE_P(y)) {
|
1999-01-20 07:59:39 +03:00
|
|
|
return rb_big_and(y, x);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2012-12-22 19:06:22 +04:00
|
|
|
|
2016-11-01 16:10:14 +03:00
|
|
|
return rb_num_coerce_bit(x, y, '&');
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2021-11-17 21:51:32 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* self & other -> integer
|
|
|
|
*
|
|
|
|
* Bitwise AND; each bit in the result is 1 if both corresponding bits
|
|
|
|
* in +self+ and +other+ are 1, 0 otherwise:
|
|
|
|
*
|
|
|
|
* "%04b" % (0b0101 & 0b0110) # => "0100"
|
|
|
|
*
|
|
|
|
* Raises an exception if +other+ is not an \Integer.
|
|
|
|
*
|
|
|
|
* Related: Integer#| (bitwise OR), Integer#^ (bitwise EXCLUSIVE OR).
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
rational.c: optimize Rational#{floor,ceil,round,truncate}
* rational.c (f_{expt10,round_common},nurat_{floor,ceil,round_half_{up,even}}):
optimize Rational#{floor,ceil,round,truncate}.
Author: Tadashi Saito <tad.a.digger@gmail.com>
* numeric.c (rb_int_divmod): rename from int_divmod to be exported.
* numeric.c (rb_int_and): rename from int_and to be exported.
* intern.h (rb_int_{divmod,and}): exported.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@56742 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2016-11-12 09:45:11 +03:00
|
|
|
VALUE
|
|
|
|
rb_int_and(VALUE x, VALUE y)
|
2016-04-30 06:08:53 +03:00
|
|
|
{
|
|
|
|
if (FIXNUM_P(x)) {
|
|
|
|
return fix_and(x, y);
|
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(x)) {
|
2016-04-30 06:08:53 +03:00
|
|
|
return rb_big_and(x, y);
|
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
fix_or(VALUE x, VALUE y)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2012-12-22 19:06:22 +04:00
|
|
|
if (FIXNUM_P(y)) {
|
|
|
|
long val = FIX2LONG(x) | FIX2LONG(y);
|
|
|
|
return LONG2NUM(val);
|
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2021-09-03 14:50:12 +03:00
|
|
|
if (RB_BIGNUM_TYPE_P(y)) {
|
1999-01-20 07:59:39 +03:00
|
|
|
return rb_big_or(y, x);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2012-12-22 19:06:22 +04:00
|
|
|
|
2016-11-01 16:10:14 +03:00
|
|
|
return rb_num_coerce_bit(x, y, '|');
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2021-11-17 21:51:32 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* self | other -> integer
|
|
|
|
*
|
|
|
|
* Bitwise OR; each bit in the result is 1 if either corresponding bit
|
|
|
|
* in +self+ or +other+ is 1, 0 otherwise:
|
|
|
|
*
|
|
|
|
* "%04b" % (0b0101 | 0b0110) # => "0111"
|
|
|
|
*
|
|
|
|
* Raises an exception if +other+ is not an \Integer.
|
|
|
|
*
|
|
|
|
* Related: Integer#& (bitwise AND), Integer#^ (bitwise EXCLUSIVE OR).
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2016-04-30 05:54:14 +03:00
|
|
|
static VALUE
|
|
|
|
int_or(VALUE x, VALUE y)
|
|
|
|
{
|
|
|
|
if (FIXNUM_P(x)) {
|
|
|
|
return fix_or(x, y);
|
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(x)) {
|
2016-04-30 05:54:14 +03:00
|
|
|
return rb_big_or(x, y);
|
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
fix_xor(VALUE x, VALUE y)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2012-12-22 19:06:22 +04:00
|
|
|
if (FIXNUM_P(y)) {
|
|
|
|
long val = FIX2LONG(x) ^ FIX2LONG(y);
|
|
|
|
return LONG2NUM(val);
|
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2021-09-03 14:50:12 +03:00
|
|
|
if (RB_BIGNUM_TYPE_P(y)) {
|
1999-01-20 07:59:39 +03:00
|
|
|
return rb_big_xor(y, x);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2012-12-22 19:06:22 +04:00
|
|
|
|
2016-11-01 16:10:14 +03:00
|
|
|
return rb_num_coerce_bit(x, y, '^');
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2021-11-17 21:51:32 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* self ^ other -> integer
|
|
|
|
*
|
|
|
|
* Bitwise EXCLUSIVE OR; each bit in the result is 1 if the corresponding bits
|
|
|
|
* in +self+ and +other+ are different, 0 otherwise:
|
|
|
|
*
|
|
|
|
* "%04b" % (0b0101 ^ 0b0110) # => "0011"
|
|
|
|
*
|
|
|
|
* Raises an exception if +other+ is not an \Integer.
|
|
|
|
*
|
|
|
|
* Related: Integer#& (bitwise AND), Integer#| (bitwise OR).
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2016-04-27 18:35:23 +03:00
|
|
|
static VALUE
|
|
|
|
int_xor(VALUE x, VALUE y)
|
|
|
|
{
|
|
|
|
if (FIXNUM_P(x)) {
|
|
|
|
return fix_xor(x, y);
|
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(x)) {
|
2016-04-27 18:35:23 +03:00
|
|
|
return rb_big_xor(x, y);
|
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
2007-07-19 09:38:48 +04:00
|
|
|
rb_fix_lshift(VALUE x, VALUE y)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2000-07-03 09:46:36 +04:00
|
|
|
long val, width;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
val = NUM2LONG(x);
|
2022-01-26 18:53:12 +03:00
|
|
|
if (!val) return (rb_to_int(y), INT2FIX(0));
|
2007-07-19 09:38:48 +04:00
|
|
|
if (!FIXNUM_P(y))
|
|
|
|
return rb_big_lshift(rb_int2big(val), y);
|
|
|
|
width = FIX2LONG(y);
|
2002-06-10 14:06:12 +04:00
|
|
|
if (width < 0)
|
2007-07-19 09:38:48 +04:00
|
|
|
return fix_rshift(val, (unsigned long)-width);
|
|
|
|
return fix_lshift(val, width);
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
fix_lshift(long val, unsigned long width)
|
|
|
|
{
|
2007-12-24 21:12:24 +03:00
|
|
|
if (width > (SIZEOF_LONG*CHAR_BIT-1)
|
|
|
|
|| ((unsigned long)val)>>(SIZEOF_LONG*CHAR_BIT-1-width) > 0) {
|
2007-07-19 09:38:48 +04:00
|
|
|
return rb_big_lshift(rb_int2big(val), ULONG2NUM(width));
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
val = val << width;
|
2002-08-28 12:05:23 +04:00
|
|
|
return LONG2NUM(val);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2021-11-18 17:28:04 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* self << count -> integer
|
|
|
|
*
|
|
|
|
* Returns +self+ with bits shifted +count+ positions to the left,
|
|
|
|
* or to the right if +count+ is negative:
|
|
|
|
*
|
|
|
|
* n = 0b11110000
|
|
|
|
* "%08b" % (n << 1) # => "111100000"
|
|
|
|
* "%08b" % (n << 3) # => "11110000000"
|
|
|
|
* "%08b" % (n << -1) # => "01111000"
|
|
|
|
* "%08b" % (n << -3) # => "00011110"
|
|
|
|
*
|
|
|
|
* Related: Integer#>>.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2016-11-12 14:52:00 +03:00
|
|
|
VALUE
|
2016-04-26 15:23:05 +03:00
|
|
|
rb_int_lshift(VALUE x, VALUE y)
|
|
|
|
{
|
|
|
|
if (FIXNUM_P(x)) {
|
|
|
|
return rb_fix_lshift(x, y);
|
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(x)) {
|
2016-04-26 15:23:05 +03:00
|
|
|
return rb_big_lshift(x, y);
|
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
2007-07-19 09:38:48 +04:00
|
|
|
rb_fix_rshift(VALUE x, VALUE y)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
|
|
|
long i, val;
|
|
|
|
|
2002-06-10 14:06:12 +04:00
|
|
|
val = FIX2LONG(x);
|
2022-01-26 18:53:12 +03:00
|
|
|
if (!val) return (rb_to_int(y), INT2FIX(0));
|
2007-07-19 09:38:48 +04:00
|
|
|
if (!FIXNUM_P(y))
|
|
|
|
return rb_big_rshift(rb_int2big(val), y);
|
|
|
|
i = FIX2LONG(y);
|
|
|
|
if (i == 0) return x;
|
|
|
|
if (i < 0)
|
|
|
|
return fix_lshift(val, (unsigned long)-i);
|
|
|
|
return fix_rshift(val, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
fix_rshift(long val, unsigned long i)
|
|
|
|
{
|
2000-07-03 09:46:36 +04:00
|
|
|
if (i >= sizeof(long)*CHAR_BIT-1) {
|
2002-06-10 14:06:12 +04:00
|
|
|
if (val < 0) return INT2FIX(-1);
|
2000-07-03 09:46:36 +04:00
|
|
|
return INT2FIX(0);
|
|
|
|
}
|
2002-06-10 14:06:12 +04:00
|
|
|
val = RSHIFT(val, i);
|
2002-08-21 19:47:54 +04:00
|
|
|
return LONG2FIX(val);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2021-11-18 17:28:04 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* self >> count -> integer
|
|
|
|
*
|
|
|
|
* Returns +self+ with bits shifted +count+ positions to the right,
|
|
|
|
* or to the left if +count+ is negative:
|
|
|
|
*
|
|
|
|
* n = 0b11110000
|
|
|
|
* "%08b" % (n >> 1) # => "01111000"
|
|
|
|
* "%08b" % (n >> 3) # => "00011110"
|
|
|
|
* "%08b" % (n >> -1) # => "111100000"
|
|
|
|
* "%08b" % (n >> -3) # => "11110000000"
|
|
|
|
*
|
|
|
|
* Related: Integer#<<.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2016-04-26 15:09:40 +03:00
|
|
|
static VALUE
|
|
|
|
rb_int_rshift(VALUE x, VALUE y)
|
|
|
|
{
|
|
|
|
if (FIXNUM_P(x)) {
|
|
|
|
return rb_fix_rshift(x, y);
|
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(x)) {
|
2016-04-26 15:09:40 +03:00
|
|
|
return rb_big_rshift(x, y);
|
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
2019-06-01 07:15:43 +03:00
|
|
|
MJIT_FUNC_EXPORTED VALUE
|
|
|
|
rb_fix_aref(VALUE fix, VALUE idx)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2001-05-02 08:22:21 +04:00
|
|
|
long val = FIX2LONG(fix);
|
2002-08-13 13:21:18 +04:00
|
|
|
long i;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2008-05-07 17:24:55 +04:00
|
|
|
idx = rb_to_int(idx);
|
|
|
|
if (!FIXNUM_P(idx)) {
|
2002-08-13 13:21:18 +04:00
|
|
|
idx = rb_big_norm(idx);
|
|
|
|
if (!FIXNUM_P(idx)) {
|
2014-02-16 01:17:34 +04:00
|
|
|
if (!BIGNUM_SIGN(idx) || val >= 0)
|
2002-08-13 13:21:18 +04:00
|
|
|
return INT2FIX(0);
|
|
|
|
return INT2FIX(1);
|
|
|
|
}
|
2001-10-29 08:07:26 +03:00
|
|
|
}
|
2008-03-11 13:48:12 +03:00
|
|
|
i = FIX2LONG(idx);
|
2001-10-29 08:07:26 +03:00
|
|
|
|
2002-08-13 13:21:18 +04:00
|
|
|
if (i < 0) return INT2FIX(0);
|
2013-10-09 19:08:41 +04:00
|
|
|
if (SIZEOF_LONG*CHAR_BIT-1 <= i) {
|
2002-08-13 13:21:18 +04:00
|
|
|
if (val < 0) return INT2FIX(1);
|
1998-01-16 15:13:05 +03:00
|
|
|
return INT2FIX(0);
|
2001-05-02 08:22:21 +04:00
|
|
|
}
|
2002-08-13 13:21:18 +04:00
|
|
|
if (val & (1L<<i))
|
|
|
|
return INT2FIX(1);
|
|
|
|
return INT2FIX(0);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2019-04-28 17:24:09 +03:00
|
|
|
|
|
|
|
/* copied from "r_less" in range.c */
|
|
|
|
/* compares _a_ and _b_ and returns:
|
|
|
|
* < 0: a < b
|
|
|
|
* = 0: a = b
|
|
|
|
* > 0: a > b or non-comparable
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
compare_indexes(VALUE a, VALUE b)
|
2016-04-27 14:56:03 +03:00
|
|
|
{
|
2019-04-28 17:24:09 +03:00
|
|
|
VALUE r = rb_funcall(a, id_cmp, 1, b);
|
|
|
|
|
|
|
|
if (NIL_P(r))
|
2019-04-28 17:42:46 +03:00
|
|
|
return INT_MAX;
|
2019-04-28 17:24:09 +03:00
|
|
|
return rb_cmpint(r, a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2019-07-19 00:15:47 +03:00
|
|
|
generate_mask(VALUE len)
|
|
|
|
{
|
2019-04-28 17:24:09 +03:00
|
|
|
return rb_int_minus(rb_int_lshift(INT2FIX(1), len), INT2FIX(1));
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
int_aref1(VALUE num, VALUE arg)
|
|
|
|
{
|
|
|
|
VALUE orig_num = num, beg, end;
|
|
|
|
int excl;
|
|
|
|
|
|
|
|
if (rb_range_values(arg, &beg, &end, &excl)) {
|
|
|
|
if (NIL_P(beg)) {
|
|
|
|
/* beginless range */
|
|
|
|
if (!RTEST(num_negative_p(end))) {
|
|
|
|
if (!excl) end = rb_int_plus(end, INT2FIX(1));
|
|
|
|
VALUE mask = generate_mask(end);
|
2022-01-01 10:06:07 +03:00
|
|
|
if (int_zero_p(rb_int_and(num, mask))) {
|
2019-04-28 17:24:09 +03:00
|
|
|
return INT2FIX(0);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
rb_raise(rb_eArgError, "The beginless range for Integer#[] results in infinity");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return INT2FIX(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
num = rb_int_rshift(num, beg);
|
|
|
|
|
|
|
|
int cmp = compare_indexes(beg, end);
|
|
|
|
if (!NIL_P(end) && cmp < 0) {
|
|
|
|
VALUE len = rb_int_minus(end, beg);
|
|
|
|
if (!excl) len = rb_int_plus(len, INT2FIX(1));
|
|
|
|
VALUE mask = generate_mask(len);
|
|
|
|
num = rb_int_and(num, mask);
|
|
|
|
}
|
|
|
|
else if (cmp == 0) {
|
|
|
|
if (excl) return INT2FIX(0);
|
|
|
|
num = orig_num;
|
|
|
|
arg = beg;
|
|
|
|
goto one_bit;
|
|
|
|
}
|
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
|
|
|
one_bit:
|
2016-04-27 14:56:03 +03:00
|
|
|
if (FIXNUM_P(num)) {
|
2019-06-01 07:15:43 +03:00
|
|
|
return rb_fix_aref(num, arg);
|
2016-04-27 14:56:03 +03:00
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(num)) {
|
2019-04-28 17:42:46 +03:00
|
|
|
return rb_big_aref(num, arg);
|
2016-04-27 14:56:03 +03:00
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
2019-04-28 17:24:09 +03:00
|
|
|
static VALUE
|
|
|
|
int_aref2(VALUE num, VALUE beg, VALUE len)
|
|
|
|
{
|
|
|
|
num = rb_int_rshift(num, beg);
|
|
|
|
VALUE mask = generate_mask(len);
|
|
|
|
num = rb_int_and(num, mask);
|
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-16 22:42:05 +03:00
|
|
|
* self[offset] -> 0 or 1
|
|
|
|
* self[offset, size] -> integer
|
|
|
|
* self[range] -> integer
|
2019-04-28 17:24:09 +03:00
|
|
|
*
|
2021-11-16 22:42:05 +03:00
|
|
|
* Returns a slice of bits from +self+.
|
2019-04-28 17:24:09 +03:00
|
|
|
*
|
2021-11-16 22:42:05 +03:00
|
|
|
* With argument +offset+, returns the bit at the given offset,
|
|
|
|
* where offset 0 refers to the least significant bit:
|
2019-04-28 17:24:09 +03:00
|
|
|
*
|
2021-11-16 22:42:05 +03:00
|
|
|
* n = 0b10 # => 2
|
|
|
|
* n[0] # => 0
|
|
|
|
* n[1] # => 1
|
|
|
|
* n[2] # => 0
|
|
|
|
* n[3] # => 0
|
2019-04-28 17:24:09 +03:00
|
|
|
*
|
|
|
|
* In principle, <code>n[i]</code> is equivalent to <code>(n >> i) & 1</code>.
|
2021-11-16 22:42:05 +03:00
|
|
|
* Thus, negative index always returns zero:
|
|
|
|
*
|
|
|
|
* 255[-1] # => 0
|
2019-04-28 17:24:09 +03:00
|
|
|
*
|
2021-11-16 22:42:05 +03:00
|
|
|
* With arguments +offset+ and +size+, returns +size+ bits from +self+,
|
|
|
|
* beginning at +offset+ and including bits of greater significance:
|
2019-04-28 17:24:09 +03:00
|
|
|
*
|
2021-11-16 22:42:05 +03:00
|
|
|
* n = 0b111000 # => 56
|
|
|
|
* "%010b" % n[0, 10] # => "0000111000"
|
|
|
|
* "%010b" % n[4, 10] # => "0000000011"
|
2019-04-28 17:24:09 +03:00
|
|
|
*
|
2021-11-16 22:42:05 +03:00
|
|
|
* With argument +range+, returns <tt>range.size</tt> bits from +self+,
|
|
|
|
* beginning at <tt>range.begin</tt> and including bits of greater significance:
|
2019-04-28 17:24:09 +03:00
|
|
|
*
|
2021-11-16 22:42:05 +03:00
|
|
|
* n = 0b111000 # => 56
|
|
|
|
* "%010b" % n[0..9] # => "0000111000"
|
|
|
|
* "%010b" % n[4..9] # => "0000000011"
|
|
|
|
*
|
|
|
|
* Raises an exception if the slice cannot be constructed.
|
2019-04-28 17:24:09 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
int_aref(int const argc, VALUE * const argv, VALUE const num)
|
|
|
|
{
|
|
|
|
rb_check_arity(argc, 1, 2);
|
|
|
|
if (argc == 2) {
|
2019-04-28 17:42:46 +03:00
|
|
|
return int_aref2(num, argv[0], argv[1]);
|
2019-04-28 17:24:09 +03:00
|
|
|
}
|
|
|
|
return int_aref1(num, argv[0]);
|
|
|
|
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
2003-12-23 19:21:17 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-18 17:28:04 +03:00
|
|
|
* to_f -> float
|
|
|
|
*
|
|
|
|
* Converts +self+ to a Float:
|
|
|
|
*
|
|
|
|
* 1.to_f # => 1.0
|
|
|
|
* -1.to_f # => -1.0
|
|
|
|
*
|
|
|
|
* If the value of +self+ does not fit in a \Float,
|
|
|
|
* the result is infinity:
|
|
|
|
*
|
|
|
|
* (10**400).to_f # => Infinity
|
|
|
|
* (-10**400).to_f # => -Infinity
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2003-12-23 19:21:17 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
2016-03-18 17:52:46 +03:00
|
|
|
int_to_f(VALUE num)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
|
|
|
double val;
|
|
|
|
|
2016-03-18 17:52:46 +03:00
|
|
|
if (FIXNUM_P(num)) {
|
|
|
|
val = (double)FIX2LONG(num);
|
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(num)) {
|
2016-03-18 18:02:45 +03:00
|
|
|
val = rb_big2dbl(num);
|
|
|
|
}
|
2016-03-18 17:52:46 +03:00
|
|
|
else {
|
2016-03-19 12:43:35 +03:00
|
|
|
rb_raise(rb_eNotImpError, "Unknown subclass for to_f: %s", rb_obj_classname(num));
|
2016-03-18 17:52:46 +03:00
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2008-09-05 22:24:21 +04:00
|
|
|
return DBL2NUM(val);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2016-04-27 15:46:46 +03:00
|
|
|
static VALUE
|
|
|
|
fix_abs(VALUE fix)
|
|
|
|
{
|
|
|
|
long i = FIX2LONG(fix);
|
|
|
|
|
|
|
|
if (i < 0) i = -i;
|
|
|
|
|
|
|
|
return LONG2NUM(i);
|
|
|
|
}
|
|
|
|
|
2016-11-12 18:43:26 +03:00
|
|
|
VALUE
|
|
|
|
rb_int_abs(VALUE num)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2016-04-26 13:59:27 +03:00
|
|
|
if (FIXNUM_P(num)) {
|
|
|
|
return fix_abs(num);
|
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(num)) {
|
2016-04-26 13:59:27 +03:00
|
|
|
return rb_big_abs(num);
|
|
|
|
}
|
|
|
|
return Qnil;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2016-04-27 15:46:46 +03:00
|
|
|
static VALUE
|
|
|
|
fix_size(VALUE fix)
|
|
|
|
{
|
|
|
|
return INT2FIX(sizeof(long));
|
|
|
|
}
|
|
|
|
|
2021-06-05 07:57:21 +03:00
|
|
|
MJIT_FUNC_EXPORTED VALUE
|
|
|
|
rb_int_size(VALUE num)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2016-04-26 14:47:14 +03:00
|
|
|
if (FIXNUM_P(num)) {
|
|
|
|
return fix_size(num);
|
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(num)) {
|
2016-04-26 14:47:14 +03:00
|
|
|
return rb_big_size_m(num);
|
|
|
|
}
|
|
|
|
return Qnil;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2016-04-27 15:46:46 +03:00
|
|
|
static VALUE
|
|
|
|
rb_fix_bit_length(VALUE fix)
|
|
|
|
{
|
|
|
|
long v = FIX2LONG(fix);
|
|
|
|
if (v < 0)
|
|
|
|
v = ~v;
|
|
|
|
return LONG2FIX(bit_length(v));
|
|
|
|
}
|
|
|
|
|
2020-07-11 08:25:51 +03:00
|
|
|
VALUE
|
2016-04-26 14:17:37 +03:00
|
|
|
rb_int_bit_length(VALUE num)
|
2013-09-01 05:31:16 +04:00
|
|
|
{
|
2016-04-26 14:17:37 +03:00
|
|
|
if (FIXNUM_P(num)) {
|
|
|
|
return rb_fix_bit_length(num);
|
|
|
|
}
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(num)) {
|
2016-04-26 14:17:37 +03:00
|
|
|
return rb_big_bit_length(num);
|
|
|
|
}
|
|
|
|
return Qnil;
|
2013-09-01 05:31:16 +04:00
|
|
|
}
|
|
|
|
|
2016-06-13 14:43:54 +03:00
|
|
|
static VALUE
|
|
|
|
rb_fix_digits(VALUE fix, long base)
|
|
|
|
{
|
|
|
|
VALUE digits;
|
|
|
|
long x = FIX2LONG(fix);
|
|
|
|
|
|
|
|
assert(x >= 0);
|
|
|
|
|
|
|
|
if (base < 2)
|
|
|
|
rb_raise(rb_eArgError, "invalid radix %ld", base);
|
|
|
|
|
|
|
|
if (x == 0)
|
|
|
|
return rb_ary_new_from_args(1, INT2FIX(0));
|
|
|
|
|
|
|
|
digits = rb_ary_new();
|
|
|
|
while (x > 0) {
|
|
|
|
long q = x % base;
|
|
|
|
rb_ary_push(digits, LONG2NUM(q));
|
|
|
|
x /= base;
|
|
|
|
}
|
|
|
|
|
|
|
|
return digits;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
rb_int_digits_bigbase(VALUE num, VALUE base)
|
|
|
|
{
|
2021-06-17 21:27:53 +03:00
|
|
|
VALUE digits, bases;
|
2016-06-13 14:43:54 +03:00
|
|
|
|
|
|
|
assert(!rb_num_negative_p(num));
|
|
|
|
|
2021-09-03 14:50:12 +03:00
|
|
|
if (RB_BIGNUM_TYPE_P(base))
|
2016-06-13 14:43:54 +03:00
|
|
|
base = rb_big_norm(base);
|
|
|
|
|
|
|
|
if (FIXNUM_P(base) && FIX2LONG(base) < 2)
|
|
|
|
rb_raise(rb_eArgError, "invalid radix %ld", FIX2LONG(base));
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(base) && BIGNUM_NEGATIVE_P(base))
|
2016-06-13 14:43:54 +03:00
|
|
|
rb_raise(rb_eArgError, "negative radix");
|
|
|
|
|
|
|
|
if (FIXNUM_P(base) && FIXNUM_P(num))
|
|
|
|
return rb_fix_digits(num, FIX2LONG(base));
|
|
|
|
|
|
|
|
if (FIXNUM_P(num))
|
|
|
|
return rb_ary_new_from_args(1, num);
|
|
|
|
|
2021-06-17 21:27:53 +03:00
|
|
|
if (int_lt(rb_int_div(rb_int_bit_length(num), rb_int_bit_length(base)), INT2FIX(50))) {
|
|
|
|
digits = rb_ary_new();
|
|
|
|
while (!FIXNUM_P(num) || FIX2LONG(num) > 0) {
|
|
|
|
VALUE qr = rb_int_divmod(num, base);
|
|
|
|
rb_ary_push(digits, RARRAY_AREF(qr, 1));
|
|
|
|
num = RARRAY_AREF(qr, 0);
|
|
|
|
}
|
|
|
|
return digits;
|
|
|
|
}
|
|
|
|
|
|
|
|
bases = rb_ary_new();
|
|
|
|
for (VALUE b = base; int_lt(b, num) == Qtrue; b = rb_int_mul(b, b)) {
|
|
|
|
rb_ary_push(bases, b);
|
|
|
|
}
|
|
|
|
digits = rb_ary_new_from_args(1, num);
|
|
|
|
while (RARRAY_LEN(bases)) {
|
|
|
|
VALUE b = rb_ary_pop(bases);
|
|
|
|
long i, last_idx = RARRAY_LEN(digits) - 1;
|
|
|
|
for(i = last_idx; i >= 0; i--) {
|
|
|
|
VALUE n = RARRAY_AREF(digits, i);
|
|
|
|
VALUE divmod = rb_int_divmod(n, b);
|
|
|
|
VALUE div = RARRAY_AREF(divmod, 0);
|
|
|
|
VALUE mod = RARRAY_AREF(divmod, 1);
|
|
|
|
if (i != last_idx || div != INT2FIX(0)) rb_ary_store(digits, 2 * i + 1, div);
|
|
|
|
rb_ary_store(digits, 2 * i, mod);
|
|
|
|
}
|
2016-06-13 14:43:54 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return digits;
|
|
|
|
}
|
|
|
|
|
2021-11-16 22:42:05 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* digits(base = 10) -> array_of_integers
|
|
|
|
*
|
|
|
|
* Returns an array of integers representing the +base+-radix
|
|
|
|
* digits of +self+;
|
|
|
|
* the first element of the array represents the least significant digit:
|
|
|
|
*
|
|
|
|
* 12345.digits # => [5, 4, 3, 2, 1]
|
|
|
|
* 12345.digits(7) # => [4, 6, 6, 0, 5]
|
|
|
|
* 12345.digits(100) # => [45, 23, 1]
|
|
|
|
*
|
|
|
|
* Raises an exception if +self+ is negative or +base+ is less than 2.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2016-06-13 14:43:54 +03:00
|
|
|
static VALUE
|
|
|
|
rb_int_digits(int argc, VALUE *argv, VALUE num)
|
|
|
|
{
|
|
|
|
VALUE base_value;
|
|
|
|
long base;
|
|
|
|
|
|
|
|
if (rb_num_negative_p(num))
|
|
|
|
rb_raise(rb_eMathDomainError, "out of domain");
|
|
|
|
|
|
|
|
if (rb_check_arity(argc, 0, 1)) {
|
|
|
|
base_value = rb_to_int(argv[0]);
|
|
|
|
if (!RB_INTEGER_TYPE_P(base_value))
|
|
|
|
rb_raise(rb_eTypeError, "wrong argument type %s (expected Integer)",
|
|
|
|
rb_obj_classname(argv[0]));
|
2021-09-03 14:50:12 +03:00
|
|
|
if (RB_BIGNUM_TYPE_P(base_value))
|
2016-06-13 14:43:54 +03:00
|
|
|
return rb_int_digits_bigbase(num, base_value);
|
|
|
|
|
|
|
|
base = FIX2LONG(base_value);
|
2016-11-04 07:05:07 +03:00
|
|
|
if (base < 0)
|
|
|
|
rb_raise(rb_eArgError, "negative radix");
|
|
|
|
else if (base < 2)
|
2016-06-13 14:43:54 +03:00
|
|
|
rb_raise(rb_eArgError, "invalid radix %ld", base);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
base = 10;
|
|
|
|
|
|
|
|
if (FIXNUM_P(num))
|
|
|
|
return rb_fix_digits(num, base);
|
2021-09-03 14:50:12 +03:00
|
|
|
else if (RB_BIGNUM_TYPE_P(num))
|
2016-06-13 14:43:54 +03:00
|
|
|
return rb_int_digits_bigbase(num, LONG2FIX(base));
|
|
|
|
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
2021-11-16 22:42:05 +03:00
|
|
|
static VALUE
|
|
|
|
int_upto_size(VALUE from, VALUE args, VALUE eobj)
|
|
|
|
{
|
|
|
|
return ruby_num_interval_step_size(from, RARRAY_AREF(args, 0), INT2FIX(1), FALSE);
|
|
|
|
}
|
|
|
|
|
2003-12-27 08:46:46 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-16 22:42:05 +03:00
|
|
|
* upto(limit) {|i| ... } -> self
|
|
|
|
* upto(limit) -> enumerator
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-11-16 22:42:05 +03:00
|
|
|
* Calls the given block with each integer value from +self+ up to +limit+;
|
|
|
|
* returns +self+:
|
2010-05-13 09:49:55 +04:00
|
|
|
*
|
2021-11-16 22:42:05 +03:00
|
|
|
* a = []
|
|
|
|
* 5.upto(10) {|i| a << i } # => 5
|
|
|
|
* a # => [5, 6, 7, 8, 9, 10]
|
|
|
|
* a = []
|
|
|
|
* -5.upto(0) {|i| a << i } # => -5
|
|
|
|
* a # => [-5, -4, -3, -2, -1, 0]
|
|
|
|
* 5.upto(4) {|i| fail 'Cannot happen' } # => 5
|
|
|
|
*
|
|
|
|
* With no block given, returns an Enumerator.
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2003-12-27 08:46:46 +03:00
|
|
|
*/
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
int_upto(VALUE from, VALUE to)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2012-11-06 21:15:15 +04:00
|
|
|
RETURN_SIZED_ENUMERATOR(from, 1, &to, int_upto_size);
|
2002-04-24 08:54:16 +04:00
|
|
|
if (FIXNUM_P(from) && FIXNUM_P(to)) {
|
|
|
|
long i, end;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2002-04-24 08:54:16 +04:00
|
|
|
end = FIX2LONG(to);
|
|
|
|
for (i = FIX2LONG(from); i <= end; i++) {
|
2002-08-21 19:47:54 +04:00
|
|
|
rb_yield(LONG2FIX(i));
|
2002-04-24 08:54:16 +04:00
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2002-04-24 08:54:16 +04:00
|
|
|
else {
|
2003-05-08 07:56:12 +04:00
|
|
|
VALUE i = from, c;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2003-05-08 07:56:12 +04:00
|
|
|
while (!(c = rb_funcall(i, '>', 1, to))) {
|
2002-04-24 08:54:16 +04:00
|
|
|
rb_yield(i);
|
|
|
|
i = rb_funcall(i, '+', 1, INT2FIX(1));
|
|
|
|
}
|
2020-10-02 15:30:07 +03:00
|
|
|
ensure_cmp(c, i, to);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
return from;
|
|
|
|
}
|
|
|
|
|
2021-11-16 22:42:05 +03:00
|
|
|
static VALUE
|
|
|
|
int_downto_size(VALUE from, VALUE args, VALUE eobj)
|
|
|
|
{
|
|
|
|
return ruby_num_interval_step_size(from, RARRAY_AREF(args, 0), INT2FIX(-1), FALSE);
|
|
|
|
}
|
|
|
|
|
2003-12-27 08:46:46 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-16 22:42:05 +03:00
|
|
|
* downto(limit) {|i| ... } -> self
|
|
|
|
* downto(limit) -> enumerator
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-11-16 22:42:05 +03:00
|
|
|
* Calls the given block with each integer value from +self+ down to +limit+;
|
|
|
|
* returns +self+:
|
2007-05-09 08:11:41 +04:00
|
|
|
*
|
2021-11-16 22:42:05 +03:00
|
|
|
* a = []
|
|
|
|
* 10.downto(5) {|i| a << i } # => 10
|
|
|
|
* a # => [10, 9, 8, 7, 6, 5]
|
|
|
|
* a = []
|
|
|
|
* 0.downto(-5) {|i| a << i } # => 0
|
|
|
|
* a # => [0, -1, -2, -3, -4, -5]
|
|
|
|
* 4.downto(5) {|i| fail 'Cannot happen' } # => 4
|
|
|
|
*
|
|
|
|
* With no block given, returns an Enumerator.
|
2010-05-13 09:49:55 +04:00
|
|
|
*
|
2003-12-27 08:46:46 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
int_downto(VALUE from, VALUE to)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2012-11-06 21:15:15 +04:00
|
|
|
RETURN_SIZED_ENUMERATOR(from, 1, &to, int_downto_size);
|
2002-04-24 08:54:16 +04:00
|
|
|
if (FIXNUM_P(from) && FIXNUM_P(to)) {
|
|
|
|
long i, end;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2002-04-24 08:54:16 +04:00
|
|
|
end = FIX2LONG(to);
|
|
|
|
for (i=FIX2LONG(from); i >= end; i--) {
|
2002-08-21 19:47:54 +04:00
|
|
|
rb_yield(LONG2FIX(i));
|
2002-04-24 08:54:16 +04:00
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
else {
|
2003-05-08 07:56:12 +04:00
|
|
|
VALUE i = from, c;
|
2002-04-24 08:54:16 +04:00
|
|
|
|
2003-05-08 07:56:12 +04:00
|
|
|
while (!(c = rb_funcall(i, '<', 1, to))) {
|
2002-04-24 08:54:16 +04:00
|
|
|
rb_yield(i);
|
|
|
|
i = rb_funcall(i, '-', 1, INT2FIX(1));
|
|
|
|
}
|
2003-05-08 07:56:12 +04:00
|
|
|
if (NIL_P(c)) rb_cmperr(i, to);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
return from;
|
|
|
|
}
|
|
|
|
|
2016-04-27 15:46:46 +03:00
|
|
|
static VALUE
|
|
|
|
int_dotimes_size(VALUE num, VALUE args, VALUE eobj)
|
|
|
|
{
|
|
|
|
if (FIXNUM_P(num)) {
|
|
|
|
if (NUM2LONG(num) <= 0) return INT2FIX(0);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (RTEST(rb_funcall(num, '<', 1, INT2FIX(0)))) return INT2FIX(0);
|
|
|
|
}
|
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
2021-11-18 01:00:50 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* times {|i| ... } -> self
|
|
|
|
* times -> enumerator
|
|
|
|
*
|
|
|
|
* Calls the given block +self+ times with each integer in <tt>(0..self-1)</tt>:
|
|
|
|
*
|
|
|
|
* a = []
|
|
|
|
* 5.times {|i| a.push(i) } # => 5
|
|
|
|
* a # => [0, 1, 2, 3, 4]
|
|
|
|
*
|
|
|
|
* With no block given, returns an Enumerator.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
int_dotimes(VALUE num)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2012-11-06 21:15:30 +04:00
|
|
|
RETURN_SIZED_ENUMERATOR(num, 0, 0, int_dotimes_size);
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2007-06-29 10:43:24 +04:00
|
|
|
if (FIXNUM_P(num)) {
|
|
|
|
long i, end;
|
2006-12-31 18:02:22 +03:00
|
|
|
|
2007-06-29 10:43:24 +04:00
|
|
|
end = FIX2LONG(num);
|
|
|
|
for (i=0; i<end; i++) {
|
2015-10-11 00:22:54 +03:00
|
|
|
rb_yield_1(LONG2FIX(i));
|
2007-06-29 10:43:24 +04:00
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2007-06-29 10:43:24 +04:00
|
|
|
else {
|
|
|
|
VALUE i = INT2FIX(0);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2007-06-29 10:43:24 +04:00
|
|
|
for (;;) {
|
2021-12-02 00:00:11 +03:00
|
|
|
if (!RTEST(int_le(i, num))) break;
|
2007-06-29 10:43:24 +04:00
|
|
|
rb_yield(i);
|
2021-12-02 00:00:11 +03:00
|
|
|
i = rb_int_plus(i, INT2FIX(1));
|
2007-06-29 10:43:24 +04:00
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2007-06-29 10:43:24 +04:00
|
|
|
return num;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2009-09-05 10:41:40 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-18 01:00:50 +03:00
|
|
|
* round(ndigits= 0, half: :up) -> integer
|
2017-04-03 22:19:20 +03:00
|
|
|
*
|
2021-11-18 01:00:50 +03:00
|
|
|
* Returns +self+ rounded to the nearest value with
|
|
|
|
* a precision of +ndigits+ decimal digits.
|
2017-04-03 22:19:20 +03:00
|
|
|
*
|
2021-11-18 01:00:50 +03:00
|
|
|
* When +ndigits+ is negative, the returned value
|
|
|
|
* has at least <tt>ndigits.abs</tt> trailing zeros:
|
|
|
|
*
|
|
|
|
* 555.round(-1) # => 560
|
|
|
|
* 555.round(-2) # => 600
|
|
|
|
* 555.round(-3) # => 1000
|
|
|
|
* -555.round(-2) # => -600
|
|
|
|
* 555.round(-4) # => 0
|
2017-04-03 22:19:20 +03:00
|
|
|
*
|
2017-05-06 22:58:12 +03:00
|
|
|
* Returns +self+ when +ndigits+ is zero or positive.
|
2017-04-03 22:19:20 +03:00
|
|
|
*
|
2021-11-18 01:00:50 +03:00
|
|
|
* 555.round # => 555
|
|
|
|
* 555.round(1) # => 555
|
|
|
|
* 555.round(50) # => 555
|
|
|
|
*
|
|
|
|
* If keyword argument +half+ is given,
|
|
|
|
* and +self+ is equidistant from the two candidate values,
|
|
|
|
* the rounding is according to the given +half+ value:
|
|
|
|
*
|
|
|
|
* - +:up+ or +nil+: round away from zero:
|
|
|
|
*
|
|
|
|
* 25.round(-1, half: :up) # => 30
|
|
|
|
* (-25).round(-1, half: :up) # => -30
|
|
|
|
*
|
|
|
|
* - +:down+: round toward zero:
|
|
|
|
*
|
|
|
|
* 25.round(-1, half: :down) # => 20
|
|
|
|
* (-25).round(-1, half: :down) # => -20
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* - +:even+: round toward the candidate whose last nonzero digit is even:
|
|
|
|
*
|
|
|
|
* 25.round(-1, half: :even) # => 20
|
|
|
|
* 15.round(-1, half: :even) # => 20
|
|
|
|
* (-25).round(-1, half: :even) # => -20
|
|
|
|
*
|
|
|
|
* Raises and exception if the value for +half+ is invalid.
|
|
|
|
*
|
|
|
|
* Related: Integer#truncate.
|
|
|
|
*
|
2009-09-05 10:41:40 +04:00
|
|
|
*/
|
|
|
|
|
2007-06-05 09:31:05 +04:00
|
|
|
static VALUE
|
|
|
|
int_round(int argc, VALUE* argv, VALUE num)
|
|
|
|
{
|
|
|
|
int ndigits;
|
2016-11-05 12:49:39 +03:00
|
|
|
int mode;
|
|
|
|
VALUE nd, opt;
|
2007-06-05 09:31:05 +04:00
|
|
|
|
2016-11-05 12:49:39 +03:00
|
|
|
if (!rb_scan_args(argc, argv, "01:", &nd, &opt)) return num;
|
|
|
|
ndigits = NUM2INT(nd);
|
|
|
|
mode = rb_num_get_rounding_option(opt);
|
2017-05-06 22:58:12 +03:00
|
|
|
if (ndigits >= 0) {
|
2007-06-29 10:44:01 +04:00
|
|
|
return num;
|
|
|
|
}
|
2016-11-05 12:49:39 +03:00
|
|
|
return rb_int_round(num, ndigits, mode);
|
2007-06-05 09:31:05 +04:00
|
|
|
}
|
|
|
|
|
2016-04-13 09:47:55 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-18 01:00:50 +03:00
|
|
|
* floor(ndigits = 0) -> integer
|
2016-04-13 09:47:55 +03:00
|
|
|
*
|
2021-11-18 01:00:50 +03:00
|
|
|
* Returns the largest number less than or equal to +self+ with
|
|
|
|
* a precision of +ndigits+ decimal digits.
|
2017-04-03 22:23:13 +03:00
|
|
|
*
|
2021-11-18 01:00:50 +03:00
|
|
|
* When +ndigits+ is negative, the returned value
|
|
|
|
* has at least <tt>ndigits.abs</tt> trailing zeros:
|
|
|
|
*
|
|
|
|
* 555.floor(-1) # => 550
|
|
|
|
* 555.floor(-2) # => 500
|
|
|
|
* -555.floor(-2) # => -600
|
|
|
|
* 555.floor(-3) # => 0
|
2016-04-13 09:47:55 +03:00
|
|
|
*
|
2017-05-06 22:58:12 +03:00
|
|
|
* Returns +self+ when +ndigits+ is zero or positive.
|
2016-04-13 09:47:55 +03:00
|
|
|
*
|
2021-11-18 01:00:50 +03:00
|
|
|
* 555.floor # => 555
|
|
|
|
* 555.floor(50) # => 555
|
|
|
|
*
|
|
|
|
* Related: Integer#ceil.
|
|
|
|
*
|
2016-04-13 09:47:55 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
int_floor(int argc, VALUE* argv, VALUE num)
|
|
|
|
{
|
|
|
|
int ndigits;
|
|
|
|
|
|
|
|
if (!rb_check_arity(argc, 0, 1)) return num;
|
|
|
|
ndigits = NUM2INT(argv[0]);
|
2017-05-06 22:58:12 +03:00
|
|
|
if (ndigits >= 0) {
|
2016-04-13 09:47:55 +03:00
|
|
|
return num;
|
|
|
|
}
|
|
|
|
return rb_int_floor(num, ndigits);
|
|
|
|
}
|
|
|
|
|
2016-04-13 09:50:24 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-18 01:00:50 +03:00
|
|
|
* ceil(ndigits = 0) -> integer
|
2016-04-13 09:50:24 +03:00
|
|
|
*
|
2021-11-18 01:00:50 +03:00
|
|
|
* Returns the smallest number greater than or equal to +self+ with
|
|
|
|
* a precision of +ndigits+ decimal digits.
|
2017-04-03 22:23:13 +03:00
|
|
|
*
|
|
|
|
* When the precision is negative, the returned value is an integer
|
2021-11-18 01:00:50 +03:00
|
|
|
* with at least <code>ndigits.abs</code> trailing zeros:
|
|
|
|
*
|
|
|
|
* 555.ceil(-1) # => 560
|
|
|
|
* 555.ceil(-2) # => 600
|
|
|
|
* -555.ceil(-2) # => -500
|
|
|
|
* 555.ceil(-3) # => 1000
|
2016-04-13 09:50:24 +03:00
|
|
|
*
|
2017-05-06 22:58:12 +03:00
|
|
|
* Returns +self+ when +ndigits+ is zero or positive.
|
2016-04-13 09:50:24 +03:00
|
|
|
*
|
2021-11-18 01:00:50 +03:00
|
|
|
* 555.ceil # => 555
|
|
|
|
* 555.ceil(50) # => 555
|
|
|
|
*
|
|
|
|
* Related: Integer#floor.
|
|
|
|
*
|
2016-04-13 09:50:24 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
int_ceil(int argc, VALUE* argv, VALUE num)
|
|
|
|
{
|
|
|
|
int ndigits;
|
|
|
|
|
|
|
|
if (!rb_check_arity(argc, 0, 1)) return num;
|
|
|
|
ndigits = NUM2INT(argv[0]);
|
2017-05-06 22:58:12 +03:00
|
|
|
if (ndigits >= 0) {
|
2016-04-13 09:50:24 +03:00
|
|
|
return num;
|
|
|
|
}
|
|
|
|
return rb_int_ceil(num, ndigits);
|
|
|
|
}
|
|
|
|
|
2016-04-18 06:55:33 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-18 01:00:50 +03:00
|
|
|
* truncate(ndigits = 0) -> integer
|
2016-04-18 06:55:33 +03:00
|
|
|
*
|
2021-11-18 01:00:50 +03:00
|
|
|
* Returns +self+ truncated (toward zero) to
|
|
|
|
* a precision of +ndigits+ decimal digits.
|
2017-04-03 22:23:13 +03:00
|
|
|
*
|
2021-11-18 01:00:50 +03:00
|
|
|
* When +ndigits+ is negative, the returned value
|
|
|
|
* has at least <tt>ndigits.abs</tt> trailing zeros:
|
|
|
|
*
|
|
|
|
* 555.truncate(-1) # => 550
|
|
|
|
* 555.truncate(-2) # => 500
|
|
|
|
* -555.truncate(-2) # => -500
|
2016-04-18 06:55:33 +03:00
|
|
|
*
|
2017-05-06 22:58:12 +03:00
|
|
|
* Returns +self+ when +ndigits+ is zero or positive.
|
2016-04-18 06:55:33 +03:00
|
|
|
*
|
2021-11-18 01:00:50 +03:00
|
|
|
* 555.truncate # => 555
|
|
|
|
* 555.truncate(50) # => 555
|
|
|
|
*
|
|
|
|
* Related: Integer#round.
|
|
|
|
*
|
2016-04-18 06:55:33 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
int_truncate(int argc, VALUE* argv, VALUE num)
|
|
|
|
{
|
|
|
|
int ndigits;
|
|
|
|
|
|
|
|
if (!rb_check_arity(argc, 0, 1)) return num;
|
|
|
|
ndigits = NUM2INT(argv[0]);
|
2017-05-06 22:58:12 +03:00
|
|
|
if (ndigits >= 0) {
|
2016-04-18 06:55:33 +03:00
|
|
|
return num;
|
|
|
|
}
|
|
|
|
return rb_int_truncate(num, ndigits);
|
|
|
|
}
|
|
|
|
|
2017-02-24 11:36:16 +03:00
|
|
|
#define DEFINE_INT_SQRT(rettype, prefix, argtype) \
|
|
|
|
rettype \
|
|
|
|
prefix##_isqrt(argtype n) \
|
|
|
|
{ \
|
2017-02-28 04:10:38 +03:00
|
|
|
if (!argtype##_IN_DOUBLE_P(n)) { \
|
2017-02-24 11:36:16 +03:00
|
|
|
unsigned int b = bit_length(n); \
|
|
|
|
argtype t; \
|
|
|
|
rettype x = (rettype)(n >> (b/2+1)); \
|
|
|
|
x |= ((rettype)1LU << (b-1)/2); \
|
|
|
|
while ((t = n/x) < (argtype)x) x = (rettype)((x + t) >> 1); \
|
|
|
|
return x; \
|
|
|
|
} \
|
2017-02-28 05:58:12 +03:00
|
|
|
return (rettype)sqrt(argtype##_TO_DOUBLE(n)); \
|
2017-02-24 11:36:16 +03:00
|
|
|
}
|
|
|
|
|
2017-02-28 04:10:38 +03:00
|
|
|
#if SIZEOF_LONG*CHAR_BIT > DBL_MANT_DIG
|
|
|
|
# define RB_ULONG_IN_DOUBLE_P(n) ((n) < (1UL << DBL_MANT_DIG))
|
|
|
|
#else
|
|
|
|
# define RB_ULONG_IN_DOUBLE_P(n) 1
|
|
|
|
#endif
|
2017-02-28 05:58:12 +03:00
|
|
|
#define RB_ULONG_TO_DOUBLE(n) (double)(n)
|
2017-02-28 04:10:38 +03:00
|
|
|
#define RB_ULONG unsigned long
|
|
|
|
DEFINE_INT_SQRT(unsigned long, rb_ulong, RB_ULONG)
|
|
|
|
|
|
|
|
#if 2*SIZEOF_BDIGIT > SIZEOF_LONG
|
|
|
|
# if 2*SIZEOF_BDIGIT*CHAR_BIT > DBL_MANT_DIG
|
|
|
|
# define BDIGIT_DBL_IN_DOUBLE_P(n) ((n) < ((BDIGIT_DBL)1UL << DBL_MANT_DIG))
|
|
|
|
# else
|
|
|
|
# define BDIGIT_DBL_IN_DOUBLE_P(n) 1
|
|
|
|
# endif
|
2017-02-28 05:58:12 +03:00
|
|
|
# ifdef ULL_TO_DOUBLE
|
|
|
|
# define BDIGIT_DBL_TO_DOUBLE(n) ULL_TO_DOUBLE(n)
|
|
|
|
# else
|
|
|
|
# define BDIGIT_DBL_TO_DOUBLE(n) (double)(n)
|
|
|
|
# endif
|
2017-02-24 11:36:16 +03:00
|
|
|
DEFINE_INT_SQRT(BDIGIT, rb_bdigit_dbl, BDIGIT_DBL)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define domain_error(msg) \
|
|
|
|
rb_raise(rb_eMathDomainError, "Numerical argument is out of domain - " #msg)
|
|
|
|
|
2017-02-26 15:51:41 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-11-18 01:00:50 +03:00
|
|
|
* Integer.sqrt(numeric) -> integer
|
2017-02-26 15:51:41 +03:00
|
|
|
*
|
|
|
|
* Returns the integer square root of the non-negative integer +n+,
|
2021-11-18 01:00:50 +03:00
|
|
|
* which is the largest non-negative integer less than or equal to the
|
|
|
|
* square root of +numeric+.
|
2017-02-26 15:51:41 +03:00
|
|
|
*
|
2021-11-18 01:00:50 +03:00
|
|
|
* Integer.sqrt(0) # => 0
|
|
|
|
* Integer.sqrt(1) # => 1
|
|
|
|
* Integer.sqrt(24) # => 4
|
|
|
|
* Integer.sqrt(25) # => 5
|
|
|
|
* Integer.sqrt(10**400) # => 10**200
|
2017-02-26 15:51:41 +03:00
|
|
|
*
|
2021-11-18 01:00:50 +03:00
|
|
|
* If +numeric+ is not an \Integer, it is converted to an \Integer:
|
|
|
|
*
|
|
|
|
* Integer.sqrt(Complex(4, 0)) # => 2
|
|
|
|
* Integer.sqrt(Rational(4, 1)) # => 2
|
|
|
|
* Integer.sqrt(4.0) # => 2
|
|
|
|
* Integer.sqrt(3.14159) # => 1
|
|
|
|
*
|
|
|
|
* This method is equivalent to <tt>Math.sqrt(numeric).floor</tt>,
|
|
|
|
* except that the result of the latter code may differ from the true value
|
2017-02-26 15:51:41 +03:00
|
|
|
* due to the limited precision of floating point arithmetic.
|
|
|
|
*
|
2021-11-18 01:00:50 +03:00
|
|
|
* Integer.sqrt(10**46) # => 100000000000000000000000
|
|
|
|
* Math.sqrt(10**46).floor # => 99999999999999991611392
|
|
|
|
*
|
|
|
|
* Raises an exception if +numeric+ is negative.
|
2017-02-26 15:51:41 +03:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2017-02-24 11:36:16 +03:00
|
|
|
static VALUE
|
|
|
|
rb_int_s_isqrt(VALUE self, VALUE num)
|
|
|
|
{
|
|
|
|
unsigned long n, sq;
|
2017-02-24 12:39:17 +03:00
|
|
|
num = rb_to_int(num);
|
2017-02-24 11:36:16 +03:00
|
|
|
if (FIXNUM_P(num)) {
|
|
|
|
if (FIXNUM_NEGATIVE_P(num)) {
|
|
|
|
domain_error("isqrt");
|
|
|
|
}
|
|
|
|
n = FIX2ULONG(num);
|
|
|
|
sq = rb_ulong_isqrt(n);
|
|
|
|
return LONG2FIX(sq);
|
|
|
|
}
|
2017-02-24 12:39:17 +03:00
|
|
|
else {
|
2017-02-24 11:36:16 +03:00
|
|
|
size_t biglen;
|
|
|
|
if (RBIGNUM_NEGATIVE_P(num)) {
|
|
|
|
domain_error("isqrt");
|
|
|
|
}
|
|
|
|
biglen = BIGNUM_LEN(num);
|
|
|
|
if (biglen == 0) return INT2FIX(0);
|
|
|
|
#if SIZEOF_BDIGIT <= SIZEOF_LONG
|
|
|
|
/* short-circuit */
|
|
|
|
if (biglen == 1) {
|
|
|
|
n = BIGNUM_DIGITS(num)[0];
|
|
|
|
sq = rb_ulong_isqrt(n);
|
|
|
|
return ULONG2NUM(sq);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return rb_big_isqrt(num);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-08 11:59:16 +03:00
|
|
|
/* :nodoc: */
|
2018-10-07 07:02:46 +03:00
|
|
|
static VALUE
|
|
|
|
int_s_try_convert(VALUE self, VALUE num)
|
|
|
|
{
|
|
|
|
return rb_check_integer_type(num);
|
|
|
|
}
|
|
|
|
|
2010-05-08 08:50:09 +04:00
|
|
|
/*
|
|
|
|
* Document-class: ZeroDivisionError
|
|
|
|
*
|
|
|
|
* Raised when attempting to divide an integer by 0.
|
|
|
|
*
|
2017-05-06 10:17:41 +03:00
|
|
|
* 42 / 0 #=> ZeroDivisionError: divided by 0
|
2010-05-08 08:50:09 +04:00
|
|
|
*
|
2013-07-15 22:27:23 +04:00
|
|
|
* Note that only division by an exact 0 will raise the exception:
|
2010-05-08 08:50:09 +04:00
|
|
|
*
|
2017-05-06 10:17:41 +03:00
|
|
|
* 42 / 0.0 #=> Float::INFINITY
|
|
|
|
* 42 / -0.0 #=> -Float::INFINITY
|
|
|
|
* 0 / 0.0 #=> NaN
|
2010-05-08 08:50:09 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Document-class: FloatDomainError
|
|
|
|
*
|
2013-07-15 22:27:23 +04:00
|
|
|
* Raised when attempting to convert special float values (in particular
|
2017-05-06 10:17:41 +03:00
|
|
|
* +Infinity+ or +NaN+) to numerical classes which don't support them.
|
2010-05-08 08:50:09 +04:00
|
|
|
*
|
2017-05-06 10:17:41 +03:00
|
|
|
* Float::INFINITY.to_r #=> FloatDomainError: Infinity
|
2010-05-08 08:50:09 +04:00
|
|
|
*/
|
|
|
|
|
2013-07-15 06:33:58 +04:00
|
|
|
/*
|
2015-10-05 09:42:14 +03:00
|
|
|
* Document-class: Numeric
|
|
|
|
*
|
|
|
|
* Numeric is the class from which all higher-level numeric classes should inherit.
|
2015-10-05 09:42:18 +03:00
|
|
|
*
|
2015-10-05 09:42:14 +03:00
|
|
|
* Numeric allows instantiation of heap-allocated objects. Other core numeric classes such as
|
|
|
|
* Integer are implemented as immediates, which means that each Integer is a single immutable
|
|
|
|
* object which is always passed by value.
|
2015-10-05 09:42:18 +03:00
|
|
|
*
|
2015-10-05 09:42:14 +03:00
|
|
|
* a = 1
|
2017-05-06 10:17:41 +03:00
|
|
|
* 1.object_id == a.object_id #=> true
|
2015-10-05 09:42:18 +03:00
|
|
|
*
|
2015-10-05 09:42:14 +03:00
|
|
|
* There can only ever be one instance of the integer +1+, for example. Ruby ensures this
|
2018-04-07 16:03:35 +03:00
|
|
|
* by preventing instantiation. If duplication is attempted, the same instance is returned.
|
2015-10-05 09:42:18 +03:00
|
|
|
*
|
2018-04-07 16:03:35 +03:00
|
|
|
* Integer.new(1) #=> NoMethodError: undefined method `new' for Integer:Class
|
|
|
|
* 1.dup #=> 1
|
|
|
|
* 1.object_id == 1.dup.object_id #=> true
|
2015-10-05 09:42:18 +03:00
|
|
|
*
|
2015-10-05 09:42:14 +03:00
|
|
|
* For this reason, Numeric should be used when defining other numeric classes.
|
2015-10-05 09:42:18 +03:00
|
|
|
*
|
2015-10-05 09:42:14 +03:00
|
|
|
* Classes which inherit from Numeric must implement +coerce+, which returns a two-member
|
|
|
|
* Array containing an object that has been coerced into an instance of the new class
|
|
|
|
* and +self+ (see #coerce).
|
2015-10-05 09:42:18 +03:00
|
|
|
*
|
2015-10-05 09:42:14 +03:00
|
|
|
* Inheriting classes should also implement arithmetic operator methods (<code>+</code>,
|
|
|
|
* <code>-</code>, <code>*</code> and <code>/</code>) and the <code><=></code> operator (see
|
|
|
|
* Comparable). These methods may rely on +coerce+ to ensure interoperability with
|
|
|
|
* instances of other numeric classes.
|
2015-10-05 09:42:18 +03:00
|
|
|
*
|
2015-10-05 09:42:14 +03:00
|
|
|
* class Tally < Numeric
|
|
|
|
* def initialize(string)
|
|
|
|
* @string = string
|
|
|
|
* end
|
2015-10-05 09:42:18 +03:00
|
|
|
*
|
2015-10-05 09:42:14 +03:00
|
|
|
* def to_s
|
|
|
|
* @string
|
|
|
|
* end
|
2015-10-05 09:42:18 +03:00
|
|
|
*
|
2015-10-05 09:42:14 +03:00
|
|
|
* def to_i
|
|
|
|
* @string.size
|
|
|
|
* end
|
2015-10-05 09:42:18 +03:00
|
|
|
*
|
2015-10-05 09:42:14 +03:00
|
|
|
* def coerce(other)
|
|
|
|
* [self.class.new('|' * other.to_i), self]
|
|
|
|
* end
|
2015-10-05 09:42:18 +03:00
|
|
|
*
|
2015-10-05 09:42:14 +03:00
|
|
|
* def <=>(other)
|
|
|
|
* to_i <=> other.to_i
|
|
|
|
* end
|
2015-10-05 09:42:18 +03:00
|
|
|
*
|
2015-10-05 09:42:14 +03:00
|
|
|
* def +(other)
|
|
|
|
* self.class.new('|' * (to_i + other.to_i))
|
|
|
|
* end
|
2015-10-05 09:42:18 +03:00
|
|
|
*
|
2015-10-05 09:42:14 +03:00
|
|
|
* def -(other)
|
|
|
|
* self.class.new('|' * (to_i - other.to_i))
|
|
|
|
* end
|
2015-10-05 09:42:18 +03:00
|
|
|
*
|
2015-10-05 09:42:14 +03:00
|
|
|
* def *(other)
|
|
|
|
* self.class.new('|' * (to_i * other.to_i))
|
|
|
|
* end
|
2015-10-05 09:42:18 +03:00
|
|
|
*
|
2015-10-05 09:42:14 +03:00
|
|
|
* def /(other)
|
|
|
|
* self.class.new('|' * (to_i / other.to_i))
|
|
|
|
* end
|
|
|
|
* end
|
2015-10-05 09:42:18 +03:00
|
|
|
*
|
2015-10-05 09:42:14 +03:00
|
|
|
* tally = Tally.new('||')
|
|
|
|
* puts tally * 2 #=> "||||"
|
|
|
|
* puts tally > 1 #=> true
|
2021-05-18 16:27:41 +03:00
|
|
|
*
|
|
|
|
* == What's Here
|
|
|
|
*
|
|
|
|
* First, what's elsewhere. \Class \Numeric:
|
|
|
|
*
|
2022-02-06 18:30:11 +03:00
|
|
|
* - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
|
|
|
|
* - Includes {module Comparable}[rdoc-ref:Comparable@What-27s+Here].
|
2021-05-18 16:27:41 +03:00
|
|
|
*
|
|
|
|
* Here, class \Numeric provides methods for:
|
|
|
|
*
|
2022-02-06 18:37:06 +03:00
|
|
|
* - {Querying}[rdoc-ref:Numeric@Querying]
|
|
|
|
* - {Comparing}[rdoc-ref:Numeric@Comparing]
|
|
|
|
* - {Converting}[rdoc-ref:Numeric@Converting]
|
|
|
|
* - {Other}[rdoc-ref:Numeric@Other]
|
2021-05-18 16:27:41 +03:00
|
|
|
*
|
|
|
|
* === Querying
|
|
|
|
*
|
2022-03-25 23:43:46 +03:00
|
|
|
* - #finite?: Returns true unless +self+ is infinite or not a number.
|
|
|
|
* - #infinite?: Returns -1, +nil+ or +1, depending on whether +self+
|
|
|
|
* is <tt>-Infinity<tt>, finite, or <tt>+Infinity</tt>.
|
|
|
|
* - #integer?: Returns whether +self+ is an integer.
|
|
|
|
* - #negative?: Returns whether +self+ is negative.
|
|
|
|
* - #nonzero?: Returns whether +self+ is not zero.
|
|
|
|
* - #positive?: Returns whether +self+ is positive.
|
|
|
|
* - #real?: Returns whether +self+ is a real value.
|
|
|
|
* - #zero?: Returns whether +self+ is zero.
|
2021-05-18 16:27:41 +03:00
|
|
|
*
|
|
|
|
* === Comparing
|
|
|
|
*
|
2022-03-26 15:07:06 +03:00
|
|
|
* - #<=>: Returns:
|
2022-03-25 23:43:46 +03:00
|
|
|
*
|
2021-05-18 16:27:41 +03:00
|
|
|
* - -1 if +self+ is less than the given value.
|
|
|
|
* - 0 if +self+ is equal to the given value.
|
2021-11-23 04:04:25 +03:00
|
|
|
* - 1 if +self+ is greater than the given value.
|
2021-05-18 16:27:41 +03:00
|
|
|
* - +nil+ if +self+ and the given value are not comparable.
|
2022-03-25 23:43:46 +03:00
|
|
|
*
|
|
|
|
* - #eql?: Returns whether +self+ and the given value have the same value and type.
|
2021-05-18 16:27:41 +03:00
|
|
|
*
|
|
|
|
* === Converting
|
|
|
|
*
|
2022-03-25 23:43:46 +03:00
|
|
|
* - #% (aliased as #modulo): Returns the remainder of +self+ divided by the given value.
|
|
|
|
* - #-@: Returns the value of +self+, negated.
|
|
|
|
* - #abs (aliased as #magnitude): Returns the absolute value of +self+.
|
|
|
|
* - #abs2: Returns the square of +self+.
|
|
|
|
* - #angle (aliased as #arg and #phase): Returns 0 if +self+ is positive,
|
|
|
|
* Math::PI otherwise.
|
|
|
|
* - #ceil: Returns the smallest number greater than or equal to +self+,
|
|
|
|
* to a given precision.
|
|
|
|
* - #coerce: Returns array <tt>[coerced_self, coerced_other]</tt>
|
|
|
|
* for the given other value.
|
|
|
|
* - #conj (aliased as #conjugate): Returns the complex conjugate of +self+.
|
|
|
|
* - #denominator: Returns the denominator (always positive)
|
|
|
|
* of the Rational representation of +self+.
|
|
|
|
* - #div: Returns the value of +self+ divided by the given value
|
|
|
|
* and converted to an integer.
|
|
|
|
* - #divmod: Returns array <tt>[quotient, modulus]</tt> resulting
|
|
|
|
* from dividing +self+ the given divisor.
|
|
|
|
* - #fdiv: Returns the Float result of dividing +self+ by the given divisor.
|
|
|
|
* - #floor: Returns the largest number less than or equal to +self+,
|
|
|
|
* to a given precision.
|
|
|
|
* - #i: Returns the Complex object <tt>Complex(0, self)</tt>.
|
|
|
|
* the given value.
|
|
|
|
* - #imaginary (aliased as #imag): Returns the imaginary part of the +self+.
|
|
|
|
* - #numerator: Returns the numerator of the Rational representation of +self+;
|
|
|
|
* has the same sign as +self+.
|
|
|
|
* - #polar: Returns the array <tt>[self.abs, self.arg]</tt>.
|
|
|
|
* - #quo: Returns the value of +self+ divided by the given value.
|
|
|
|
* - #real: Returns the real part of +self+.
|
|
|
|
* - #rect (aliased as #rectangular): Returns the array <tt>[self, 0]</tt>.
|
|
|
|
* - #remainder: Returns <tt>self-arg*(self/arg).truncate</tt> for the given +arg+.
|
|
|
|
* - #round: Returns the value of +self+ rounded to the nearest value
|
|
|
|
* for the given a precision.
|
|
|
|
* - #to_c: Returns the Complex representation of +self+.
|
|
|
|
* - #to_int: Returns the Integer representation of +self+, truncating if necessary.
|
|
|
|
* - #truncate: Returns +self+ truncated (toward zero) to a given precision.
|
2021-05-18 16:27:41 +03:00
|
|
|
*
|
|
|
|
* === Other
|
|
|
|
*
|
2022-03-25 23:43:46 +03:00
|
|
|
* - #clone: Returns +self+; does not allow freezing.
|
|
|
|
* - #dup (aliased as #+@): Returns +self+.
|
|
|
|
* - #step: Invokes the given block with the sequence of specified numbers.
|
2021-05-18 16:27:41 +03:00
|
|
|
*
|
2013-07-15 06:33:58 +04:00
|
|
|
*/
|
1998-01-16 15:13:05 +03:00
|
|
|
void
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
Init_Numeric(void)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2016-05-13 02:46:43 +03:00
|
|
|
#ifdef _UNICOSMP
|
2003-12-20 18:45:15 +03:00
|
|
|
/* Turn off floating point exceptions for divide by zero, etc. */
|
|
|
|
_set_Creg(0, 0);
|
1999-08-13 09:45:20 +04:00
|
|
|
#endif
|
2020-09-25 20:56:30 +03:00
|
|
|
id_coerce = rb_intern_const("coerce");
|
|
|
|
id_to = rb_intern_const("to");
|
|
|
|
id_by = rb_intern_const("by");
|
1998-01-16 15:13:05 +03:00
|
|
|
|
1999-08-13 09:45:20 +04:00
|
|
|
rb_eZeroDivError = rb_define_class("ZeroDivisionError", rb_eStandardError);
|
2000-05-01 13:42:38 +04:00
|
|
|
rb_eFloatDomainError = rb_define_class("FloatDomainError", rb_eRangeError);
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_cNumeric = rb_define_class("Numeric", rb_cObject);
|
|
|
|
|
2003-12-01 16:16:09 +03:00
|
|
|
rb_define_method(rb_cNumeric, "singleton_method_added", num_sadded, 1);
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_include_module(rb_cNumeric, rb_mComparable);
|
2003-04-03 09:25:00 +04:00
|
|
|
rb_define_method(rb_cNumeric, "coerce", num_coerce, 1);
|
2017-02-22 05:02:11 +03:00
|
|
|
rb_define_method(rb_cNumeric, "clone", num_clone, -1);
|
|
|
|
rb_define_method(rb_cNumeric, "dup", num_dup, 0);
|
1999-01-20 07:59:39 +03:00
|
|
|
|
2009-08-17 02:28:48 +04:00
|
|
|
rb_define_method(rb_cNumeric, "i", num_imaginary, 0);
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_define_method(rb_cNumeric, "+@", num_uplus, 0);
|
|
|
|
rb_define_method(rb_cNumeric, "-@", num_uminus, 0);
|
2002-11-22 12:14:24 +03:00
|
|
|
rb_define_method(rb_cNumeric, "<=>", num_cmp, 1);
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_define_method(rb_cNumeric, "eql?", num_eql, 1);
|
2008-05-27 16:47:14 +04:00
|
|
|
rb_define_method(rb_cNumeric, "fdiv", num_fdiv, 1);
|
2003-01-23 09:22:50 +03:00
|
|
|
rb_define_method(rb_cNumeric, "div", num_div, 1);
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_define_method(rb_cNumeric, "divmod", num_divmod, 1);
|
2009-06-20 16:37:13 +04:00
|
|
|
rb_define_method(rb_cNumeric, "%", num_modulo, 1);
|
2000-07-06 11:21:26 +04:00
|
|
|
rb_define_method(rb_cNumeric, "modulo", num_modulo, 1);
|
2000-07-04 08:17:26 +04:00
|
|
|
rb_define_method(rb_cNumeric, "remainder", num_remainder, 1);
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_define_method(rb_cNumeric, "abs", num_abs, 0);
|
2008-08-29 17:41:41 +04:00
|
|
|
rb_define_method(rb_cNumeric, "magnitude", num_abs, 0);
|
2002-07-29 10:14:10 +04:00
|
|
|
rb_define_method(rb_cNumeric, "to_int", num_to_int, 0);
|
1999-01-20 07:59:39 +03:00
|
|
|
|
|
|
|
rb_define_method(rb_cNumeric, "zero?", num_zero_p, 0);
|
|
|
|
rb_define_method(rb_cNumeric, "nonzero?", num_nonzero_p, 0);
|
|
|
|
|
2016-04-18 06:57:34 +03:00
|
|
|
rb_define_method(rb_cNumeric, "floor", num_floor, -1);
|
|
|
|
rb_define_method(rb_cNumeric, "ceil", num_ceil, -1);
|
2007-05-31 21:01:15 +04:00
|
|
|
rb_define_method(rb_cNumeric, "round", num_round, -1);
|
2016-04-18 06:57:34 +03:00
|
|
|
rb_define_method(rb_cNumeric, "truncate", num_truncate, -1);
|
2002-04-24 08:54:16 +04:00
|
|
|
rb_define_method(rb_cNumeric, "step", num_step, -1);
|
2015-05-17 09:01:47 +03:00
|
|
|
rb_define_method(rb_cNumeric, "positive?", num_positive_p, 0);
|
|
|
|
rb_define_method(rb_cNumeric, "negative?", num_negative_p, 0);
|
2000-07-06 11:21:26 +04:00
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_cInteger = rb_define_class("Integer", rb_cNumeric);
|
2002-12-20 11:33:17 +03:00
|
|
|
rb_undef_alloc_func(rb_cInteger);
|
2001-08-29 10:28:51 +04:00
|
|
|
rb_undef_method(CLASS_OF(rb_cInteger), "new");
|
2017-02-24 11:36:16 +03:00
|
|
|
rb_define_singleton_method(rb_cInteger, "sqrt", rb_int_s_isqrt, 1);
|
2018-10-07 07:02:46 +03:00
|
|
|
rb_define_singleton_method(rb_cInteger, "try_convert", int_s_try_convert, 1);
|
2001-08-29 10:28:51 +04:00
|
|
|
|
Optimize dynamic string interpolation for symbol/true/false/nil/0-9
This provides a significant speedup for symbol, true, false,
nil, and 0-9, class/module, and a small speedup in most other cases.
Speedups (using included benchmarks):
:symbol :: 60%
0-9 :: 50%
Class/Module :: 50%
nil/true/false :: 20%
integer :: 10%
[] :: 10%
"" :: 3%
One reason this approach is faster is it reduces the number of
VM instructions for each interpolated value.
Initial idea, approach, and benchmarks from Eric Wong. I applied
the same approach against the master branch, updating it to handle
the significant internal changes since this was first proposed 4
years ago (such as CALL_INFO/CALL_CACHE -> CALL_DATA). I also
expanded it to optimize true/false/nil/0-9/class/module, and added
handling of missing methods, refined methods, and RUBY_DEBUG.
This renames the tostring insn to anytostring, and adds an
objtostring insn that implements the optimization. This requires
making a few functions non-static, and adding some non-static
functions.
This disables 4 YJIT tests. Those tests should be reenabled after
YJIT optimizes the new objtostring insn.
Implements [Feature #13715]
Co-authored-by: Eric Wong <e@80x24.org>
Co-authored-by: Alan Wu <XrXr@users.noreply.github.com>
Co-authored-by: Yusuke Endoh <mame@ruby-lang.org>
Co-authored-by: Koichi Sasada <ko1@atdot.net>
2021-11-19 02:10:20 +03:00
|
|
|
rb_define_method(rb_cInteger, "to_s", rb_int_to_s, -1);
|
2016-03-18 15:33:28 +03:00
|
|
|
rb_define_alias(rb_cInteger, "inspect", "to_s");
|
2017-12-12 12:12:14 +03:00
|
|
|
rb_define_method(rb_cInteger, "allbits?", int_allbits_p, 1);
|
|
|
|
rb_define_method(rb_cInteger, "anybits?", int_anybits_p, 1);
|
|
|
|
rb_define_method(rb_cInteger, "nobits?", int_nobits_p, 1);
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_define_method(rb_cInteger, "upto", int_upto, 1);
|
|
|
|
rb_define_method(rb_cInteger, "downto", int_downto, 1);
|
|
|
|
rb_define_method(rb_cInteger, "times", int_dotimes, 0);
|
|
|
|
rb_define_method(rb_cInteger, "succ", int_succ, 0);
|
|
|
|
rb_define_method(rb_cInteger, "next", int_succ, 0);
|
2007-01-30 07:27:04 +03:00
|
|
|
rb_define_method(rb_cInteger, "pred", int_pred, 0);
|
2007-10-26 12:38:14 +04:00
|
|
|
rb_define_method(rb_cInteger, "chr", int_chr, -1);
|
2016-03-18 17:52:46 +03:00
|
|
|
rb_define_method(rb_cInteger, "to_f", int_to_f, 0);
|
2016-04-13 09:47:55 +03:00
|
|
|
rb_define_method(rb_cInteger, "floor", int_floor, -1);
|
2016-04-13 09:50:24 +03:00
|
|
|
rb_define_method(rb_cInteger, "ceil", int_ceil, -1);
|
2016-04-18 06:55:33 +03:00
|
|
|
rb_define_method(rb_cInteger, "truncate", int_truncate, -1);
|
2007-06-01 20:27:05 +04:00
|
|
|
rb_define_method(rb_cInteger, "round", int_round, -1);
|
2016-11-12 04:29:01 +03:00
|
|
|
rb_define_method(rb_cInteger, "<=>", rb_int_cmp, 1);
|
1999-01-20 07:59:39 +03:00
|
|
|
|
2016-04-30 15:24:06 +03:00
|
|
|
rb_define_method(rb_cInteger, "+", rb_int_plus, 1);
|
2016-04-30 15:09:31 +03:00
|
|
|
rb_define_method(rb_cInteger, "-", rb_int_minus, 1);
|
2016-04-30 14:54:26 +03:00
|
|
|
rb_define_method(rb_cInteger, "*", rb_int_mul, 1);
|
2016-04-30 15:39:53 +03:00
|
|
|
rb_define_method(rb_cInteger, "/", rb_int_div, 1);
|
2016-04-30 08:43:15 +03:00
|
|
|
rb_define_method(rb_cInteger, "div", rb_int_idiv, 1);
|
2016-04-30 14:31:28 +03:00
|
|
|
rb_define_method(rb_cInteger, "%", rb_int_modulo, 1);
|
2016-04-30 08:26:52 +03:00
|
|
|
rb_define_method(rb_cInteger, "modulo", rb_int_modulo, 1);
|
2016-04-30 11:27:30 +03:00
|
|
|
rb_define_method(rb_cInteger, "remainder", int_remainder, 1);
|
rational.c: optimize Rational#{floor,ceil,round,truncate}
* rational.c (f_{expt10,round_common},nurat_{floor,ceil,round_half_{up,even}}):
optimize Rational#{floor,ceil,round,truncate}.
Author: Tadashi Saito <tad.a.digger@gmail.com>
* numeric.c (rb_int_divmod): rename from int_divmod to be exported.
* numeric.c (rb_int_and): rename from int_and to be exported.
* intern.h (rb_int_{divmod,and}): exported.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@56742 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2016-11-12 09:45:11 +03:00
|
|
|
rb_define_method(rb_cInteger, "divmod", rb_int_divmod, 1);
|
2016-11-10 18:23:33 +03:00
|
|
|
rb_define_method(rb_cInteger, "fdiv", rb_int_fdiv, 1);
|
2016-04-30 06:59:02 +03:00
|
|
|
rb_define_method(rb_cInteger, "**", rb_int_pow, 1);
|
1999-01-20 07:59:39 +03:00
|
|
|
|
2017-12-06 15:36:37 +03:00
|
|
|
rb_define_method(rb_cInteger, "pow", rb_int_powm, -1); /* in bignum.c */
|
2017-12-04 05:35:40 +03:00
|
|
|
|
2016-11-12 05:24:32 +03:00
|
|
|
rb_define_method(rb_cInteger, "===", rb_int_equal, 1);
|
|
|
|
rb_define_method(rb_cInteger, "==", rb_int_equal, 1);
|
2016-11-22 08:21:12 +03:00
|
|
|
rb_define_method(rb_cInteger, ">", rb_int_gt, 1);
|
2016-05-17 18:08:33 +03:00
|
|
|
rb_define_method(rb_cInteger, ">=", rb_int_ge, 1);
|
2016-04-30 13:10:23 +03:00
|
|
|
rb_define_method(rb_cInteger, "<", int_lt, 1);
|
2016-04-30 12:48:25 +03:00
|
|
|
rb_define_method(rb_cInteger, "<=", int_le, 1);
|
|
|
|
|
rational.c: optimize Rational#{floor,ceil,round,truncate}
* rational.c (f_{expt10,round_common},nurat_{floor,ceil,round_half_{up,even}}):
optimize Rational#{floor,ceil,round,truncate}.
Author: Tadashi Saito <tad.a.digger@gmail.com>
* numeric.c (rb_int_divmod): rename from int_divmod to be exported.
* numeric.c (rb_int_and): rename from int_and to be exported.
* intern.h (rb_int_{divmod,and}): exported.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@56742 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2016-11-12 09:45:11 +03:00
|
|
|
rb_define_method(rb_cInteger, "&", rb_int_and, 1);
|
2016-04-30 05:54:14 +03:00
|
|
|
rb_define_method(rb_cInteger, "|", int_or, 1);
|
2016-04-27 18:35:23 +03:00
|
|
|
rb_define_method(rb_cInteger, "^", int_xor, 1);
|
2019-04-28 17:24:09 +03:00
|
|
|
rb_define_method(rb_cInteger, "[]", int_aref, -1);
|
1999-01-20 07:59:39 +03:00
|
|
|
|
2016-04-26 15:23:05 +03:00
|
|
|
rb_define_method(rb_cInteger, "<<", rb_int_lshift, 1);
|
2016-04-26 15:09:40 +03:00
|
|
|
rb_define_method(rb_cInteger, ">>", rb_int_rshift, 1);
|
1999-01-20 07:59:39 +03:00
|
|
|
|
2016-06-13 14:43:54 +03:00
|
|
|
rb_define_method(rb_cInteger, "digits", rb_int_digits, -1);
|
2016-04-30 15:55:59 +03:00
|
|
|
|
Optimize dynamic string interpolation for symbol/true/false/nil/0-9
This provides a significant speedup for symbol, true, false,
nil, and 0-9, class/module, and a small speedup in most other cases.
Speedups (using included benchmarks):
:symbol :: 60%
0-9 :: 50%
Class/Module :: 50%
nil/true/false :: 20%
integer :: 10%
[] :: 10%
"" :: 3%
One reason this approach is faster is it reduces the number of
VM instructions for each interpolated value.
Initial idea, approach, and benchmarks from Eric Wong. I applied
the same approach against the master branch, updating it to handle
the significant internal changes since this was first proposed 4
years ago (such as CALL_INFO/CALL_CACHE -> CALL_DATA). I also
expanded it to optimize true/false/nil/0-9/class/module, and added
handling of missing methods, refined methods, and RUBY_DEBUG.
This renames the tostring insn to anytostring, and adds an
objtostring insn that implements the optimization. This requires
making a few functions non-static, and adding some non-static
functions.
This disables 4 YJIT tests. Those tests should be reenabled after
YJIT optimizes the new objtostring insn.
Implements [Feature #13715]
Co-authored-by: Eric Wong <e@80x24.org>
Co-authored-by: Alan Wu <XrXr@users.noreply.github.com>
Co-authored-by: Yusuke Endoh <mame@ruby-lang.org>
Co-authored-by: Koichi Sasada <ko1@atdot.net>
2021-11-19 02:10:20 +03:00
|
|
|
rb_fix_to_s_static[0] = rb_fstring_literal("0");
|
|
|
|
rb_fix_to_s_static[1] = rb_fstring_literal("1");
|
|
|
|
rb_fix_to_s_static[2] = rb_fstring_literal("2");
|
|
|
|
rb_fix_to_s_static[3] = rb_fstring_literal("3");
|
|
|
|
rb_fix_to_s_static[4] = rb_fstring_literal("4");
|
|
|
|
rb_fix_to_s_static[5] = rb_fstring_literal("5");
|
|
|
|
rb_fix_to_s_static[6] = rb_fstring_literal("6");
|
|
|
|
rb_fix_to_s_static[7] = rb_fstring_literal("7");
|
|
|
|
rb_fix_to_s_static[8] = rb_fstring_literal("8");
|
|
|
|
rb_fix_to_s_static[9] = rb_fstring_literal("9");
|
|
|
|
for(int i = 0; i < 10; i++) {
|
|
|
|
rb_gc_register_mark_object(rb_fix_to_s_static[i]);
|
|
|
|
}
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_cFloat = rb_define_class("Float", rb_cNumeric);
|
|
|
|
|
2002-12-20 11:33:17 +03:00
|
|
|
rb_undef_alloc_func(rb_cFloat);
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_undef_method(CLASS_OF(rb_cFloat), "new");
|
|
|
|
|
2013-02-03 04:59:51 +04:00
|
|
|
/*
|
|
|
|
* The base of the floating point, or number of unique digits used to
|
|
|
|
* represent the number.
|
|
|
|
*
|
|
|
|
* Usually defaults to 2 on most systems, which would represent a base-10 decimal.
|
|
|
|
*/
|
2002-12-24 11:53:56 +03:00
|
|
|
rb_define_const(rb_cFloat, "RADIX", INT2FIX(FLT_RADIX));
|
2013-02-03 04:59:51 +04:00
|
|
|
/*
|
|
|
|
* The number of base digits for the +double+ data type.
|
|
|
|
*
|
|
|
|
* Usually defaults to 53.
|
|
|
|
*/
|
2002-12-24 11:53:56 +03:00
|
|
|
rb_define_const(rb_cFloat, "MANT_DIG", INT2FIX(DBL_MANT_DIG));
|
2013-02-03 04:59:51 +04:00
|
|
|
/*
|
2014-03-02 05:55:02 +04:00
|
|
|
* The minimum number of significant decimal digits in a double-precision
|
|
|
|
* floating point.
|
2013-02-03 04:59:51 +04:00
|
|
|
*
|
|
|
|
* Usually defaults to 15.
|
|
|
|
*/
|
2002-12-24 11:53:56 +03:00
|
|
|
rb_define_const(rb_cFloat, "DIG", INT2FIX(DBL_DIG));
|
2013-02-03 04:59:51 +04:00
|
|
|
/*
|
2017-05-06 10:17:41 +03:00
|
|
|
* The smallest possible exponent value in a double-precision floating
|
2013-02-03 04:59:51 +04:00
|
|
|
* point.
|
|
|
|
*
|
|
|
|
* Usually defaults to -1021.
|
|
|
|
*/
|
2002-12-24 11:53:56 +03:00
|
|
|
rb_define_const(rb_cFloat, "MIN_EXP", INT2FIX(DBL_MIN_EXP));
|
2013-02-03 04:59:51 +04:00
|
|
|
/*
|
|
|
|
* The largest possible exponent value in a double-precision floating
|
|
|
|
* point.
|
|
|
|
*
|
|
|
|
* Usually defaults to 1024.
|
|
|
|
*/
|
2002-12-24 11:53:56 +03:00
|
|
|
rb_define_const(rb_cFloat, "MAX_EXP", INT2FIX(DBL_MAX_EXP));
|
2013-02-03 04:59:51 +04:00
|
|
|
/*
|
|
|
|
* The smallest negative exponent in a double-precision floating point
|
|
|
|
* where 10 raised to this power minus 1.
|
|
|
|
*
|
|
|
|
* Usually defaults to -307.
|
|
|
|
*/
|
2002-12-24 11:53:56 +03:00
|
|
|
rb_define_const(rb_cFloat, "MIN_10_EXP", INT2FIX(DBL_MIN_10_EXP));
|
2013-02-03 04:59:51 +04:00
|
|
|
/*
|
|
|
|
* The largest positive exponent in a double-precision floating point where
|
|
|
|
* 10 raised to this power minus 1.
|
|
|
|
*
|
|
|
|
* Usually defaults to 308.
|
|
|
|
*/
|
2002-12-24 11:53:56 +03:00
|
|
|
rb_define_const(rb_cFloat, "MAX_10_EXP", INT2FIX(DBL_MAX_10_EXP));
|
2013-02-03 04:59:51 +04:00
|
|
|
/*
|
2015-08-11 17:01:22 +03:00
|
|
|
* The smallest positive normalized number in a double-precision floating point.
|
2013-02-03 04:59:51 +04:00
|
|
|
*
|
|
|
|
* Usually defaults to 2.2250738585072014e-308.
|
2015-08-11 17:01:22 +03:00
|
|
|
*
|
|
|
|
* If the platform supports denormalized numbers,
|
|
|
|
* there are numbers between zero and Float::MIN.
|
|
|
|
* 0.0.next_float returns the smallest positive floating point number
|
|
|
|
* including denormalized numbers.
|
2013-02-03 04:59:51 +04:00
|
|
|
*/
|
2008-09-05 22:24:21 +04:00
|
|
|
rb_define_const(rb_cFloat, "MIN", DBL2NUM(DBL_MIN));
|
2013-02-03 04:59:51 +04:00
|
|
|
/*
|
|
|
|
* The largest possible integer in a double-precision floating point number.
|
|
|
|
*
|
|
|
|
* Usually defaults to 1.7976931348623157e+308.
|
|
|
|
*/
|
2008-09-05 22:24:21 +04:00
|
|
|
rb_define_const(rb_cFloat, "MAX", DBL2NUM(DBL_MAX));
|
2013-02-03 04:59:51 +04:00
|
|
|
/*
|
|
|
|
* The difference between 1 and the smallest double-precision floating
|
2015-08-11 17:01:22 +03:00
|
|
|
* point number greater than 1.
|
2013-02-03 04:59:51 +04:00
|
|
|
*
|
|
|
|
* Usually defaults to 2.2204460492503131e-16.
|
|
|
|
*/
|
2008-09-05 22:24:21 +04:00
|
|
|
rb_define_const(rb_cFloat, "EPSILON", DBL2NUM(DBL_EPSILON));
|
2013-02-03 04:59:51 +04:00
|
|
|
/*
|
|
|
|
* An expression representing positive infinity.
|
|
|
|
*/
|
2018-01-19 04:45:36 +03:00
|
|
|
rb_define_const(rb_cFloat, "INFINITY", DBL2NUM(HUGE_VAL));
|
2013-02-03 04:59:51 +04:00
|
|
|
/*
|
|
|
|
* An expression representing a value which is "not a number".
|
|
|
|
*/
|
2018-01-20 06:16:59 +03:00
|
|
|
rb_define_const(rb_cFloat, "NAN", DBL2NUM(nan("")));
|
2002-12-24 11:53:56 +03:00
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_define_method(rb_cFloat, "to_s", flo_to_s, 0);
|
2012-08-15 15:50:01 +04:00
|
|
|
rb_define_alias(rb_cFloat, "inspect", "to_s");
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_define_method(rb_cFloat, "coerce", flo_coerce, 1);
|
2019-01-01 15:20:05 +03:00
|
|
|
rb_define_method(rb_cFloat, "+", rb_float_plus, 1);
|
2020-12-09 12:48:59 +03:00
|
|
|
rb_define_method(rb_cFloat, "-", rb_float_minus, 1);
|
2019-01-03 09:19:17 +03:00
|
|
|
rb_define_method(rb_cFloat, "*", rb_float_mul, 1);
|
2019-08-10 08:30:34 +03:00
|
|
|
rb_define_method(rb_cFloat, "/", rb_float_div, 1);
|
2008-04-07 17:52:26 +04:00
|
|
|
rb_define_method(rb_cFloat, "quo", flo_quo, 1);
|
|
|
|
rb_define_method(rb_cFloat, "fdiv", flo_quo, 1);
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_define_method(rb_cFloat, "%", flo_mod, 1);
|
2000-07-06 11:21:26 +04:00
|
|
|
rb_define_method(rb_cFloat, "modulo", flo_mod, 1);
|
2000-02-01 06:12:21 +03:00
|
|
|
rb_define_method(rb_cFloat, "divmod", flo_divmod, 1);
|
2016-11-11 19:38:28 +03:00
|
|
|
rb_define_method(rb_cFloat, "**", rb_float_pow, 1);
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_define_method(rb_cFloat, "==", flo_eq, 1);
|
2009-08-12 09:55:06 +04:00
|
|
|
rb_define_method(rb_cFloat, "===", flo_eq, 1);
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_define_method(rb_cFloat, "<=>", flo_cmp, 1);
|
2016-11-22 08:21:12 +03:00
|
|
|
rb_define_method(rb_cFloat, ">", rb_float_gt, 1);
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_define_method(rb_cFloat, ">=", flo_ge, 1);
|
|
|
|
rb_define_method(rb_cFloat, "<", flo_lt, 1);
|
|
|
|
rb_define_method(rb_cFloat, "<=", flo_le, 1);
|
|
|
|
rb_define_method(rb_cFloat, "eql?", flo_eql, 1);
|
|
|
|
rb_define_method(rb_cFloat, "hash", flo_hash, 0);
|
|
|
|
|
2016-04-18 06:56:33 +03:00
|
|
|
rb_define_method(rb_cFloat, "to_i", flo_to_i, 0);
|
|
|
|
rb_define_method(rb_cFloat, "to_int", flo_to_i, 0);
|
2016-04-13 09:54:38 +03:00
|
|
|
rb_define_method(rb_cFloat, "floor", flo_floor, -1);
|
2016-04-13 09:56:36 +03:00
|
|
|
rb_define_method(rb_cFloat, "ceil", flo_ceil, -1);
|
2007-05-31 21:01:15 +04:00
|
|
|
rb_define_method(rb_cFloat, "round", flo_round, -1);
|
2016-04-18 06:56:33 +03:00
|
|
|
rb_define_method(rb_cFloat, "truncate", flo_truncate, -1);
|
2000-06-12 11:48:31 +04:00
|
|
|
|
|
|
|
rb_define_method(rb_cFloat, "nan?", flo_is_nan_p, 0);
|
2017-09-27 05:55:03 +03:00
|
|
|
rb_define_method(rb_cFloat, "infinite?", rb_flo_is_infinite_p, 0);
|
2017-09-27 05:38:51 +03:00
|
|
|
rb_define_method(rb_cFloat, "finite?", rb_flo_is_finite_p, 0);
|
2014-05-18 04:37:10 +04:00
|
|
|
rb_define_method(rb_cFloat, "next_float", flo_next_float, 0);
|
|
|
|
rb_define_method(rb_cFloat, "prev_float", flo_prev_float, 0);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
2013-09-25 11:58:49 +04:00
|
|
|
|
|
|
|
#undef rb_float_value
|
|
|
|
double
|
|
|
|
rb_float_value(VALUE v)
|
|
|
|
{
|
|
|
|
return rb_float_value_inline(v);
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef rb_float_new
|
|
|
|
VALUE
|
|
|
|
rb_float_new(double d)
|
|
|
|
{
|
|
|
|
return rb_float_new_inline(d);
|
|
|
|
}
|
2020-06-21 00:55:09 +03:00
|
|
|
|
2021-01-02 05:39:07 +03:00
|
|
|
#include "numeric.rbinc"
|