2011-01-19 58 views
11

我试图计算产品的平均净价格。我在我的产品模型中:total_sold和:total_net_revenue。在方法中做直分区似乎总是导致0.我采取了使用BigDecimal,因为我认为这是问题......但随着我最近迭代的代码下面,当答案出来时我仍然是零小数点。在Ruby on Rails 3中使用小数3

def avg_price 
    BigDecimal(total_sold.to_s)/(BigDecimal(total_net_revenue.to_s)/100) 
end 

净营收是美分,这就是为什么我除以100.有人能指出我做错了什么或应该怎么做?

+2

为什么一个`BigDecimal`?这些值的末尾不会`to_f`足够吗? – 2011-01-19 05:17:19

回答

13
total_net_revenue/total_sold 

total_net_revenue/total_sold/100.0 

total_net_revenue.to_f/total_sold/100 

这三种方法给出精确的量增加,如果你想要它。请记住,“平均价格”是“平均价格/销售这钱每个项目,所以你会想要做师在特定的顺序

12

首先:你是将错误的方式

。 100个项目/ $ 150 = 0.667项每美元

$百分之一百五十〇项每项

二= $ 1.50:1像其他LA nguages,您需要强制将等式中的其中一个数字作为小数,以便将结果也作为一个数字进行投射。由于您的收入是一个整数,这意味着所有三个值都是整数,这意味着您得到了一个整数。要获得小数点,请将其中的一个转换为浮点数。

换句话说,得到你所需要的,这样做的:

price_per_item = (total_net_revenue.to_f/100)/total_sold 
3

你需要转换你的价值观是在整个美分(整数),以彩车(有小数位的数字),这样的数学会导致浮动数字而不是整数。

所以一般它的工作原理是这样的:

some_integer.to_f/some_other_integer.to_f # returns a float 
8

你在做什么叫做整数除法,其中丢弃任何剩余部分,因为它不会在整数表达,如:

1/3 # == 0 

正如其他受访者所提到的,您可以强制进行浮点分割。您需要通过调用.to_f强制第一个参数成为float(1)。第二个参数将被自动强制转换为浮动,即:

1.to_f/3 # ~ 0.3333... 

注意,一旦你移动到浮点数,结果,一般来说,不再是准确的。这就是为什么我把〜0.333。

确切的细节更多地涉及。在今天的微处理器中常见的二进制浮点运算中,我相信2的幂数仍然是精确的。但是,例如,整数3不再精确地表示,但仅在浮点表示的精度内(通常为1E-16或其左右的“双精度”)。长话短说,这里有一条经验法则:如果你正在处理的是金钱价值,那么精确度至关重要(曾经有人注意到电话账单上1美分的差异?),不要存储计算结果,并且不要不会以浮点数存储值。而是使用整数或十进制数据类型(内部存储字符串)。如果可能的话,计算浮点结果仅用于显示和按需显示。一旦它们浮动,避免将大和小的值一起添加,并避免在浮动中进行链式计算。重做你的代数,以避免分裂,直到结束。 Ruby还支持一种Rational数据类型,它精确地表示分数,可能会有用。

这些问题属于“浮点错误传播”的科学范畴,如果您需要,您可以在这里查找更多信息。

+0

感谢您的详细解释。我通常将货币价值存储为美分,并基于美分计算以避免小数,因为我确实需要不时存储这些值。 – Slick23 2011-01-19 02:14:05

0

即使其中一个值为Float,结果也将为Float。

另外,如果你在特定的模型中使用Rails和你的数据存储,ActiveRecord有特殊的方法,你不需要自己计算。

Model.average("field_with_data") 

此外还有最小值,最大值,计数,总和方法。