2015-08-23 9 views
10

In einem Programm berechne ich einen Prozentsatz und drucke es für den Benutzer aus. Das Problem besteht darin, dass der gedruckte Prozentsatz mit zu vielen Dezimalstellen angezeigt wird. Ich suchte nach einer Funktion, die dieses Problem anspricht, fand keine und programmierte die Rundungsfunktion unten, aber ich frage mich, ob es stattdessen einen Standard-Weg gibt, dies zu tun. Auch die in this Java topic beschriebene Idee ist ziemlich ordentlich, und wenn es bereits Funktionen gibt, würde ich es gerne wissen.Haskell: Wie kann man einen Prozentsatz von bis zu zwei Dezimalstellen richtig anzeigen?

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" 

Update: Eine vollständigere Version folgt, entwickelt, dank der Antworten, die ich erhalten habe.

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 

Antwort

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

können Sie most format strings C's printf supports verwenden.

Beachten Sie jedoch, dass Haskell printf einige komplexe typeclass Maschinen beteiligt und schwer lesbare Typfehler generieren kann. Es ist auch sehr allgemein gehalten, da es auch IO Aktionen zurückkehren kann, das heißt

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

keine Zeichenfolge zurück, sondern druckt ihn direkt. Ich würde empfehlen, dass Sie nach jedem Aufruf von printf immer eine Typannotation hinzufügen (z. B. :: String), es sei denn, aus dem Kontext ist klar, was der Rückgabetyp ist (z. B. in einem do Block mit anderen E/A-Aktionen).

8

printf ist solide, und eine andere Bibliothek im Wert von etwa ist zu wissen, formatting (was aus der schönen HoleyMonoid Bibliothek basiert):

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

Beachten Sie, dass formatting ist typsicher, im Gegensatz zu 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 
Verwandte Themen