Leo*_*own 2 ruby ruby-on-rails
对于长数组来说,似乎#sum比#reduce快,而对于短数组,它们基本相同.
def reduce_t(s,f)
start = Time.now
puts (s..f).reduce(:+) #Printing the result just to make sure something is happening.
finish = Time.now
puts finish - start
end
def sum_t(s,f)
start = Time.now
puts (s..f).sum
finish = Time.now
puts finish - start
end
irb(main):078:0> sum_t(1,10); reduce_t(1,10)
55
0.000445
55
0.000195
=> nil
irb(main):079:0> sum_t(1,1000000); reduce_t(1,1000000)
500000500000
8.1e-05
500000500000
0.101487
=> nil
Run Code Online (Sandbox Code Playgroud)
除速度外还有其他考虑因素吗?有没有什么情况下使用#reduce而不是#sum来完成相同的结束,这是一个简单的总和?
编辑
mu太短了正确指出我应该在得出关于时序结果的结论之前进行多次迭代.我没有使用,Benchmark因为我还不熟悉它,但我希望我在下面写的内容足够且令人信服.
def sum_reduce_t(s,f)
time_reduce = 0
time_sum = 0
reduce_faster = 0
sum_faster = 0
30.times do
start_reduce = Time.now
(s..f).reduce(:+)
finish_reduce = Time.now
time_reduce += (finish_reduce - start_reduce)
start_sum = Time.now
(s..f).sum
finish_sum = Time.now
time_sum += (finish_sum - start_sum)
if time_sum > time_reduce
reduce_faster += 1
else
sum_faster += 1
end
end
puts "Total time (s) spent on reduce: #{time_reduce}"
puts "Total time (s) spent on sum: #{time_sum}"
puts "Number of times reduce is faster: #{reduce_faster}"
puts "Number of times sum is faster: #{sum_faster}"
end
irb(main):205:0> sum_reduce_t(1,10)
Total time (s) spent on reduce: 0.00023900000000000004
Total time (s) spent on sum: 0.00015400000000000003
Number of times reduce is faster: 0
Number of times sum is faster: 30
=> nil
irb(main):206:0> sum_reduce_t(1,100)
Total time (s) spent on reduce: 0.0011480000000000004
Total time (s) spent on sum: 0.00024999999999999995
Number of times reduce is faster: 0
Number of times sum is faster: 30
=> nil
irb(main):207:0> sum_reduce_t(1,1000)
Total time (s) spent on reduce: 0.004804000000000001
Total time (s) spent on sum: 0.00019899999999999996
Number of times reduce is faster: 0
Number of times sum is faster: 30
=> nil
irb(main):208:0> sum_reduce_t(1,10000)
Total time (s) spent on reduce: 0.031862
Total time (s) spent on sum: 0.00010299999999999996
Number of times reduce is faster: 0
Number of times sum is faster: 30
=> nil
irb(main):209:0> sum_reduce_t(1,100000)
Total time (s) spent on reduce: 0.286317
Total time (s) spent on sum: 0.00013199999999999998
Number of times reduce is faster: 0
Number of times sum is faster: 30
=> nil
irb(main):210:0> sum_reduce_t(1,1000000)
Total time (s) spent on reduce: 2.7116779999999996
Total time (s) spent on sum: 0.00021200000000000008
Number of times reduce is faster: 0
Number of times sum is faster: 30
=> nil
Run Code Online (Sandbox Code Playgroud)
我的问题仍然存在:是否有时候使用#reduce代替#sum?
好的,我认为这些评论可以结合起来形成一个很好的答案,但如果有人想更深入地解释,我当然会接受其他人。
关键点是:
reduce(:-)、reduce(:*)等),因此不应认为它无用。如果 sum 方法可用,它就不是对巨大数组求和的最佳选择。我的问题的直接答案是:
使用行为和结果sum不同的一种方法inject &:+是在对浮点值求和时.
如果向较小的浮点值添加大浮点值,通常结果与较大的浮点值相同:
> 99999999999999.98 + 0.001
=> 99999999999999.98
Run Code Online (Sandbox Code Playgroud)
添加浮点数时,这可能会导致错误,因为较小的值实际上会丢失,即使它们很多也是如此.
例如:
> a = [99999999999999.98, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001]
=> [99999999999999.98, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001]
> a.inject(&:+)
=> 99999999999999.98
Run Code Online (Sandbox Code Playgroud)
在此示例中,您可以0.001根据需要随时添加,它永远不会更改结果的值.
Ruby的实现sum在求和浮点数时使用Kahan求和算法来减少这个错误:
> a.sum
=> 100000000000000.0
Run Code Online (Sandbox Code Playgroud)
(注意这里的结果,你可能会期待一些结果,.99因为0.001数组中有10个.这只是正常的浮点行为,也许我应该试图找到一个更好的例子.重要的一点是总和确实增加了你添加了很多小的值,这不会发生inject &:+.)
| 归档时间: |
|
| 查看次数: |
1413 次 |
| 最近记录: |