From daec5f9edcfbf98b10a4bfc1aa501c9ac2c64841 Mon Sep 17 00:00:00 2001 From: "S.H" Date: Sat, 2 Jan 2021 11:39:07 +0900 Subject: Improve performance some Float methods [Feature #17498] (#4018) --- .document | 2 +- benchmark/float_methods.yml | 14 +++ common.mk | 8 +- inits.c | 2 +- integer.rb | 150 -------------------------------- numeric.c | 54 +----------- numeric.rb | 207 ++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 228 insertions(+), 209 deletions(-) create mode 100644 benchmark/float_methods.yml delete mode 100644 integer.rb create mode 100644 numeric.rb diff --git a/.document b/.document index 8616203552..a3f7571ea7 100644 --- a/.document +++ b/.document @@ -14,7 +14,7 @@ array.rb ast.rb dir.rb gc.rb -integer.rb +numeric.rb io.rb kernel.rb pack.rb diff --git a/benchmark/float_methods.yml b/benchmark/float_methods.yml new file mode 100644 index 0000000000..56ea41effc --- /dev/null +++ b/benchmark/float_methods.yml @@ -0,0 +1,14 @@ +prelude: | + flo = 4.2 +benchmark: + to_f: | + flo.to_f + abs: | + flo.abs + magnitude: | + flo.magnitude + -@: | + -flo + zero?: | + flo.zero? +loop_count: 20000000 diff --git a/common.mk b/common.mk index a692577636..af647a68bb 100644 --- a/common.mk +++ b/common.mk @@ -1020,7 +1020,7 @@ BUILTIN_RB_SRCS = \ $(srcdir)/ast.rb \ $(srcdir)/dir.rb \ $(srcdir)/gc.rb \ - $(srcdir)/integer.rb \ + $(srcdir)/numeric.rb \ $(srcdir)/io.rb \ $(srcdir)/pack.rb \ $(srcdir)/trace_point.rb \ @@ -8224,7 +8224,6 @@ miniinit.$(OBJEXT): {$(VPATH)}encoding.h miniinit.$(OBJEXT): {$(VPATH)}gc.rb miniinit.$(OBJEXT): {$(VPATH)}gem_prelude.rb miniinit.$(OBJEXT): {$(VPATH)}id.h -miniinit.$(OBJEXT): {$(VPATH)}integer.rb miniinit.$(OBJEXT): {$(VPATH)}intern.h miniinit.$(OBJEXT): {$(VPATH)}internal.h miniinit.$(OBJEXT): {$(VPATH)}internal/anyargs.h @@ -8376,6 +8375,7 @@ miniinit.$(OBJEXT): {$(VPATH)}miniinit.c miniinit.$(OBJEXT): {$(VPATH)}miniprelude.c miniinit.$(OBJEXT): {$(VPATH)}missing.h miniinit.$(OBJEXT): {$(VPATH)}node.h +miniinit.$(OBJEXT): {$(VPATH)}numeric.rb miniinit.$(OBJEXT): {$(VPATH)}onigmo.h miniinit.$(OBJEXT): {$(VPATH)}oniguruma.h miniinit.$(OBJEXT): {$(VPATH)}pack.rb @@ -9062,8 +9062,6 @@ numeric.$(OBJEXT): {$(VPATH)}defines.h numeric.$(OBJEXT): {$(VPATH)}encoding.h numeric.$(OBJEXT): {$(VPATH)}id.h numeric.$(OBJEXT): {$(VPATH)}id_table.h -numeric.$(OBJEXT): {$(VPATH)}integer.rb -numeric.$(OBJEXT): {$(VPATH)}integer.rbinc numeric.$(OBJEXT): {$(VPATH)}intern.h numeric.$(OBJEXT): {$(VPATH)}internal.h numeric.$(OBJEXT): {$(VPATH)}internal/anyargs.h @@ -9208,6 +9206,8 @@ numeric.$(OBJEXT): {$(VPATH)}internal/warning_push.h numeric.$(OBJEXT): {$(VPATH)}internal/xmalloc.h numeric.$(OBJEXT): {$(VPATH)}missing.h numeric.$(OBJEXT): {$(VPATH)}numeric.c +numeric.$(OBJEXT): {$(VPATH)}numeric.rb +numeric.$(OBJEXT): {$(VPATH)}numeric.rbinc numeric.$(OBJEXT): {$(VPATH)}onigmo.h numeric.$(OBJEXT): {$(VPATH)}oniguruma.h numeric.$(OBJEXT): {$(VPATH)}ruby_assert.h diff --git a/inits.c b/inits.c index 95c6229dcc..d2c99ed495 100644 --- a/inits.c +++ b/inits.c @@ -87,7 +87,7 @@ rb_call_builtin_inits(void) #define BUILTIN(n) CALL(builtin_##n) BUILTIN(gc); BUILTIN(ractor); - BUILTIN(integer); + BUILTIN(numeric); BUILTIN(io); BUILTIN(dir); BUILTIN(ast); diff --git a/integer.rb b/integer.rb deleted file mode 100644 index d18494f42f..0000000000 --- a/integer.rb +++ /dev/null @@ -1,150 +0,0 @@ -class Integer - # call-seq: - # -int -> integer - # - # Returns +int+, negated. - def -@ - Primitive.attr! 'inline' - Primitive.cexpr! 'rb_int_uminus(self)' - end - - # call-seq: - # ~int -> integer - # - # One's complement: returns a number where each bit is flipped. - # - # Inverts the bits in an Integer. As integers are conceptually of - # infinite length, the result acts as if it had an infinite number of - # one bits to the left. In hex representations, this is displayed - # as two periods to the left of the digits. - # - # sprintf("%X", ~0x1122334455) #=> "..FEEDDCCBBAA" - def ~ - Primitive.attr! 'inline' - Primitive.cexpr! 'rb_int_comp(self)' - end - - def abs - Primitive.attr! 'inline' - Primitive.cexpr! 'rb_int_abs(self)' - end - - # call-seq: - # int.bit_length -> integer - # - # Returns the number of bits of the value of +int+. - # - # "Number of bits" means the bit position of the highest bit - # which is different from the sign bit - # (where the least significant bit has bit position 1). - # If there is no such bit (zero or minus one), zero is returned. - # - # I.e. this method returns ceil(log2(int < 0 ? -int : int+1)). - # - # (-2**1000-1).bit_length #=> 1001 - # (-2**1000).bit_length #=> 1000 - # (-2**1000+1).bit_length #=> 1000 - # (-2**12-1).bit_length #=> 13 - # (-2**12).bit_length #=> 12 - # (-2**12+1).bit_length #=> 12 - # -0x101.bit_length #=> 9 - # -0x100.bit_length #=> 8 - # -0xff.bit_length #=> 8 - # -2.bit_length #=> 1 - # -1.bit_length #=> 0 - # 0.bit_length #=> 0 - # 1.bit_length #=> 1 - # 0xff.bit_length #=> 8 - # 0x100.bit_length #=> 9 - # (2**12-1).bit_length #=> 12 - # (2**12).bit_length #=> 13 - # (2**12+1).bit_length #=> 13 - # (2**1000-1).bit_length #=> 1000 - # (2**1000).bit_length #=> 1001 - # (2**1000+1).bit_length #=> 1001 - # - # This method can be used to detect overflow in Array#pack as follows: - # - # if n.bit_length < 32 - # [n].pack("l") # no overflow - # else - # raise "overflow" - # end - def bit_length - Primitive.attr! 'inline' - Primitive.cexpr! 'rb_int_bit_length(self)' - end - - # call-seq: - # int.even? -> true or false - # - # Returns +true+ if +int+ is an even number. - def even? - Primitive.attr! 'inline' - Primitive.cexpr! 'rb_int_even_p(self)' - end - - # call-seq: - # int.integer? -> true - # - # Since +int+ is already an Integer, this always returns +true+. - def integer? - return true - end - - def magnitude - Primitive.attr! 'inline' - Primitive.cexpr! 'rb_int_abs(self)' - end - - # call-seq: - # int.odd? -> true or false - # - # Returns +true+ if +int+ is an odd number. - def odd? - Primitive.attr! 'inline' - Primitive.cexpr! 'rb_int_odd_p(self)' - end - - # call-seq: - # int.ord -> self - # - # Returns the +int+ itself. - # - # 97.ord #=> 97 - # - # This method is intended for compatibility to character literals - # in Ruby 1.9. - # - # For example, ?a.ord returns 97 both in 1.8 and 1.9. - def ord - return self - end - - # call-seq: - # int.to_i -> integer - # - # Since +int+ is already an Integer, returns +self+. - # - # #to_int is an alias for #to_i. - def to_i - return self - end - - # call-seq: - # int.to_int -> integer - # - # Since +int+ is already an Integer, returns +self+. - def to_int - return self - end - - # call-seq: - # int.zero? -> true or false - # - # Returns +true+ if +int+ has a zero value. - def zero? - Primitive.attr! 'inline' - Primitive.cexpr! 'rb_int_zero_p(self)' - end -end diff --git a/numeric.c b/numeric.c index e4bb4817bb..2ce6f8bfa6 100644 --- a/numeric.c +++ b/numeric.c @@ -1030,13 +1030,6 @@ flo_coerce(VALUE x, VALUE y) return rb_assoc_new(rb_Float(y), x); } -/* - * call-seq: - * -float -> float - * - * Returns +float+, negated. - */ - VALUE rb_float_uminus(VALUE flt) { @@ -1701,33 +1694,6 @@ rb_float_eql(VALUE x, VALUE y) #define flo_eql rb_float_eql -/* - * call-seq: - * float.to_f -> self - * - * Since +float+ is already a Float, returns +self+. - */ - -static VALUE -flo_to_f(VALUE num) -{ - return num; -} - -/* - * call-seq: - * float.abs -> float - * float.magnitude -> float - * - * Returns the absolute value of +float+. - * - * (-34.56).abs #=> 34.56 - * -34.56.abs #=> 34.56 - * 34.56.abs #=> 34.56 - * - * Float#magnitude is an alias for Float#abs. - */ - VALUE rb_float_abs(VALUE flt) { @@ -1735,19 +1701,6 @@ rb_float_abs(VALUE flt) return DBL2NUM(val); } -/* - * call-seq: - * float.zero? -> true or false - * - * Returns +true+ if +float+ is 0.0. - */ - -static VALUE -flo_zero_p(VALUE num) -{ - return flo_iszero(num) ? Qtrue : Qfalse; -} - /* * call-seq: * float.nan? -> true or false @@ -5677,7 +5630,6 @@ Init_Numeric(void) rb_define_method(rb_cFloat, "to_s", flo_to_s, 0); rb_define_alias(rb_cFloat, "inspect", "to_s"); rb_define_method(rb_cFloat, "coerce", flo_coerce, 1); - rb_define_method(rb_cFloat, "-@", rb_float_uminus, 0); rb_define_method(rb_cFloat, "+", rb_float_plus, 1); rb_define_method(rb_cFloat, "-", rb_float_minus, 1); rb_define_method(rb_cFloat, "*", rb_float_mul, 1); @@ -5697,10 +5649,6 @@ Init_Numeric(void) 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); - rb_define_method(rb_cFloat, "to_f", flo_to_f, 0); - rb_define_method(rb_cFloat, "abs", rb_float_abs, 0); - rb_define_method(rb_cFloat, "magnitude", rb_float_abs, 0); - rb_define_method(rb_cFloat, "zero?", flo_zero_p, 0); rb_define_method(rb_cFloat, "to_i", flo_to_i, 0); rb_define_method(rb_cFloat, "to_int", flo_to_i, 0); @@ -5732,4 +5680,4 @@ rb_float_new(double d) return rb_float_new_inline(d); } -#include "integer.rbinc" +#include "numeric.rbinc" diff --git a/numeric.rb b/numeric.rb new file mode 100644 index 0000000000..b8b3a90d75 --- /dev/null +++ b/numeric.rb @@ -0,0 +1,207 @@ +class Integer + # call-seq: + # -int -> integer + # + # Returns +int+, negated. + def -@ + Primitive.attr! 'inline' + Primitive.cexpr! 'rb_int_uminus(self)' + end + + # call-seq: + # ~int -> integer + # + # One's complement: returns a number where each bit is flipped. + # + # Inverts the bits in an Integer. As integers are conceptually of + # infinite length, the result acts as if it had an infinite number of + # one bits to the left. In hex representations, this is displayed + # as two periods to the left of the digits. + # + # sprintf("%X", ~0x1122334455) #=> "..FEEDDCCBBAA" + def ~ + Primitive.attr! 'inline' + Primitive.cexpr! 'rb_int_comp(self)' + end + + def abs + Primitive.attr! 'inline' + Primitive.cexpr! 'rb_int_abs(self)' + end + + # call-seq: + # int.bit_length -> integer + # + # Returns the number of bits of the value of +int+. + # + # "Number of bits" means the bit position of the highest bit + # which is different from the sign bit + # (where the least significant bit has bit position 1). + # If there is no such bit (zero or minus one), zero is returned. + # + # I.e. this method returns ceil(log2(int < 0 ? -int : int+1)). + # + # (-2**1000-1).bit_length #=> 1001 + # (-2**1000).bit_length #=> 1000 + # (-2**1000+1).bit_length #=> 1000 + # (-2**12-1).bit_length #=> 13 + # (-2**12).bit_length #=> 12 + # (-2**12+1).bit_length #=> 12 + # -0x101.bit_length #=> 9 + # -0x100.bit_length #=> 8 + # -0xff.bit_length #=> 8 + # -2.bit_length #=> 1 + # -1.bit_length #=> 0 + # 0.bit_length #=> 0 + # 1.bit_length #=> 1 + # 0xff.bit_length #=> 8 + # 0x100.bit_length #=> 9 + # (2**12-1).bit_length #=> 12 + # (2**12).bit_length #=> 13 + # (2**12+1).bit_length #=> 13 + # (2**1000-1).bit_length #=> 1000 + # (2**1000).bit_length #=> 1001 + # (2**1000+1).bit_length #=> 1001 + # + # This method can be used to detect overflow in Array#pack as follows: + # + # if n.bit_length < 32 + # [n].pack("l") # no overflow + # else + # raise "overflow" + # end + def bit_length + Primitive.attr! 'inline' + Primitive.cexpr! 'rb_int_bit_length(self)' + end + + # call-seq: + # int.even? -> true or false + # + # Returns +true+ if +int+ is an even number. + def even? + Primitive.attr! 'inline' + Primitive.cexpr! 'rb_int_even_p(self)' + end + + # call-seq: + # int.integer? -> true + # + # Since +int+ is already an Integer, this always returns +true+. + def integer? + return true + end + + def magnitude + Primitive.attr! 'inline' + Primitive.cexpr! 'rb_int_abs(self)' + end + + # call-seq: + # int.odd? -> true or false + # + # Returns +true+ if +int+ is an odd number. + def odd? + Primitive.attr! 'inline' + Primitive.cexpr! 'rb_int_odd_p(self)' + end + + # call-seq: + # int.ord -> self + # + # Returns the +int+ itself. + # + # 97.ord #=> 97 + # + # This method is intended for compatibility to character literals + # in Ruby 1.9. + # + # For example, ?a.ord returns 97 both in 1.8 and 1.9. + def ord + return self + end + + # call-seq: + # int.to_i -> integer + # + # Since +int+ is already an Integer, returns +self+. + # + # #to_int is an alias for #to_i. + def to_i + return self + end + + # call-seq: + # int.to_int -> integer + # + # Since +int+ is already an Integer, returns +self+. + def to_int + return self + end + + # call-seq: + # int.zero? -> true or false + # + # Returns +true+ if +int+ has a zero value. + def zero? + Primitive.attr! 'inline' + Primitive.cexpr! 'rb_int_zero_p(self)' + end +end + +class Float + # + # call-seq: + # float.to_f -> self + # + # Since +float+ is already a Float, returns +self+. + # + def to_f + return self + end + + # + # call-seq: + # float.abs -> float + # float.magnitude -> float + # + # Returns the absolute value of +float+. + # + # (-34.56).abs #=> 34.56 + # -34.56.abs #=> 34.56 + # 34.56.abs #=> 34.56 + # + # Float#magnitude is an alias for Float#abs. + # + def abs + Primitive.attr! 'inline' + Primitive.cexpr! 'rb_float_abs(self)' + end + + def magnitude + Primitive.attr! 'inline' + Primitive.cexpr! 'rb_float_abs(self)' + end + + # + # call-seq: + # -float -> float + # + # Returns +float+, negated. + # + def -@ + Primitive.attr! 'inline' + Primitive.cexpr! 'rb_float_uminus(self)' + end + + # + # call-seq: + # float.zero? -> true or false + # + # Returns +true+ if +float+ is 0.0. + # + def zero? + Primitive.attr! 'inline' + Primitive.cexpr! 'flo_iszero(self) ? Qtrue : Qfalse' + end +end -- cgit v1.2.3