refactor and unify code

This fixes several bugs in both modules.
This commit is contained in:
Joey Hess 2013-07-19 19:39:14 -04:00
parent 442418d845
commit 9c68e06276
3 changed files with 37 additions and 27 deletions

View file

@ -50,6 +50,8 @@ module Utility.DataUnits (
import Data.List import Data.List
import Data.Char import Data.Char
import Utility.HumanNumber
type ByteSize = Integer type ByteSize = Integer
type Name = String type Name = String
type Abbrev = String type Abbrev = String
@ -105,7 +107,7 @@ oldSchoolUnits = zipWith (curry mingle) storageUnits memoryUnits
{- approximate display of a particular number of bytes -} {- approximate display of a particular number of bytes -}
roughSize :: [Unit] -> Bool -> ByteSize -> String roughSize :: [Unit] -> Bool -> ByteSize -> String
roughSize units abbrev i roughSize units short i
| i < 0 = '-' : findUnit units' (negate i) | i < 0 = '-' : findUnit units' (negate i)
| otherwise = findUnit units' i | otherwise = findUnit units' i
where where
@ -116,23 +118,14 @@ roughSize units abbrev i
| otherwise = findUnit us i' | otherwise = findUnit us i'
findUnit [] i' = showUnit i' (last units') -- bytes findUnit [] i' = showUnit i' (last units') -- bytes
showUnit i' (Unit s a n) = let (num, decimal) = chop i' s in showUnit x (Unit size abbrev name) = s ++ " " ++ unit
show num ++ decimal ++ " " ++ where
(if abbrev then a else plural num decimal n) v = (fromInteger x :: Double) / fromInteger size
s = showImprecise 2 v
chop :: Integer -> Integer -> (Integer, String) unit
chop i' d = | short = abbrev
let (num, decimal) = properFraction $ (fromInteger i' :: Double) / fromInteger d | s == "1" = name
dnum = round (decimal * 100) :: Integer | otherwise = name ++ "s"
ds = show dnum
ds' = (take (2 - length ds) (repeat '0')) ++ ds
in if (dnum == 0)
then (num, "")
else (num, "." ++ ds')
plural num decimal n
| num == 1 && null decimal = n
| otherwise = n ++ "s"
{- displays comparison of two sizes -} {- displays comparison of two sizes -}
compareSizes :: [Unit] -> Bool -> ByteSize -> ByteSize -> String compareSizes :: [Unit] -> Bool -> ByteSize -> ByteSize -> String

21
Utility/HumanNumber.hs Normal file
View file

@ -0,0 +1,21 @@
{- numbers for humans
-
- Copyright 2012-2013 Joey Hess <joey@kitenet.net>
-
- Licensed under the GNU GPL version 3 or higher.
-}
module Utility.HumanNumber where
{- Displays a fractional value as a string with a limited number
- of decimal digits. -}
showImprecise :: RealFrac a => Int -> a -> String
showImprecise precision n
| precision == 0 || remainder == 0 = show (round n :: Integer)
| otherwise = show int ++ "." ++ striptrailing0s (pad0s $ show remainder)
where
int :: Integer
(int, frac) = properFraction n
remainder = round (frac * 10 ^ precision) :: Integer
pad0s s = (take (precision - length s) (repeat '0')) ++ s
striptrailing0s = reverse . dropWhile (== '0') . reverse

View file

@ -13,6 +13,8 @@ module Utility.Percentage (
import Data.Ratio import Data.Ratio
import Utility.HumanNumber
newtype Percentage = Percentage (Ratio Integer) newtype Percentage = Percentage (Ratio Integer)
instance Show Percentage where instance Show Percentage where
@ -25,14 +27,8 @@ percentage full have = Percentage $ have * 100 % full
{- Pretty-print a Percentage, with a specified level of precision. -} {- Pretty-print a Percentage, with a specified level of precision. -}
showPercentage :: Int -> Percentage -> String showPercentage :: Int -> Percentage -> String
showPercentage precision (Percentage p) showPercentage precision (Percentage p) = v ++ "%"
| precision == 0 || remainder == 0 = go $ show int
| otherwise = go $ show int ++ "." ++ strip0s (show remainder)
where where
go v = v ++ "%" v = showImprecise precision n
int :: Integer n = fromRational p :: Double
(int, frac) = properFraction (fromRational p)
remainder = floor (frac * multiplier) :: Integer
strip0s = reverse . dropWhile (== '0') . reverse strip0s = reverse . dropWhile (== '0') . reverse
multiplier :: Float
multiplier = 10 ** (fromIntegral precision)