Ruby  3.4.0dev (2024-12-06 revision 892c46283a5ea4179500d951c9d4866c0051f27b)
numeric.h
1 #ifndef INTERNAL_NUMERIC_H /*-*-C-*-vi:se ft=c:*/
2 #define INTERNAL_NUMERIC_H
11 #include "internal/bignum.h" /* for BIGNUM_POSITIVE_P */
12 #include "internal/bits.h" /* for RUBY_BIT_ROTL */
13 #include "internal/fixnum.h" /* for FIXNUM_POSITIVE_P */
14 #include "internal/vm.h" /* for rb_method_basic_definition_p */
15 #include "ruby/intern.h" /* for rb_cmperr */
16 #include "ruby/ruby.h" /* for USE_FLONUM */
17 
18 #define ROUND_TO(mode, even, up, down) \
19  ((mode) == RUBY_NUM_ROUND_HALF_EVEN ? even : \
20  (mode) == RUBY_NUM_ROUND_HALF_UP ? up : down)
21 #define ROUND_FUNC(mode, name) \
22  ROUND_TO(mode, name##_half_even, name##_half_up, name##_half_down)
23 #define ROUND_CALL(mode, name, args) \
24  ROUND_TO(mode, name##_half_even args, \
25  name##_half_up args, name##_half_down args)
26 
27 #ifndef ROUND_DEFAULT
28 # define ROUND_DEFAULT RUBY_NUM_ROUND_HALF_UP
29 #endif
30 
31 enum ruby_num_rounding_mode {
32  RUBY_NUM_ROUND_HALF_UP,
33  RUBY_NUM_ROUND_HALF_EVEN,
34  RUBY_NUM_ROUND_HALF_DOWN,
35  RUBY_NUM_ROUND_DEFAULT = ROUND_DEFAULT,
36 };
37 
38 /* same as internal.h */
39 #define numberof(array) ((int)(sizeof(array) / sizeof((array)[0])))
40 #define roomof(x, y) (((x) + (y) - 1) / (y))
41 #define type_roomof(x, y) roomof(sizeof(x), sizeof(y))
42 
43 #if SIZEOF_DOUBLE <= SIZEOF_VALUE
44 typedef double rb_float_value_type;
45 #else
46 typedef struct {
47  VALUE values[roomof(SIZEOF_DOUBLE, SIZEOF_VALUE)];
48 } rb_float_value_type;
49 #endif
50 
51 struct RFloat {
52  struct RBasic basic;
53  rb_float_value_type float_value;
54 };
55 
56 #define RFLOAT(obj) ((struct RFloat *)(obj))
57 
58 /* numeric.c */
59 int rb_num_to_uint(VALUE val, unsigned int *ret);
60 VALUE ruby_num_interval_step_size(VALUE from, VALUE to, VALUE step, int excl);
61 double ruby_float_step_size(double beg, double end, double unit, int excl);
62 int ruby_float_step(VALUE from, VALUE to, VALUE step, int excl, int allow_endless);
63 int rb_num_negative_p(VALUE);
64 VALUE rb_int_succ(VALUE num);
65 VALUE rb_float_uminus(VALUE num);
66 VALUE rb_int_plus(VALUE x, VALUE y);
67 VALUE rb_float_plus(VALUE x, VALUE y);
68 VALUE rb_int_minus(VALUE x, VALUE y);
69 VALUE rb_float_minus(VALUE x, VALUE y);
70 VALUE rb_int_mul(VALUE x, VALUE y);
71 VALUE rb_float_mul(VALUE x, VALUE y);
72 VALUE rb_float_div(VALUE x, VALUE y);
73 VALUE rb_int_idiv(VALUE x, VALUE y);
74 VALUE rb_int_modulo(VALUE x, VALUE y);
75 VALUE rb_int2str(VALUE num, int base);
76 VALUE rb_fix_plus(VALUE x, VALUE y);
77 VALUE rb_int_gt(VALUE x, VALUE y);
78 VALUE rb_float_gt(VALUE x, VALUE y);
79 VALUE rb_int_ge(VALUE x, VALUE y);
80 enum ruby_num_rounding_mode rb_num_get_rounding_option(VALUE opts);
81 double rb_int_fdiv_double(VALUE x, VALUE y);
82 VALUE rb_int_pow(VALUE x, VALUE y);
83 VALUE rb_float_pow(VALUE x, VALUE y);
84 VALUE rb_int_cmp(VALUE x, VALUE y);
85 VALUE rb_int_equal(VALUE x, VALUE y);
86 VALUE rb_int_divmod(VALUE x, VALUE y);
87 VALUE rb_int_and(VALUE x, VALUE y);
88 VALUE rb_int_lshift(VALUE x, VALUE y);
89 VALUE rb_int_rshift(VALUE x, VALUE y);
90 VALUE rb_int_div(VALUE x, VALUE y);
91 int rb_int_positive_p(VALUE num);
92 int rb_int_negative_p(VALUE num);
93 VALUE rb_check_integer_type(VALUE);
94 VALUE rb_num_pow(VALUE x, VALUE y);
95 VALUE rb_float_ceil(VALUE num, int ndigits);
96 VALUE rb_float_floor(VALUE x, int ndigits);
97 VALUE rb_float_abs(VALUE flt);
98 static inline VALUE rb_num_compare_with_zero(VALUE num, ID mid);
99 static inline int rb_num_positive_int_p(VALUE num);
100 static inline int rb_num_negative_int_p(VALUE num);
101 static inline double rb_float_flonum_value(VALUE v);
102 static inline double rb_float_noflonum_value(VALUE v);
103 static inline double rb_float_value_inline(VALUE v);
104 static inline VALUE rb_float_new_inline(double d);
105 static inline bool INT_POSITIVE_P(VALUE num);
106 static inline bool INT_NEGATIVE_P(VALUE num);
107 static inline bool FLOAT_ZERO_P(VALUE num);
108 #define rb_float_value rb_float_value_inline
109 #define rb_float_new rb_float_new_inline
110 
111 RUBY_SYMBOL_EXPORT_BEGIN
112 /* numeric.c (export) */
113 RUBY_SYMBOL_EXPORT_END
114 
115 VALUE rb_flo_div_flo(VALUE x, VALUE y);
116 double ruby_float_mod(double x, double y);
117 VALUE rb_float_equal(VALUE x, VALUE y);
118 int rb_float_cmp(VALUE x, VALUE y);
119 VALUE rb_float_eql(VALUE x, VALUE y);
120 VALUE rb_fix_aref(VALUE fix, VALUE idx);
121 VALUE rb_int_zero_p(VALUE num);
122 VALUE rb_int_even_p(VALUE num);
123 VALUE rb_int_odd_p(VALUE num);
124 VALUE rb_int_abs(VALUE num);
125 VALUE rb_int_bit_length(VALUE num);
126 VALUE rb_int_uminus(VALUE num);
127 VALUE rb_int_comp(VALUE num);
128 
129 static inline bool
130 INT_POSITIVE_P(VALUE num)
131 {
132  if (FIXNUM_P(num)) {
133  return FIXNUM_POSITIVE_P(num);
134  }
135  else {
136  return BIGNUM_POSITIVE_P(num);
137  }
138 }
139 
140 static inline bool
141 INT_NEGATIVE_P(VALUE num)
142 {
143  if (FIXNUM_P(num)) {
144  return FIXNUM_NEGATIVE_P(num);
145  }
146  else {
147  return BIGNUM_NEGATIVE_P(num);
148  }
149 }
150 
151 static inline bool
152 FLOAT_ZERO_P(VALUE num)
153 {
154  return RFLOAT_VALUE(num) == 0.0;
155 }
156 
157 static inline VALUE
158 rb_num_compare_with_zero(VALUE num, ID mid)
159 {
160  VALUE zero = INT2FIX(0);
161  VALUE r = rb_check_funcall(num, mid, 1, &zero);
162  if (RB_UNDEF_P(r)) {
163  rb_cmperr(num, zero);
164  }
165  return r;
166 }
167 
168 static inline int
169 rb_num_positive_int_p(VALUE num)
170 {
171  const ID mid = '>';
172 
173  if (FIXNUM_P(num)) {
175  return FIXNUM_POSITIVE_P(num);
176  }
177  else if (RB_TYPE_P(num, T_BIGNUM)) {
179  return BIGNUM_POSITIVE_P(num);
180  }
181  return RTEST(rb_num_compare_with_zero(num, mid));
182 }
183 
184 static inline int
185 rb_num_negative_int_p(VALUE num)
186 {
187  const ID mid = '<';
188 
189  if (FIXNUM_P(num)) {
191  return FIXNUM_NEGATIVE_P(num);
192  }
193  else if (RB_TYPE_P(num, T_BIGNUM)) {
195  return BIGNUM_NEGATIVE_P(num);
196  }
197  return RTEST(rb_num_compare_with_zero(num, mid));
198 }
199 
200 static inline double
201 rb_float_flonum_value(VALUE v)
202 {
203 #if USE_FLONUM
204  if (v != (VALUE)0x8000000000000002) { /* LIKELY */
205  union {
206  double d;
207  VALUE v;
208  } t;
209 
210  VALUE b63 = (v >> 63);
211  /* e: xx1... -> 011... */
212  /* xx0... -> 100... */
213  /* ^b63 */
214  t.v = RUBY_BIT_ROTR((2 - b63) | (v & ~(VALUE)0x03), 3);
215  return t.d;
216  }
217 #endif
218  return 0.0;
219 }
220 
221 static inline double
222 rb_float_noflonum_value(VALUE v)
223 {
224 #if SIZEOF_DOUBLE <= SIZEOF_VALUE
225  return RFLOAT(v)->float_value;
226 #else
227  union {
228  rb_float_value_type v;
229  double d;
230  } u = {RFLOAT(v)->float_value};
231  return u.d;
232 #endif
233 }
234 
235 static inline double
236 rb_float_value_inline(VALUE v)
237 {
238  if (FLONUM_P(v)) {
239  return rb_float_flonum_value(v);
240  }
241  return rb_float_noflonum_value(v);
242 }
243 
244 static inline VALUE
245 rb_float_new_inline(double d)
246 {
247 #if USE_FLONUM
248  union {
249  double d;
250  VALUE v;
251  } t;
252  int bits;
253 
254  t.d = d;
255  bits = (int)((VALUE)(t.v >> 60) & 0x7);
256  /* bits contains 3 bits of b62..b60. */
257  /* bits - 3 = */
258  /* b011 -> b000 */
259  /* b100 -> b001 */
260 
261  if (t.v != 0x3000000000000000 /* 1.72723e-77 */ &&
262  !((bits-3) & ~0x01)) {
263  return (RUBY_BIT_ROTL(t.v, 3) & ~(VALUE)0x01) | 0x02;
264  }
265  else if (t.v == (VALUE)0) {
266  /* +0.0 */
267  return 0x8000000000000002;
268  }
269  /* out of range */
270 #endif
271  return rb_float_new_in_heap(d);
272 }
273 
274 #endif /* INTERNAL_NUMERIC_H */
VALUE rb_float_new_in_heap(double d)
Identical to rb_float_new(), except it does not generate Flonums.
Definition: numeric.c:991
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition: double.h:28
#define INT2FIX
Old name of RB_INT2FIX.
Definition: long.h:48
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition: value_type.h:57
#define FLONUM_P
Old name of RB_FLONUM_P.
#define FIXNUM_P
Old name of RB_FIXNUM_P.
VALUE rb_cInteger
Module class.
Definition: numeric.c:198
void rb_cmperr(VALUE a, VALUE b)
Raises "comparison failed" error.
Definition: compar.c:28
int rb_method_basic_definition_p(VALUE klass, ID mid)
Well...
Definition: vm_method.c:2838
VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcallv(), except it returns RUBY_Qundef instead of raising rb_eNoMethodError.
Definition: vm_eval.c:668
static bool RB_UNDEF_P(VALUE obj)
Checks if the given object is undef.
#define RTEST
This is an old name of RB_TEST.
Ruby object's base components.
Definition: rbasic.h:63
Definition: numeric.h:51
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition: value.h:52
#define SIZEOF_VALUE
Identical to sizeof(VALUE), except it is a macro that can also be used inside of preprocessor directi...
Definition: value.h:69
uintptr_t VALUE
Type that represents a Ruby object.
Definition: value.h:40
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition: value_type.h:376