开发者

preserving units for calculations in programming

开发者 https://www.devze.com 2023-01-28 10:39 出处:网络
I was wondering if there are any sweet languages that offer some sort of abstraction for \"feet\" vs \"inches\" or \"cm\" etc.I was considering doing something like the following in Java:

I was wondering if there are any sweet languages that offer some sort of abstraction for "feet" vs "inches" or "cm" etc. I was considering doing something like the following in Java:

u(56).feet() + u(26).inches()

and be able to get something like

17.7292 meters as the result.

One possible approach is, when making a new value, immediately convert it to a "base" unit, like meters or something, so you can add them easily.

However, I would much ra开发者_如何学Pythonther have the ability to preserve units, so that something like

u(799.95555).feet() - u(76).feet() 

returns

723.95555 feet

and not

243.826452 meters - 23.1648 meters = 220.661652 meters

//220.661652 meters to feet returns 723.955551 feet 

Since this problem seems like it would be really common, is there any framework or even a programming language that exists that handles this elegantly?

I suppose I can just add the units as they are in my methods, adding matching units together and only converting in order to +-*/ [add/subtract/multiply/divide] when they are requested, which is great for adding and subtracting:

//A
{
    this.inches = 36.2;
    this.meters = 1;
}

//total length is 1.91948 m

if I add this to an object B with values

//B
{
    this.inches = 0.8;
    this.meters = 2;
}

//total length is 2.02032 m

and I get a new object that is

{
    this.inches = 37;
    this.meters = 3;
}

//total length is 3.9398 meters

which is totally awesome, I can convert it whenever I want no problem. But operations such as multiplication would fail ...

//A * B = 3.87796383 m^2
{
    this.inches = 28.96;
    this.meters = 2;
}

// ...but multiplying piece-wise and then adding
// gives you 2.01868383 m^2, assuming you make 2m*1m give you 2 m^2.

So all I really wanted to show with that example was that

( A1 + A2 ) * ( Z1 + Z2 ) is not ( A1 * Z1 ) + ( A2 * Z2 )

And I'm pretty sure this means one has to convert to a common unit if they want to multiply or divide.

The example was mostly to discourage the reflexive answer, that you add or subtract them piece-wise before converting at the last moment, since * and / will fail.

tl;dr: Are there any clever ways to preserve units in programming? Are there clever ways to name methods/routines such that it's easy for me to understand what I'm adding and subtracting, etc?


I know for a fact there is such a language, although I haven't used it myself.
It's called Frink.

It not only allows you to mix different units for the same dimension but also operate on several different physical measurements. The sample calculations on its site are a fun read. I particular like the Superman bit.


F# has language support for units of measure.

EDIT: See also How do F# Units of Measure work


Many functional languages allow creating types for this sort of unit preservation. In Haskell:

-- you need GeneralizedNewtypeDeriving to derive Num
newtype Feet = Feet {unFeet :: Float} deriving (Eq, Show, Num)
newtype Meters = Meters {unMeters :: Float} deriving (Eq, Show, Num)

Now each unit is its own type, and you can only perform operations on values of the same type:

*Main> let a1 = 1 :: Feet
*Main> let a2 = 2 :: Feet
*Main> let a3 = 3 :: Meters
*Main> a1+a2
Feet 3.0
*Main> a1+a3

<interactive>:1:3:
    Couldn't match expected type `Feet' against inferred type `Meters'
    In the second argument of `(+)', namely `a3'
    In the expression: a1 + a3
    In the definition of `it': it = a1 + a3
*Main>

Now you can create a conversion type class to convert to and from any measurement types

class LengthMeasure unit where
  untype :: unit -> Float
  toFeet :: unit -> Feet
  toFeet = Feet . (* 3.2808) . untype . toMeters
  toMeters :: unit -> Meters
  toMeters = Meters . (* 0.3048) . untype . toFeet

instance LengthMeasure Feet where
  untype = unFeet
  toFeet = id

instance LengthMeasure Meters where
  untype = unMeters
  toMeters = id

Now we can freely convert between types:

*Main> a1+toFeet a3
Feet {unFeet = 10.842401}

Of course, packages to do this sort of thing are available in Haskell.

Since you're using Java already, maybe Scala or Clojure would offer similar capabilities?


JSR-275 might be relevant http://code.google.com/p/unitsofmeasure/

See Which jsr-275 units implementation should be used?


I have done a lot of work with Units and there isn't anything comprehensive. You can find a lot of partial utilities (I think there are some distributed with UNIXes). NIST was developing a units markup language but it's been at least a decade cooking.

To do this properly needs an ontology in which the units are defined and the rules for conversion. You also have to deal with prefixes.

If you stick with physical science (SI units) there are 7 (possibly 8) base unit-types and 22 named derived quantities. But there are an also infinote number of ways they can be combined. For example the rate of change of acceleration is called "jerk" by some. In principle you could have an indefinite number of derivatives.

Are currencies units? etc...

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号