Câu trả lời ngắn
Đối với một phạm vi số nguyên:
Enumerable#sum
trả lại (range.max-range.min+1)*(range.max+range.min)/2
Enumerable#inject(:+)
lặp đi lặp lại trên mọi yếu tố.
Học thuyết
Tổng các số nguyên giữa 1 và n
được gọi là số tam giác , và bằng n*(n+1)/2
.
Tổng các số nguyên giữa n
và m
là số tam giác m
trừ đi số tam giác của n-1
, bằng m*(m+1)/2-n*(n-1)/2
và có thể được viết (m-n+1)*(m+n)/2
.
Vô số # tổng trong Ruby 2.4
Thuộc tính này được sử dụng trong Enumerable#sum
phạm vi số nguyên:
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
trông như thế này:
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);
tương đương với:
(range.max-range.min+1)*(range.max+range.min)/2
sự bình đẳng nói trên!
Phức tạp
Cảm ơn rất nhiều đến @k_g và @ Hynek-Pichi-Vychodil cho phần này!
Tổng
(1...1000000000000000000000000000000).sum
đòi hỏi ba bổ sung, một phép nhân, một phép con và phép chia.
Đó là một số lượng hoạt động không đổi, nhưng phép nhân là O ((log n) ²), Enumerable#sum
O ((log n) ²) cho một phạm vi số nguyên.
tiêm
(1...1000000000000000000000000000000).inject(:+)
yêu cầu bổ sung 999999999999999999999999999998!
Ngoài ra là O (log n), Enumerable#inject
O (n log n) cũng vậy.
Với 1E30
đầu vào, inject
không bao giờ trở lại. Mặt trời sẽ nổ tung từ lâu!
Kiểm tra
Thật dễ dàng để kiểm tra nếu Ruby Integers đang được thêm vào:
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
Thật vậy, từ enum.c
ý kiến:
Enumerable#sum
phương pháp có thể không tôn trọng định nghĩa lại "+"
phương thức của các phương thức như Integer#+
.