2015-08-23 23 views
10

W programie obliczam procent i drukuję go użytkownikowi. Problem polega na tym, że wydrukowany procent jest pokazany ze zbyt dużą liczbą miejsc po przecinku. Szukałem funkcji zajmującej się tym problemem, nie znalazłem ani nie zaprogramowałem funkcji zaokrąglania poniżej, ale zastanawiam się, czy istnieje bardziej standardowy sposób, aby to zrobić. Pomysł opisany w this Java topic jest całkiem czysty, a jeśli już istnieją funkcje do tego, chciałbym to wiedzieć.Haskell: jak prawidłowo wyświetlać wartość procentową do dwóch miejsc po przecinku?

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" 

Aktualizacja: Poniżej znajduje się bardziej kompletna wersja, opracowana dzięki odpowiedziom, które otrzymałem.

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 

Odpowiedz

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

Można użyć most format strings C's printf supports.

Należy jednak pamiętać, że Haskell's printf zawiera skomplikowaną maszynę typu typeclass i może generować błędy typu "trudno odczytać". Jest to również bardzo ogólne, ponieważ może również zwrócić działania IO, tj

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

nie zwraca ciąg ale bezpośrednio drukuje go. Zalecam, aby zawsze dodawać adnotacje typu (takie jak :: String powyżej) po każdym wywołaniu printf, chyba że z kontekstu wynika, jaki jest typ zwracany (np. W bloku do z innymi działaniami IO).

8

printf jest stałe, a inna biblioteka warto wiedzieć jest formatting (która opiera się na piękny HoleyMonoid biblioteki):

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

Zauważ, że formatting jest typu bezpieczne, w przeciwieństwie 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