2011-01-19 35 views
11

Bir ürünün ortalama net fiyatını hesaplamaya çalışıyorum. Ürün modelimde: total_sold ve: total_net_revenue var. Yöntemde düz bölme yapmak her zaman 0'a neden oluyor gibi görünüyor. Bu sorun olduğunu düşündüğüm gibi BigDecimal kullanmaya başvurdum ... ama aşağıdaki kodun en son yinelenmesiyle, yanıt geldiğinde hala sıfır oluyor ondalık.Ruby on Rails ondalık ile çalışma 3

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

Net gelir Birinin yanlış yapıyorum veya ne yapması gerektiğini işaret edebilir 100 ile bölmek neden olan cent var? İstersen

+2

Neden "BigDecimal"? Bu değerlerin sonuna kadar to_f 'yeterli olmaz mı? –

cevap

13
total_net_revenue/total_sold 

veya

total_net_revenue/total_sold/100.0 

veya
total_net_revenue.to_f/total_sold/100 

Bu üç yöntem

, kesinlik giderek artan miktarda vermek. "Ortalama fiyat" "ortalama fiyat/satış olduğunu unutmayın Eğer bu sırayla bölünme yapmak istiyorum böylece Bu para Öğe başına var

12

İlk:.. Yanlış tarafa bölünüyor

./dolar başına 150 $ = 0,667 ürün

vs

$ 150/100 ürün = $ 1.50 öğe

İkinci başına 100 ürün: diğer la gibi Nüfuslar, denklemdeki sayılardan birini ondalık olması için zorlamanız gerekir, böylece sonuç birer birer olarak çıkar. Geliriniz tam bir sayı olduğu için, bu üç değerin tam sayı olduğu anlamına gelir, yani sonuç olarak tam bir sayı elde edersiniz. Ondalık elde etmek için bunlardan birini kayan noktalı sayı olarak yayınlayın. Başka bir deyişle,

Eğer bunu gerekenleri almak için:

Sen yüzen bütün sent (tamsayı) içinde (ondalık ile sayılar) matematik olacak şekilde olan değerlerinizi dönüştürmek gerekir
price_per_item = (total_net_revenue.to_f/100)/total_sold 
3

bir tam sayı yerine kayan bir sayı ile sonuçlanır.

Yani genel olarak bu gibi işleri:

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

Ne, tamsayılar içinde eksprese olmaz gibi, herhangi bir geri kalanını siler tamsayı bölme, denir yapıyoruz mesela:

1/3 # == 0 

Diğer katılımcıların da belirttiği gibi, bir kayan nokta bölümünü zorlayabilirsiniz. İlk argümanı bir float (1 burada) .to_f ile arayarak zorlamak zorundasınız. İkinci argüman otomatik kayan nokta sayıları taşınmaları sonrasında, sonuç, genel anlamda, tam artık olduğunu yani .:

1.to_f/3 # ~ 0.3333... 

Not bir şamandıra coerced edilecektir. Bu yüzden ~ 0.333 koydu.

Kesin ayrıntılar daha fazla yer almaktadır. Bugünün mikroişlemcilerinde yaygın olan ikili kayan nokta aritmetiğinde, 2'nin gücü hala kesin.Fakat tamsayı 3, örneğin, tam olarak değil, sadece kayan nokta gösteriminin kesinliği içinde (tipik olarak 1E-16 veya "çift" doğruluk için) gösterilir.

Uzun lafın kısası, işte bir başparmak kuralı: Para değerleriyle uğraşıyorsanız, hassaslığın önemli olduğu durumlarda (bir telefon faturasında 1 cent fark var mı?) Hesaplanan sonuçları saklamayın ve değerleri kayan noktalarda depolar. Bunun yerine, tamsayı veya ondalık veri türlerini kullanın (dahili olarak dizeleri depolar). Kayan nokta hesaplamaları, mümkün ise yalnızca görüntüleme ve talep üzerine hesaplanır. Yüzdüklerinde büyük ve küçük değerleri bir araya getirmekten kaçının ve şamandıralardaki zincirleme hesaplamalarından kaçının. Sonuna kadar bölünmeleri önlemek için cebirinizi yeniden işleyin. Ruby ayrıca kesirleri tam olarak temsil eden ve yararlı olabilecek bir Rasyonel veri türünü destekler.

Bu sorunlar, ihtiyaç duyduğunuzda daha fazla bilgi arayabileceğiniz "kayan nokta hatası yayma" bilimi kapsamına girer.

+0

Detay açıklaması için teşekkürler. Genellikle para değerlerini sent olarak saklıyorum ve ondalıklardan kaçınmak için sentlere dayalı hesaplamalar yapıyorum çünkü bu değerleri şimdi ve sonra depolamak zorundayım. – Slick23

+0

Ben de genellikle en iyi işlerini buldum. Bazı taşlar da vardır, ör. para mücevher, bu yaklaşıma biraz kolaylık katıyor. –

0

Değerlerden biri Float olsa bile, sonuç Float olacaktır. Ayrıca, Rails'i ve veri depolarınızı belirli bir modelde kullanıyorsanız, ActiveRecord'un özel yöntemleri vardır ve kendiniz hesaplamanıza gerek yoktur. ( ).