Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting from m/s to km/h using F# Units of Measure

I'm in the process of learning F# - and is currently looking into Units of Measure. I have a simple calculation returning meters per second, and I want to introduce a function converting it to kilometres per hour.

My code looks like this:

[<Measure>] type kg
[<Measure>] type s
[<Measure>] type m
[<Measure>] type km
[<Measure>] type h            

let msToKmph(speed : float<m/s>) =
    (float speed) * 3.6<km/h>

let gravityOnEarth = 9.81<m/s^2>
let heightOfJump = 3.5<m>

let speedOfImpact = sqrt (2.0 * gravityOnEarth * heightOfJump)
let speedOfImpactKmh = msToKmph(speedOfImpact)

This works - I get 8.28673639 m/s and 29.832251 km/h. What I am unsure of is if this is the best way to express the relationship between different units. Can this be done more elegantly?

For instance, the line doing (float speed) to remove the unit information from the speed parameter, to make the msToKmph return km/h. If I did not remove unit information before doing the calculation, the returned unit would be: km m/(h s)

like image 567
Jonas Follesø Avatar asked Dec 11 '12 14:12

Jonas Follesø


People also ask

How do we convert m/s to km h?

To convert m/sec into km/hr: Multiply speed in m/s with 3600. Divide the results by 1000. The result is the speed in kilometers per hour.

How do you convert m/s to mph?

To convert a meter per second measurement to a mile per hour measurement, multiply the speed by the conversion ratio. The speed in miles per hour is equal to the meters per second multiplied by 2.236936.

What is the speed of 1 m/sec in km/h in scientific notation?

1 m/s = 3.6 km/h.


2 Answers

First, your msToKmph is totally incorrect. Although it returns a correct return value, what it is actually doing, is it just drops the original <m/s> value by converting to a plain, measureless float and then multiplies the measureless value to a 3.6<km/h>.

To better express the relations between UoM's, consider this:

let kmToM = 1000.0<m/km>  // relation between kilometers and meters
let hrToSec = 3600.0<s/h> // relation between seconds and hours
let msToKmph(speed : float<m/s>) =
    speed / kmToM * hrToSec

Note, all "magic numbers" are encapsulated within UoM converters, hence your formulas remain clean, e.g. they simply operate values and constants, but the UoM are calculated by the compiler.

Update: The philosophy of UoM conversion is that the conversion formulas should be something that has physical sense. The rule of thumb is whether your conversion value presents in reference books. In plain English, 3.6<km/h> from above is useless, but 1000.0<m/km> just says, "there is 1000 m in 1 km", which makes sense.

You can even improve hrToSec like this:

let hrToSec2 = 60.0<s/minute> * 60.0<minute/h>

This will make every value a well-known value found in reference books.

like image 174
bytebuster Avatar answered Nov 15 '22 05:11

bytebuster


You're right that removing unit information is a bad thing. You should create a few constants with appropriate units for conversion.

let mPerKm = 1000.0<m/km>
let secondPerHour = 3600.0<s/h>

// val msToKmph : float<m/s> -> float<km/h>
let msToKmph(speed : float<m/s>) =
    speed / mPerKm * secondPerHour

For km and m, a generic solution is to define a unit prefix k so it works for many UoMs which have kilo as a metric:

[<Measure>] type k

let kilo = 1000.0<1/k>
let secondPerHour = 3600.0<s/h>

// val msToKmph : float<m/s> -> float<k m/h>
let msToKmph(speed : float<m/s>) =
    speed / kilo * secondPerHour
like image 31
pad Avatar answered Nov 15 '22 05:11

pad