сохранение единиц для расчетов в программировании - PullRequest
6 голосов
/ 01 декабря 2010

Мне было интересно, есть ли какие-нибудь сладкие языки, которые предлагают какую-то абстракцию для "футов" против "дюймов" или "см" и т. Д. Я подумывал сделать что-то вроде следующего в Java:

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

и сможете получить что-то вроде

17,7292 метра в результате.

Один из возможных подходов заключается в том, чтобы при создании нового значения немедленно преобразовать его в «базовую» единицу, например, в метры или что-то еще, чтобы вы могли легко добавлять их.

Тем не менее, я бы предпочел иметь возможность сохранять юниты, чтобы что-то вроде

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

возвращает

723.95555 feet

а не

243.826452 meters - 23.1648 meters = 220.661652 meters

//220.661652 meters to feet returns 723.955551 feet 

Поскольку эта проблема выглядит так, как будто она действительно распространена, существует ли какая-либо платформа или даже язык программирования, который бы справлялся с этим элегантно?

Полагаю, я могу просто добавить единицы измерения такими, какие они есть в моих методах, добавив соответствующие единицы измерения вместе и преобразовав их только в +-*/ [добавить / вычесть / умножить / разделить], когда они запрашиваются, что отлично подходит для добавления и вычитание:

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

//total length is 1.91948 m

если я добавлю это к объекту B со значениями

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

//total length is 2.02032 m

и я получаю новый объект

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

//total length is 3.9398 meters

, что совершенно потрясающе, я могу преобразовать его, когда не хочу никаких проблем. Но такие операции, как умножение не удастся ...

//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.

Так что я действительно хотел показать на этом примере, что

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

И я почти уверен, что это означает, что нужно преобразовать в общую единицу, если они хотят умножить или разделить.

Примером было в основном препятствовать рефлексивному ответу: вы добавляете или вычитаете их по частям перед конвертацией в последний момент, так как * и / завершатся неудачей.

tl; dr: Есть ли какие-нибудь умные способы сохранить единицы в программировании? Есть ли умные способы назвать методы / процедуры так, чтобы мне было легко понять, что я добавляю и вычитаю и т. Д.?

Ответы [ 5 ]

5 голосов
/ 01 декабря 2010

Я точно знаю, что такой язык существует, хотя сам не использовал его.
Он называется Frink .

Он не только позволяет смешивать разныеединицы для того же самого размера, но также работают на нескольких различных физических измерениях. пример вычислений на его сайте очень интересный.Мне особенно нравится Супермен бит.

2 голосов
/ 01 декабря 2010

Многие функциональные языки позволяют создавать типы для такого рода сохранения единиц.В 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)

Теперь каждый блок имеет свой собственный тип, и вы можете выполнять операции только со значениями того же типа:

*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>

Теперь вы можете создать класс типа преобразованиядля преобразования в и из любых типов измерений

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

Теперь мы можем свободно конвертировать между типами:

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

Конечно, пакеты для такого рода вещей доступны в Haskell.

Поскольку вы уже используете Java, возможно, Scala или Clojure предложат аналогичные возможности?

2 голосов
/ 01 декабря 2010

F # имеет языковую поддержку для единиц измерения .

РЕДАКТИРОВАТЬ: См. Также Как работают единицы измерения F #

1 голос
/ 01 декабря 2010
0 голосов
/ 01 декабря 2010

Я проделал большую работу с Юнитами, и нет ничего всеобъемлющего. Вы можете найти много частичных утилит (я думаю, что есть некоторые, распространяемые с UNIX). NIST разрабатывал язык разметки модулей, но готовил его не менее десяти лет.

Чтобы сделать это правильно, нужна онтология, в которой определены единицы измерения и правила конвертации. Вам также придется иметь дело с префиксами.

Если вы придерживаетесь физической науки (единицы СИ), существует 7 (возможно, 8) базовых типов единиц и 22 названных производных количества. Но существует также бесконечное количество способов их объединения. Например, скорость изменения ускорения у некоторых называется «рывком». В принципе, вы можете иметь неограниченное количество производных.

Являются ли единицы валюты? и т.д ...

...