mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			249 lines
		
	
	
	
		
			6.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			249 lines
		
	
	
	
		
			6.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #ifndef INTERNAL_NUMERIC_H /* -*- C -*- */
 | |
| #define INTERNAL_NUMERIC_H
 | |
| /**
 | |
|  * @file
 | |
|  * @brief      Internal header for Numeric.
 | |
|  * @author     \@shyouhei
 | |
|  * @copyright  This  file  is   a  part  of  the   programming  language  Ruby.
 | |
|  *             Permission  is hereby  granted,  to  either redistribute  and/or
 | |
|  *             modify this file, provided that  the conditions mentioned in the
 | |
|  *             file COPYING are met.  Consult the file for details.
 | |
|  */
 | |
| #include "internal/bignum.h"    /* for BIGNUM_POSITIVE_P */
 | |
| #include "internal/bits.h"      /* for RUBY_BIT_ROTL */
 | |
| #include "internal/fixnum.h"    /* for FIXNUM_POSITIVE_P */
 | |
| #include "internal/vm.h"        /* for rb_method_basic_definition_p */
 | |
| #include "ruby/intern.h"        /* for rb_cmperr */
 | |
| #include "ruby/ruby.h"          /* for USE_FLONUM */
 | |
| 
 | |
| #define ROUND_TO(mode, even, up, down) \
 | |
|     ((mode) == RUBY_NUM_ROUND_HALF_EVEN ? even : \
 | |
|      (mode) == RUBY_NUM_ROUND_HALF_UP ? up : down)
 | |
| #define ROUND_FUNC(mode, name) \
 | |
|     ROUND_TO(mode, name##_half_even, name##_half_up, name##_half_down)
 | |
| #define ROUND_CALL(mode, name, args) \
 | |
|     ROUND_TO(mode, name##_half_even args, \
 | |
|              name##_half_up args, name##_half_down args)
 | |
| 
 | |
| #ifndef ROUND_DEFAULT
 | |
| # define ROUND_DEFAULT RUBY_NUM_ROUND_HALF_UP
 | |
| #endif
 | |
| 
 | |
| enum ruby_num_rounding_mode {
 | |
|     RUBY_NUM_ROUND_HALF_UP,
 | |
|     RUBY_NUM_ROUND_HALF_EVEN,
 | |
|     RUBY_NUM_ROUND_HALF_DOWN,
 | |
|     RUBY_NUM_ROUND_DEFAULT = ROUND_DEFAULT,
 | |
| };
 | |
| 
 | |
| struct RFloat {
 | |
|     struct RBasic basic;
 | |
|     double float_value;
 | |
| };
 | |
| 
 | |
| #define RFLOAT(obj)  (R_CAST(RFloat)(obj))
 | |
| 
 | |
| /* numeric.c */
 | |
| int rb_num_to_uint(VALUE val, unsigned int *ret);
 | |
| VALUE ruby_num_interval_step_size(VALUE from, VALUE to, VALUE step, int excl);
 | |
| double ruby_float_step_size(double beg, double end, double unit, int excl);
 | |
| int ruby_float_step(VALUE from, VALUE to, VALUE step, int excl, int allow_endless);
 | |
| int rb_num_negative_p(VALUE);
 | |
| VALUE rb_int_succ(VALUE num);
 | |
| VALUE rb_int_uminus(VALUE num);
 | |
| VALUE rb_float_uminus(VALUE num);
 | |
| VALUE rb_int_plus(VALUE x, VALUE y);
 | |
| VALUE rb_float_plus(VALUE x, VALUE y);
 | |
| VALUE rb_int_minus(VALUE x, VALUE y);
 | |
| VALUE rb_int_mul(VALUE x, VALUE y);
 | |
| VALUE rb_float_mul(VALUE x, VALUE y);
 | |
| VALUE rb_float_div(VALUE x, VALUE y);
 | |
| VALUE rb_int_idiv(VALUE x, VALUE y);
 | |
| VALUE rb_int_modulo(VALUE x, VALUE y);
 | |
| VALUE rb_int2str(VALUE num, int base);
 | |
| VALUE rb_fix_plus(VALUE x, VALUE y);
 | |
| VALUE rb_int_gt(VALUE x, VALUE y);
 | |
| VALUE rb_float_gt(VALUE x, VALUE y);
 | |
| VALUE rb_int_ge(VALUE x, VALUE y);
 | |
| enum ruby_num_rounding_mode rb_num_get_rounding_option(VALUE opts);
 | |
| double rb_int_fdiv_double(VALUE x, VALUE y);
 | |
| VALUE rb_int_pow(VALUE x, VALUE y);
 | |
| VALUE rb_float_pow(VALUE x, VALUE y);
 | |
| VALUE rb_int_cmp(VALUE x, VALUE y);
 | |
| VALUE rb_int_equal(VALUE x, VALUE y);
 | |
| VALUE rb_int_divmod(VALUE x, VALUE y);
 | |
| VALUE rb_int_and(VALUE x, VALUE y);
 | |
| VALUE rb_int_lshift(VALUE x, VALUE y);
 | |
| VALUE rb_int_div(VALUE x, VALUE y);
 | |
| VALUE rb_int_abs(VALUE num);
 | |
| VALUE rb_int_odd_p(VALUE num);
 | |
| int rb_int_positive_p(VALUE num);
 | |
| int rb_int_negative_p(VALUE num);
 | |
| VALUE rb_num_pow(VALUE x, VALUE y);
 | |
| VALUE rb_float_ceil(VALUE num, int ndigits);
 | |
| VALUE rb_float_abs(VALUE flt);
 | |
| static inline VALUE rb_num_compare_with_zero(VALUE num, ID mid);
 | |
| static inline int rb_num_positive_int_p(VALUE num);
 | |
| static inline int rb_num_negative_int_p(VALUE num);
 | |
| static inline double rb_float_flonum_value(VALUE v);
 | |
| static inline double rb_float_noflonum_value(VALUE v);
 | |
| static inline double rb_float_value_inline(VALUE v);
 | |
| static inline VALUE rb_float_new_inline(double d);
 | |
| static inline bool INT_POSITIVE_P(VALUE num);
 | |
| static inline bool INT_NEGATIVE_P(VALUE num);
 | |
| static inline bool FLOAT_ZERO_P(VALUE num);
 | |
| #define rb_float_value rb_float_value_inline
 | |
| #define rb_float_new   rb_float_new_inline
 | |
| 
 | |
| RUBY_SYMBOL_EXPORT_BEGIN
 | |
| /* numeric.c (export) */
 | |
| VALUE rb_int_positive_pow(long x, unsigned long y);
 | |
| RUBY_SYMBOL_EXPORT_END
 | |
| 
 | |
| MJIT_SYMBOL_EXPORT_BEGIN
 | |
| VALUE rb_flo_div_flo(VALUE x, VALUE y);
 | |
| double ruby_float_mod(double x, double y);
 | |
| VALUE rb_float_equal(VALUE x, VALUE y);
 | |
| int rb_float_cmp(VALUE x, VALUE y);
 | |
| VALUE rb_float_eql(VALUE x, VALUE y);
 | |
| VALUE rb_fix_aref(VALUE fix, VALUE idx);
 | |
| MJIT_SYMBOL_EXPORT_END
 | |
| 
 | |
| static inline bool
 | |
| INT_POSITIVE_P(VALUE num)
 | |
| {
 | |
|     if (FIXNUM_P(num)) {
 | |
|         return FIXNUM_POSITIVE_P(num);
 | |
|     }
 | |
|     else {
 | |
|         return BIGNUM_POSITIVE_P(num);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static inline bool
 | |
| INT_NEGATIVE_P(VALUE num)
 | |
| {
 | |
|     if (FIXNUM_P(num)) {
 | |
|         return FIXNUM_NEGATIVE_P(num);
 | |
|     }
 | |
|     else {
 | |
|         return BIGNUM_NEGATIVE_P(num);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static inline bool
 | |
| FLOAT_ZERO_P(VALUE num)
 | |
| {
 | |
|     return RFLOAT_VALUE(num) == 0.0;
 | |
| }
 | |
| 
 | |
| static inline VALUE
 | |
| rb_num_compare_with_zero(VALUE num, ID mid)
 | |
| {
 | |
|     VALUE zero = INT2FIX(0);
 | |
|     VALUE r = rb_check_funcall(num, mid, 1, &zero);
 | |
|     if (r == Qundef) {
 | |
|         rb_cmperr(num, zero);
 | |
|     }
 | |
|     return r;
 | |
| }
 | |
| 
 | |
| static inline int
 | |
| rb_num_positive_int_p(VALUE num)
 | |
| {
 | |
|     const ID mid = '>';
 | |
| 
 | |
|     if (FIXNUM_P(num)) {
 | |
|         if (rb_method_basic_definition_p(rb_cInteger, mid))
 | |
|             return FIXNUM_POSITIVE_P(num);
 | |
|     }
 | |
|     else if (RB_TYPE_P(num, T_BIGNUM)) {
 | |
|         if (rb_method_basic_definition_p(rb_cInteger, mid))
 | |
|             return BIGNUM_POSITIVE_P(num);
 | |
|     }
 | |
|     return RTEST(rb_num_compare_with_zero(num, mid));
 | |
| }
 | |
| 
 | |
| static inline int
 | |
| rb_num_negative_int_p(VALUE num)
 | |
| {
 | |
|     const ID mid = '<';
 | |
| 
 | |
|     if (FIXNUM_P(num)) {
 | |
|         if (rb_method_basic_definition_p(rb_cInteger, mid))
 | |
|             return FIXNUM_NEGATIVE_P(num);
 | |
|     }
 | |
|     else if (RB_TYPE_P(num, T_BIGNUM)) {
 | |
|         if (rb_method_basic_definition_p(rb_cInteger, mid))
 | |
|             return BIGNUM_NEGATIVE_P(num);
 | |
|     }
 | |
|     return RTEST(rb_num_compare_with_zero(num, mid));
 | |
| }
 | |
| 
 | |
| static inline double
 | |
| rb_float_flonum_value(VALUE v)
 | |
| {
 | |
| #if USE_FLONUM
 | |
|     if (v != (VALUE)0x8000000000000002) { /* LIKELY */
 | |
|         union {
 | |
|             double d;
 | |
|             VALUE v;
 | |
|         } t;
 | |
| 
 | |
|         VALUE b63 = (v >> 63);
 | |
|         /* e: xx1... -> 011... */
 | |
|         /*    xx0... -> 100... */
 | |
|         /*      ^b63           */
 | |
|         t.v = RUBY_BIT_ROTR((2 - b63) | (v & ~(VALUE)0x03), 3);
 | |
|         return t.d;
 | |
|     }
 | |
| #endif
 | |
|     return 0.0;
 | |
| }
 | |
| 
 | |
| static inline double
 | |
| rb_float_noflonum_value(VALUE v)
 | |
| {
 | |
|     return RFLOAT(v)->float_value;
 | |
| }
 | |
| 
 | |
| static inline double
 | |
| rb_float_value_inline(VALUE v)
 | |
| {
 | |
|     if (FLONUM_P(v)) {
 | |
|         return rb_float_flonum_value(v);
 | |
|     }
 | |
|     return rb_float_noflonum_value(v);
 | |
| }
 | |
| 
 | |
| static inline VALUE
 | |
| rb_float_new_inline(double d)
 | |
| {
 | |
| #if USE_FLONUM
 | |
|     union {
 | |
|         double d;
 | |
|         VALUE v;
 | |
|     } t;
 | |
|     int bits;
 | |
| 
 | |
|     t.d = d;
 | |
|     bits = (int)((VALUE)(t.v >> 60) & 0x7);
 | |
|     /* bits contains 3 bits of b62..b60. */
 | |
|     /* bits - 3 = */
 | |
|     /*   b011 -> b000 */
 | |
|     /*   b100 -> b001 */
 | |
| 
 | |
|     if (t.v != 0x3000000000000000 /* 1.72723e-77 */ &&
 | |
|         !((bits-3) & ~0x01)) {
 | |
|         return (RUBY_BIT_ROTL(t.v, 3) & ~(VALUE)0x01) | 0x02;
 | |
|     }
 | |
|     else if (t.v == (VALUE)0) {
 | |
|         /* +0.0 */
 | |
|         return 0x8000000000000002;
 | |
|     }
 | |
|     /* out of range */
 | |
| #endif
 | |
|     return rb_float_new_in_heap(d);
 | |
| }
 | |
| 
 | |
| #endif /* INTERNAL_NUMERIC_H */
 | 
