Programming Praxis – Feet And Inches

In today’s Programming Praxis exercise, our goal is to convert a decimal length value to the fractions used by carpenters. Let’s get started, shall we?

Some imports:

import Data.Ratio
import Text.Printf

To get proper rounding we first multiply by 32 and then see how many feet, inches and fractions of an inch there are.

toCarpenter :: RealFrac a => a -> (Int, Int, Ratio Int)
toCarpenter l = (feet, div r 32, mod r 32 % 32) where
    (feet, r) = divMod (round $ l * 32) (32 * 12)

Formatting the text is a unfortunately a tad unwieldy due to the number of special cases.

feetAndInches :: RealFrac a => a -> String
feetAndInches l = case toCarpenter l of
    (0,0,0) -> "0 feet 0 inches"
    (f,i,t) -> showUnit "foot" "feet" (f % 1) ++
               (if f > 0 && (i%1 + t) > 0 then " " else "") ++
               showUnit "inch" "inches" (i % 1 + t)
    where
    showUnit _ _ 0 = ""
    showUnit s m n = printf "%s %s" (showVal n) $ if n <= 1 then s else m
    showVal v | d == 1    = show n
              | v < 1     = printf "%d/%d" n d
              | otherwise = printf "%d and %d/%d" (div n d) (mod n d) d
              where (n,d) = (numerator v, denominator v)

Some tests to see if everything is working properly:

main :: IO ()
main = do print $ feetAndInches 0       == "0 feet 0 inches"
          print $ feetAndInches 0.2785  == "9/32 inch"
          print $ feetAndInches 1.6895  == "1 and 11/16 inches"
          print $ feetAndInches 11.9999 == "1 foot"
          print $ feetAndInches 12.2785 == "1 foot 9/32 inch"
          print $ feetAndInches 71.9999 == "6 feet"
          print $ feetAndInches 72      == "6 feet"
          print $ feetAndInches 72.3492 == "6 feet 11/32 inch"
          print $ feetAndInches 72.9999 == "6 feet 1 inch"
          print $ feetAndInches 73      == "6 feet 1 inch"
          print $ feetAndInches 73.0135 == "6 feet 1 inch"
          print $ feetAndInches 73.0185 == "6 feet 1 and 1/32 inches"
          print $ feetAndInches 73.8218 == "6 feet 1 and 13/16 inches"
About these ads

Tags: , , , , , , , ,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


Follow

Get every new post delivered to your Inbox.

Join 35 other followers

%d bloggers like this: