Haskell:如何正确显示最多两位小数的百分比?

时间:2015-08-23 18:43:24

标签: haskell double rounding show

在程序中,我计算一个百分比并将其打印给用户。问题是打印的百分比显示的小数点太多。我搜索了一个解决这个问题的函数,没找到,并编写了下面的舍入函数,但我想知道是否有更标准的方法来代替。此外,this Java topic中描述的想法非常简洁,如果已经有功能这样做,我很想知道。

roundTo :: (Integral int1, Integral int2) => int1 -> Double -> Either int2 Double
roundTo digitsAfterComma value
    | (digitsAfterComma >= 1) =
        let
            factor = fromIntegral (10 ^ digitsAfterComma)
            result = ((/ factor) . fromIntegral . round . (* factor)) value
        in
            Right result
    | (digitsAfterComma == 0) = Left (round value)
    | otherwise = error "minimal precision must be non-negative"

更新:接下来是一个更完整的版本,感谢我收到的一些答案。

import qualified Text.Printf as T

showPercentage :: (Integral a, Show a) => a -> Double -> String
showPercentage digitsAfterComma fraction
    | (digitsAfterComma >= 1) =
        let formatString = "%." ++ (show digitsAfterComma) ++ "f%%"
        in  T.printf formatString percentage

    | (digitsAfterComma == 0) =
        let formatString = "%d%%"
        in  T.printf formatString (round percentage :: Int)

    | otherwise = error "minimal precision must be non-negative"
    where percentage = 100 * fraction

3 个答案:

答案 0 :(得分:11)

> import Text.Printf
> printf "%.2f" 0.22324 :: String
"0.22"

您可以使用most format strings C's printf supports

但请记住,Haskell的printf涉及一些复杂的类型类机制,并且可能会产生难以读取的类型错误。它也很通用,因为它也可以返回IO动作,即

> printf "%.2f" 0.22324 :: IO ()
0.22

不会返回字符串,而是直接打印它。我建议您在每次调用:: String后始终添加类型注释(例如上面的printf),除非从上下文中清楚了什么是返回类型(例如,带有其他IO操作的do块。)

答案 1 :(得分:8)

printf是可靠的,另一个值得了解的库是formatting(基于可爱的HoleyMonoid库):

Prelude Formatting> format ("to two decimal places: " % prec 2 % "!") 0.2222
"to two decimal places: 0.22!"

请注意formatting类型安全,与printf不同:

Prelude Text.Printf Formatting> :t printf "%.2f" "hi"
printf "%.2f" "hi" :: PrintfType t => t
Prelude Text.Printf Formatting> printf "%.2f" "hi"
*** Exception: printf: bad formatting char 'f'

Prelude Text.Printf Formatting> :t format (prec 2) "hi"
-- type error

答案 2 :(得分:1)

这里是显示用于表示百分比的浮点数的功能。它不包含%符号,但是您可以在该符号之前添加。验证数字在0100之间,因为此函数将对1e7这样的数字产生不正确的结果。

showPercent :: Double -> Maybe Text
showPercent d
  | d < 0 = Nothing
  | d > 100 = Nothing
  | otherwise = Just . pack $ f d
  where
    f x = reverse $ case reverse (show x) of
      '0':'.':rest -> rest
      rest         -> rest

结果:

λ showPercent (-5)
Nothing

λ showPercent 0
Just "0"

λ showPercent 5
Just "5"

λ showPercent 10.5
Just "10.5"

λ showPercent 15.765
Just "15.765"

λ showPercent 35.123000000
Just "35.123"

λ showPercent 51.123000321000
Just "51.123000321"

λ showPercent 200
Nothing