ruby 小數點顯示問題


#1

目前公司設計一個後台是需要計算成本與利潤
但是碰到一個問題
我如果在欄位設計為t.float, 這樣拉出來的數字可以直接相減
例如 20.5 - 10, 但是在前端顯示就會出現20.5.0和10.00,
若我希望小數點後面沒有數字就顯示整數應該如何做呢?

目前只想到一個解法就是讓欄位變成t.string, 然後使用者輸入什麼就顯示什麼(沒輸入小數點就不顯示)
但是在計算的時候,就變成每次都要.to_f 然後再相減

不知道各位大大有沒有比較好的做法


#2
(20.5 - 10).to_i
# => 10

(20.5 - 10).round
# => 11

看是要四捨五入還是無條件捨去,保留欄位為float,前端依你想要的呈現的方式去變化即可


#3

我建議用 int 或 decimal 來解,不過全部都不要有小數點

因為工作的關係我們家的小數點要有"八位",類似 0.00000001 的精度才行,且『完全不允許精確度喪失』

但真正的實作是類似把 9.12345678 存成 912345678,在需要顯示的時候才把數值加上去
而任何數值 input 進來時先用

require 'bigdecimal'
BASE = 100000000 #用這個可以不怕寫 code 少打 0

samount = (BigDecimal.new('9.12345678') * BASE).to_i
#=> 912345678
#處理和儲存都用這個數字

(BigDecimal.new(samount.to_s) / BASE).to_f
#=> 9.12345678
#轉出或顯示時需要才做,不準用此數值進行處理或換算

這樣完全不用怕精確度喪失之類的,且同行大概都和我們相同的做法才是

如果你要問為何這樣做?…試試唄,類似最近有個傢伙問我的問題

if 0.7 * 0.7 == 0.49
  puts "YES"
else
  puts "NO"
end

先不要看答案,然後試試看這個答案唄

puts 0.7 * 0.7

最後再回頭看我所說的,你會懂我的意思的,至於浮點數精確問題是已知的問題了,你可以去到處找看看, Ruby 同 C 語言,所以浮點數會有相同問題就是,以上


#4

讓我想起以前用C++做Eye-tracking時,是為了提高運算速度,所以把浮點數換成整數,做法如出一轍。


#5

float 計算的時候會有 rounding error 的風險.
所以如 JC 大所言, 要用 int 或 decimal 來解.

倒是平常在 ruby or rails 的開發上, 都很習慣先找生態系的工具.
後來在處理錢的存儲與計算, 都會直接使用 money & money-rails.


可以參考看看, 除了符點數問題外, 特別好用是匯率轉換的部分.

另外因他的原理就是用 int 來存儲 cents 與你現有欄位採用 float 比較不同.
這部分 gem 中也有現成的 migrate DSL 可用, 自動幫你建立對應的 column type.