Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby方式:捕获除零_Ruby_Refactoring_Divide By Zero - Fatal编程技术网

Ruby方式:捕获除零

Ruby方式:捕获除零,ruby,refactoring,divide-by-zero,Ruby,Refactoring,Divide By Zero,我采用以下方法计算平均值: def compute_average(a,b,c,d,e) total = [a,b,c,d,e].sum.to_f average = [a, 2*b, 3*c, 4*d, 5*e].sum / total average.round(2) end 这没什么特别的,但它有一个问题,我希望所有的平均方程都有:如果输入都为零,它可能被零除 所以,我想这样做: def compute_average(a,b,c,d,e) total = [a,b,c,

我采用以下方法计算平均值:

def compute_average(a,b,c,d,e)
  total = [a,b,c,d,e].sum.to_f
  average = [a, 2*b, 3*c, 4*d, 5*e].sum / total
  average.round(2)
end
这没什么特别的,但它有一个问题,我希望所有的平均方程都有:如果输入都为零,它可能被零除

所以,我想这样做:

def compute_average(a,b,c,d,e)
  total = [a,b,c,d,e].sum.to_f
  if total==0
    average = 0.00
  else
    average = [a, 2*b, 3*c, 4*d, 5*e].sum / total
    average.round(2)
  end
end
。。。这是可行的,但我觉得很尴尬。有没有更优雅的“Ruby方式”来避免这种零除问题

我希望我有一个“除非”接线员,比如

average = numerator / denominator unless denominator == 0 then 0

任何建议?

您可以使用
非零?
,如下所示:

def compute_average(a,b,c,d,e)
  total = [a,b,c,d,e].sum.to_f
  average = [a, 2*b, 3*c, 4*d, 5*e].sum / (total.nonzero? || 1)
end

更多的人会更熟悉使用三元运算符
(total==0?1:total)
,所以这是另一种可能性。

我不太喜欢Ruby ist,但我会这样做:

def compute_average(a,b,c,d,e)
  total = (a+b+c+d+e).to_f
  total.zero? ? 0 : ((a + 2*b + 3*c + 4*d + 5*e) / total).round(2)
end
average = denominator.nonzero? ? numerator/denominator : 0

可能有更好的答案,但这可能就足够了。

/
如果要除法的数字或分母是浮点,则不会返回零除法错误

def compute_average(a,b,c,d,e)
  total = [a,b,c,d,e].sum.to_f
  average = [a, 2*b, 3*c, 4*d, 5*e].sum / total
  average.finite? ? average.round(2) : 0.0
end
更一般地说,根据ruby1.9

def compute_average *args
  average = args.to_enum.with_index.map{|x, w| x * w}.sum / args.sum.to_f
  average.finite? ? average.round(2) : 0.0
end

通常依靠
rescue
捕获异常,然后返回默认值:

def compute_average(a, b, c, d, e)
  total = [a, b, c, d, e].sum.to_f
  average = [ a, 2*b, 3*c, 4*d, 5*e ].sum / total
  average.round(2)
  rescue ZeroDivisionError
    0.0
end
我还要写:

average = numerator / denominator unless denominator == 0 then 0
作为


对我来说,最干净的方式是:

numerator / denominator rescue 0
它还可以避免处理
0/0

正如@Andrew指出的,这只对整数有效。有关更多信息,请参见此答案的注释。

TL;DR:一个可能的解决方案 这可防止出现以下情况:

compute_average(1,2,3,4,5)
=> 3.67

compute_average(0,0,0,0,0)
=> NaN

compute_average(1,2,nil,4,5)
=> 3.08

compute_average(1,2,"string",4,5)
=> 3.08

compute_average(1)
=> 1.0

compute_average([1,2,3,4,5])
=> 3.67

compute_average
=> NaN
compute_average(1,2,3,4,5)
=> 3.0

compute_average(0,0,0,0,0)
=> 0.0

compute_average(1,2,nil,4,5)
=> 3.0

compute_average(1,2,"string",4,5)
=> 3.0

compute_average(1)
=> 1.0

compute_average([1,2,3,4,5])
=> 3.0

compute_average
=> NaN
原始功能: 考虑检查零: 此更改仅针对一种情况提供保护:

compute_average(1,2,3,4,5)
# => 3.67

compute_average(0,0,0,0,0)
# => nil

compute_average(1,2,nil,4,5)
# => TypeError: NilClass can't be coerced into Fixnum

compute_average(1,2,"string",4,5)
# => TypeError: String can't be coerced into Fixnum

compute_average(1)
# => ArgumentError: wrong number of arguments calling `compute_average` (1 for 5)

compute_average([1,2,3,4,5])
# => ArgumentError: wrong number of arguments calling `compute_average` (1 for 5)

compute_average
# => ArgumentError: wrong number of arguments calling `compute_average` (0 for 5)
考虑使用内联<代码>救援<代码> 此更改仅针对一种情况提供保护,并且:

compute_average(1,2,3,4,5)
# => 3.67

compute_average(0,0,0,0,0)
# => NaN

compute_average(1,2,nil,4,5)
# => TypeError: NilClass can't be coerced into Fixnum

compute_average(1,2,"string",4,5)
# => TypeError: String can't be coerced into Fixnum

compute_average(1)
# => ArgumentError: wrong number of arguments calling `compute_average` (1 for 5)

compute_average([1,2,3,4,5])
# => ArgumentError: wrong number of arguments calling `compute_average` (1 for 5)

compute_average
# => ArgumentError: wrong number of arguments calling `compute_average` (0 for 5)
使用内联
救援
还有另一个后果。考虑这个错字:

def compute_average(a,b,c,d,e)
  total = [a,b,c,d,e].sum.to_f
  average = [a, 2*b, 3*c, 4*d, 5*e].smu / total rescue 0
  #                                 ^^^
  average.round(2)
end

compute_average(1,2,3,4,5)
# => 0.0

compute_average(0,0,0,0,0)
# => 0.0
考虑使用<代码>救援<代码> 这样做更好,因为它不会隐藏错误,但可以防止与上面的斜坡
救援
相同的情况

另一个版本,我称之为正常平均计算 作为旁注,我所熟悉的平均操作是使用total/count计算的,所以这里有一个版本可以做到这一点

def compute_average(*values)

  # This makes sure arrays get flattened to a single array.
  values.flatten!

  # Throws away all nil values passed as arguments.
  values.reject!(&:nil?)

  # Throws away all non-numeric values.
  # This includes trashing strings that look like numbers, like "12".
  values.keep_if{ |v| v.is_a? Numeric }

  total = values.sum.to_f
  count = values.count
  return Float::NAN if count.zero?

  total / count
end
这可防止出现以下情况:

compute_average(1,2,3,4,5)
=> 3.67

compute_average(0,0,0,0,0)
=> NaN

compute_average(1,2,nil,4,5)
=> 3.08

compute_average(1,2,"string",4,5)
=> 3.08

compute_average(1)
=> 1.0

compute_average([1,2,3,4,5])
=> 3.67

compute_average
=> NaN
compute_average(1,2,3,4,5)
=> 3.0

compute_average(0,0,0,0,0)
=> 0.0

compute_average(1,2,nil,4,5)
=> 3.0

compute_average(1,2,"string",4,5)
=> 3.0

compute_average(1)
=> 1.0

compute_average([1,2,3,4,5])
=> 3.0

compute_average
=> NaN

虽然这是一个过时的线程,我想我会插话一个简单的一行,你可以使用

@average = variable1 / variable2 rescue 0


是否有
数组#sum
?我没有,这是一个奇怪的平均函数。更正常的平均值(算术/几何)除以元素数,所以它们实际上没有问题,除非你尝试取一个空集的平均值。好的,是的,原因是我用它来计算投票数的平均值,所以a、b、c、d和e是1星、2星、3星、4星和5星投票总数,所以我在计算所有投票的“平均星星数”。是的,我想这是一个有点奇怪的情况。@sawa——这很有趣,我只试过一次,它起了作用,所以我现在用它,当我需要或想要很多括号的时候。我在Ruby 1.9.2上…是的,rails在ActiveSupport中添加了它。尽管
reduce 0,&:+
很容易添加您自己。我喜欢这个方法,也喜欢Jakub的方法,但您的方法将赋值放在前面——我意识到这并不是真正必要的,但我喜欢它,因为它可以帮助我在稍后查看时记住我在做什么。在
compute\u average的情况下,这会给出不同的结果(1,0,0,0,-1)#=>-4
而@Andrew's和我的将在这一点上给出
0
。这有点太微妙了……它依赖于一个事实,即当total为0时分子也为0,这是一个正交事实。三元运算的简单用法似乎更清楚:average=(total.zero:[A,2*b,3*c,4*d,5*e]。sum/total)。round(2)这个函数只有在假设正输入时才正确——考虑到它是在计算星星,这可能是一个合理的假设。这是一个很好的观点——尽管在这种情况下不可能有负输入。谢谢你的提示!三元运算符在这里不是更为惯用吗?是的,双问号在视觉上并不好(你总是忘记写第二个!).但我猜最后你会习惯它。只是检查一下,如果你在后缀中使用rescue,它只会保存当前的表达式?也就是说,这行吗?
a=raise'不是这个“rescue”这个“;a#=>“this”
所以,只是摆弄一下这个,如果你的一个参数是浮点,那么它将不起作用,因为它将返回无穷大,所以这是唯一可行的如果你做的是整数。除法我想你经常会对分数结果感兴趣,所以浮点数很可能是等式的一部分。不过,好主意!我只是在浮点数上使用了这种技术。除法后,它返回NaN,而不是触发rescue。Grrr。如果rescue失败,这是非常低效的触发的次数超过,可能会导致调试困难。(很抱歉删除和推荐。我无意中访问了谷歌搜索URL。)
非零?
在数值类上,因此如果
分母
nil
这仍然会引发错误。如果触发救援次数超过,但至少没有隐藏其他错误,则效率极低。需要注意的是,如果任何参数为nil,函数仍会引发
TypeError:NilClass无法强制非常优雅的解决方案。不要这样做,内联救援是不好的。它们会掩盖该行中发生的每一个错误(考虑
variable1
是一个进行一些计算的方法名),并且很难调试。
def compute_average(a,b,c,d,e)
  total = [a,b,c,d,e].sum.to_f
  average = [a, 2*b, 3*c, 4*d, 5*e].sum / total
  average.round(2)
rescue ZeroDivisionError
  0.0
end
def compute_average(*values)

  # This makes sure arrays get flattened to a single array.
  values.flatten!

  # Throws away all nil values passed as arguments.
  values.reject!(&:nil?)

  # Throws away all non-numeric values.
  # This includes trashing strings that look like numbers, like "12".
  values.keep_if{ |v| v.is_a? Numeric }

  total = values.sum.to_f
  count = values.count
  return Float::NAN if count.zero?

  total / count
end
compute_average(1,2,3,4,5)
=> 3.0

compute_average(0,0,0,0,0)
=> 0.0

compute_average(1,2,nil,4,5)
=> 3.0

compute_average(1,2,"string",4,5)
=> 3.0

compute_average(1)
=> 1.0

compute_average([1,2,3,4,5])
=> 3.0

compute_average
=> NaN
@average = variable1 / variable2 rescue 0