Kısa cevap
Bir tam sayı aralığı için:
Enumerable#sum İadeler (range.max-range.min+1)*(range.max+range.min)/2
Enumerable#inject(:+) her öğeyi yineler.
teori
1 ile arasındaki tam sayıların toplamına üçgen sayın denir ve buna eşittir .n*(n+1)/2
Arasında tamsayı toplamı nve müçgen sayısı meksi üçgen sayısı n-1eşittir, m*(m+1)/2-n*(n-1)/2ve yazılabilir (m-n+1)*(m+n)/2.
Ruby 2.4'te numaralandırılabilir # toplam
Bu özellik, Enumerable#sumtamsayı aralıklarında kullanılır:
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 buna benzer :
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);
bu şuna eşdeğerdir:
(range.max-range.min+1)*(range.max+range.min)/2
söz konusu eşitlik!
karmaşa
Bu bölüm için @k_g ve @ Hynek-Pichi-Vychodil'e çok teşekkürler!
toplam
(1...1000000000000000000000000000000).sum
üç toplama, bir çarpma, bir çıkarma ve bir bölme gerektirir.
Bu sabit bir işlem sayısıdır, ancak çarpma O ((log n) ²), dolayısıyla Enumerable#sumbir tamsayı aralığı için O ((log n) ²).
iğne yapmak
(1...1000000000000000000000000000000).inject(:+)
999999999999999999999999999998 eklemeler gerektirir!
Toplama O (log n), yani Enumerable#injectO (n log n).
İle 1E30, girdi olarak injectasla geri ile. Güneş çok önceden patlayacak!
Ölçek
Ruby Tamsayılarının eklenip eklenmediğini kontrol etmek kolaydır:
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
Nitekim enum.cyorumlardan:
Enumerable#sumyöntem "+"
gibi yöntemlerin yeniden tanımlanmasına saygı duymayabilir Integer#+.