Krótka odpowiedź
Dla zakresu liczb całkowitych:
Enumerable#sum
zwroty (range.max-range.min+1)*(range.max+range.min)/2
Enumerable#inject(:+)
iteruje po każdym elemencie.
Teoria
Suma liczb całkowitych między 1 i n
nazywana jest liczbą trójkątną i jest równa n*(n+1)/2
.
Suma liczb całkowitych między n
i m
jest liczbą trójkątną m
minus trójkątna liczba n-1
, która jest równa m*(m+1)/2-n*(n-1)/2
i można ją zapisać (m-n+1)*(m+n)/2
.
Enumerable # sum w Rubim 2.4
Ta właściwość jest używana w Enumerable#sum
zakresach liczb całkowitych:
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
wygląda tak :
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);
co jest równoważne z:
(range.max-range.min+1)*(range.max+range.min)/2
wspomniana równość!
Złożoność
Wielkie dzięki dla @k_g i @ Hynek-Pichi-Vychodil za tę część!
suma
(1...1000000000000000000000000000000).sum
wymaga trzech dodawania, mnożenia, odejmowania i dzielenia.
Jest to stała liczba operacji, ale mnożenie to O ((log n) ²), a więc Enumerable#sum
O ((log n) ²) dla zakresu liczb całkowitych.
wstrzykiwać
(1...1000000000000000000000000000000).inject(:+)
wymaga 999999999999999999999999999998 dodatków!
Dodawanie to O (log n), więc Enumerable#inject
jest O (n log n).
Z 1E30
wejściem, inject
bez powrotu. Słońce już dawno wybuchnie!
Test
Łatwo jest sprawdzić, czy dodawane są liczby całkowite Ruby:
module AdditionInspector
def +(b)
puts "Calculating #{self}+#{b}"
super
end
end
class Integer
prepend AdditionInspector
end
puts (1..5).sum
puts (1..5).inject(:+)
Rzeczywiście, z enum.c
komentarzy:
Enumerable#sum
metoda może nie uwzględniać przedefiniowania "+"
metod, takich jak Integer#+
.
n+1
tylko zakresów? Nie mam zainstalowanej wersji 2.4 lub sam bym przetestował, ale inne Enumerable Objects są obsługiwane przez podstawowe dodawanie tak, jak byłyby w minusieinject(:+)
narzutu symbolu do proc.n, n+1, n+2, .., m
stanowi szereg arytmetyczny, którego suma jest równa(m-n+1)*(m+n)/2
. Podobnie, suma o geometrycznym ,n, (α^1)n, (α^2)n, (α^3)n, ... , (α^m)n
. można obliczyć z wyrażenia w postaci zamkniętej.