短い答え
整数範囲の場合:
Enumerable#sum
戻り値 (range.max-range.min+1)*(range.max+range.min)/2
Enumerable#inject(:+)
すべての要素を反復します。
理論
1との間の整数の合計はn
、三角数と呼ばれ、と等しくなりn*(n+1)/2
ます。
間の整数の和n
とは、m
三角形の数であり、m
マイナスの三角形の数n-1
に等しい、m*(m+1)/2-n*(n-1)/2
と書くことができます(m-n+1)*(m+n)/2
。
Ruby 2.4のEnumerable#sum
このプロパティはEnumerable#sum
整数範囲で使用されます:
if (RTEST(rb_range_values(obj, &beg, &end, &excl))) {
if (!memo.block_given && !memo.float_value &&
(FIXNUM_P(beg) || RB_TYPE_P(beg, T_BIGNUM)) &&
(FIXNUM_P(end) || RB_TYPE_P(end, T_BIGNUM))) {
return int_range_sum(beg, end, excl, memo.v);
}
}
int_range_sum
このように見えます:
VALUE a;
a = rb_int_plus(rb_int_minus(end, beg), LONG2FIX(1));
a = rb_int_mul(a, rb_int_plus(end, beg));
a = rb_int_idiv(a, LONG2FIX(2));
return rb_int_plus(init, a);
これは次と同等です:
(range.max-range.min+1)*(range.max+range.min)/2
前述の平等!
複雑
この部分について@k_gと@ Hynek-Pichi-Vychodilに感謝します!
和
(1...1000000000000000000000000000000).sum
3つの加算、乗算、減算、除算が必要です。
これは定数の演算ですが、乗算はO((log n)²)なので、 Enumerable#sum
、整数範囲のです。
注入する
(1...1000000000000000000000000000000).inject(:+)
999999999999999999999999999998の追加が必要です!
加算はO(log n)なのでEnumerable#inject
、O(n log n)も同様です。
1E30
入力としてinject
返すことはありませんと。太陽はずっと前に爆発します!
テスト
Ruby整数が追加されているかどうかを確認するのは簡単です。
module AdditionInspector
def +(b)
puts "Calculating #{self}+#{b}"
super
end
end
class Integer
prepend AdditionInspector
end
puts (1..5).sum
#=> 15
puts (1..5).inject(:+)
# Calculating 1+2
# Calculating 3+3
# Calculating 6+4
# Calculating 10+5
#=> 15
確かに、enum.c
コメントから:
Enumerable#sum
methodは、"+"
などのメソッドのメソッド再定義を尊重しない場合がありInteger#+
ます。