Ruby  3.1.4p223 (2023-03-30 revision HEAD)
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 #if SIZEOF_DOUBLE <= SIZEOF_VALUE
39 typedef double rb_float_value_type;
40 #else
41 typedef struct {
42  VALUE values[(SIZEOF_DOUBLE + SIZEOF_VALUE - 1) / SIZEOF_VALUE];
43  /* roomof() needs internal.h, and the order of some macros may matter */
44 } rb_float_value_type;
45 #endif
46 
47 struct RFloat {
48  struct RBasic basic;
49  rb_float_value_type float_value;
50 };
51 
52 #define RFLOAT(obj) ((struct RFloat *)(obj))
53 
54 /* numeric.c */
55 int rb_num_to_uint(VALUE val, unsigned int *ret);
56 VALUE ruby_num_interval_step_size(VALUE from, VALUE to, VALUE step, int excl);
57 double ruby_float_step_size(double beg, double end, double unit, int excl);
58 int ruby_float_step(VALUE from, VALUE to, VALUE step, int excl, int allow_endless);
59 int rb_num_negative_p(VALUE);
60 VALUE rb_int_succ(VALUE num);
61 VALUE rb_float_uminus(VALUE num);
62 VALUE rb_int_plus(VALUE x, VALUE y);
63 VALUE rb_float_plus(VALUE x, VALUE y);
64 VALUE rb_int_minus(VALUE x, VALUE y);
65 VALUE rb_float_minus(VALUE x, VALUE y);
66 VALUE rb_int_mul(VALUE x, VALUE y);
67 VALUE rb_float_mul(VALUE x, VALUE y);
68 VALUE rb_float_div(VALUE x, VALUE y);
69 VALUE rb_int_idiv(VALUE x, VALUE y);
70 VALUE rb_int_modulo(VALUE x, VALUE y);
71 VALUE rb_int2str(VALUE num, int base);
72 VALUE rb_fix_plus(VALUE x, VALUE y);
73 VALUE rb_int_gt(VALUE x, VALUE y);
74 VALUE rb_float_gt(VALUE x, VALUE y);
75 VALUE rb_int_ge(VALUE x, VALUE y);
76 enum ruby_num_rounding_mode rb_num_get_rounding_option(VALUE opts);
77 double rb_int_fdiv_double(VALUE x, VALUE y);
78 VALUE rb_int_pow(VALUE x, VALUE y);
79 VALUE rb_float_pow(VALUE x, VALUE y);
80 VALUE rb_int_cmp(VALUE x, VALUE y);
81 VALUE rb_int_equal(VALUE x, VALUE y);
82 VALUE rb_int_divmod(VALUE x, VALUE y);
83 VALUE rb_int_and(VALUE x, VALUE y);
84 VALUE rb_int_lshift(VALUE x, VALUE y);
85 VALUE rb_int_div(VALUE x, VALUE y);
86 int rb_int_positive_p(VALUE num);
87 int rb_int_negative_p(VALUE num);
88 VALUE rb_check_integer_type(VALUE);
89 VALUE rb_num_pow(VALUE x, VALUE y);
90 VALUE rb_float_ceil(VALUE num, int ndigits);
91 VALUE rb_float_floor(VALUE x, int ndigits);
92 VALUE rb_float_abs(VALUE flt);
93 static inline VALUE rb_num_compare_with_zero(VALUE num, ID mid);
94 static inline int rb_num_positive_int_p(VALUE num);
95 static inline int rb_num_negative_int_p(VALUE num);
96 static inline double rb_float_flonum_value(VALUE v);
97 static inline double rb_float_noflonum_value(VALUE v);
98 static inline double rb_float_value_inline(VALUE v);
99 static inline VALUE rb_float_new_inline(double d);
100 static inline bool INT_POSITIVE_P(VALUE num);
101 static inline bool INT_NEGATIVE_P(VALUE num);
102 static inline bool FLOAT_ZERO_P(VALUE num);
103 #define rb_float_value rb_float_value_inline
104 #define rb_float_new rb_float_new_inline
105 
106 RUBY_SYMBOL_EXPORT_BEGIN
107 /* numeric.c (export) */
108 RUBY_SYMBOL_EXPORT_END
109 
110 MJIT_SYMBOL_EXPORT_BEGIN
111 VALUE rb_flo_div_flo(VALUE x, VALUE y);
112 double ruby_float_mod(double x, double y);
113 VALUE rb_float_equal(VALUE x, VALUE y);
114 int rb_float_cmp(VALUE x, VALUE y);
115 VALUE rb_float_eql(VALUE x, VALUE y);
116 VALUE rb_fix_aref(VALUE fix, VALUE idx);
117 VALUE rb_int_zero_p(VALUE num);
118 VALUE rb_int_even_p(VALUE num);
119 VALUE rb_int_odd_p(VALUE num);
120 VALUE rb_int_abs(VALUE num);
121 VALUE rb_int_bit_length(VALUE num);
122 VALUE rb_int_uminus(VALUE num);
123 VALUE rb_int_comp(VALUE num);
124 MJIT_SYMBOL_EXPORT_END
125 
126 static inline bool
127 INT_POSITIVE_P(VALUE num)
128 {
129  if (FIXNUM_P(num)) {
130  return FIXNUM_POSITIVE_P(num);
131  }
132  else {
133  return BIGNUM_POSITIVE_P(num);
134  }
135 }
136 
137 static inline bool
138 INT_NEGATIVE_P(VALUE num)
139 {
140  if (FIXNUM_P(num)) {
141  return FIXNUM_NEGATIVE_P(num);
142  }
143  else {
144  return BIGNUM_NEGATIVE_P(num);
145  }
146 }
147 
148 static inline bool
149 FLOAT_ZERO_P(VALUE num)
150 {
151  return RFLOAT_VALUE(num) == 0.0;
152 }
153 
154 static inline VALUE
155 rb_num_compare_with_zero(VALUE num, ID mid)
156 {
157  VALUE zero = INT2FIX(0);
158  VALUE r = rb_check_funcall(num, mid, 1, &zero);
159  if (r == Qundef) {
160  rb_cmperr(num, zero);
161  }
162  return r;
163 }
164 
165 static inline int
166 rb_num_positive_int_p(VALUE num)
167 {
168  const ID mid = '>';
169 
170  if (FIXNUM_P(num)) {
172  return FIXNUM_POSITIVE_P(num);
173  }
174  else if (RB_TYPE_P(num, T_BIGNUM)) {
176  return BIGNUM_POSITIVE_P(num);
177  }
178  return RTEST(rb_num_compare_with_zero(num, mid));
179 }
180 
181 static inline int
182 rb_num_negative_int_p(VALUE num)
183 {
184  const ID mid = '<';
185 
186  if (FIXNUM_P(num)) {
188  return FIXNUM_NEGATIVE_P(num);
189  }
190  else if (RB_TYPE_P(num, T_BIGNUM)) {
192  return BIGNUM_NEGATIVE_P(num);
193  }
194  return RTEST(rb_num_compare_with_zero(num, mid));
195 }
196 
197 static inline double
198 rb_float_flonum_value(VALUE v)
199 {
200 #if USE_FLONUM
201  if (v != (VALUE)0x8000000000000002) { /* LIKELY */
202  union {
203  double d;
204  VALUE v;
205  } t;
206 
207  VALUE b63 = (v >> 63);
208  /* e: xx1... -> 011... */
209  /* xx0... -> 100... */
210  /* ^b63 */
211  t.v = RUBY_BIT_ROTR((2 - b63) | (v & ~(VALUE)0x03), 3);
212  return t.d;
213  }
214 #endif
215  return 0.0;
216 }
217 
218 static inline double
219 rb_float_noflonum_value(VALUE v)
220 {
221 #if SIZEOF_DOUBLE <= SIZEOF_VALUE
222  return RFLOAT(v)->float_value;
223 #else
224  union {
225  rb_float_value_type v;
226  double d;
227  } u = {RFLOAT(v)->float_value};
228  return u.d;
229 #endif
230 }
231 
232 static inline double
233 rb_float_value_inline(VALUE v)
234 {
235  if (FLONUM_P(v)) {
236  return rb_float_flonum_value(v);
237  }
238  return rb_float_noflonum_value(v);
239 }
240 
241 static inline VALUE
242 rb_float_new_inline(double d)
243 {
244 #if USE_FLONUM
245  union {
246  double d;
247  VALUE v;
248  } t;
249  int bits;
250 
251  t.d = d;
252  bits = (int)((VALUE)(t.v >> 60) & 0x7);
253  /* bits contains 3 bits of b62..b60. */
254  /* bits - 3 = */
255  /* b011 -> b000 */
256  /* b100 -> b001 */
257 
258  if (t.v != 0x3000000000000000 /* 1.72723e-77 */ &&
259  !((bits-3) & ~0x01)) {
260  return (RUBY_BIT_ROTL(t.v, 3) & ~(VALUE)0x01) | 0x02;
261  }
262  else if (t.v == (VALUE)0) {
263  /* +0.0 */
264  return 0x8000000000000002;
265  }
266  /* out of range */
267 #endif
268  return rb_float_new_in_heap(d);
269 }
270 
271 #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:1016
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition: double.h:28
#define Qundef
Old name of RUBY_Qundef.
#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:192
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:2643
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:664
#define RTEST
This is an old name of RB_TEST.
Ruby's object's, base components.
Definition: rbasic.h:64
Definition: numeric.h:47
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:375