다음을 통해 공유


측정 단위

F#의 부동 소수점 및 부동 소수점 정수 값에는 일반적으로 길이, 볼륨, 질량 등을 나타내는 데 사용되는 연결된 측정 단위가 있을 수 있습니다. 단위가 있는 수량을 사용하면 컴파일러가 산술 관계에 올바른 단위가 있는지 확인할 수 있으므로 프로그래밍 오류를 방지할 수 있습니다.

참고 항목

이러한 예제는 측정 단위를 포함하는 산술 계산의 정확성을 보여 줍니다. FSharp.UMX 프로젝트와 같은 접근 방식을 사용하여 표현 비용이 0인 형식 안전 주석을 다른 형식에 추가하는 데에도 이 기능을 활용할 수 있습니다.

구문

[<Measure>] type unit-name [ = measure ]

설명

이전 구문은 단위 이름을 측정 단위로 정의합니다. 선택적 부분은 이전에 정의된 단위를 기준으로 새 측정값을 정의하는 데 사용됩니다. 예를 들어 다음 줄은 측정값 cm (센티미터)을 정의합니다.

[<Measure>] type cm

다음 줄은 측정값 ml (밀리리터)을 입방 센티미터(cm^3)로 정의합니다.

[<Measure>] type ml = cm^3

이전 구문 에서 측정값 은 단위를 포함하는 수식입니다. 단위를 포함하는 수식에서 정수 계열은 지원되며(양수 및 음수), 단위 사이의 공백은 두 단위의 곱을 나타내고 단위 * 의 곱을 나타내며 / 단위의 몫을 나타냅니다. 상호 단위의 경우 음수 정수 전원을 사용하거나 / 단위 수식의 분자와 분모 간의 구분을 나타내는 값을 사용할 수 있습니다. 분모의 여러 단위는 괄호로 묶어야 합니다. 후 공백 / 으로 구분된 단위는 분모의 일부로 해석되지만 다음 단위 * 는 숫자의 일부로 해석됩니다.

단위 식에서 1을 사용하여 차원 없는 수량을 나타내거나 숫자와 같은 다른 단위와 함께 사용할 수 있습니다. 예를 들어 속도 단위는 초를 나타내는 단위로 1/ss 작성됩니다. 단위 수식에는 괄호가 사용되지 않습니다. 단위 수식에는 숫자 변환 상수를 지정하지 않습니다. 그러나 단위로 변환 상수를 별도로 정의하고 단위 검사 계산에 사용할 수 있습니다.

동일한 것을 의미하는 단위 수식은 다양한 동등한 방법으로 작성할 수 있습니다. 따라서 컴파일러는 단위 수식을 일관된 형식으로 변환하여 음의 힘을 역수로 변환하고, 단위를 단일 숫자 및 분모로 그룹화하고, 숫자 및 분모의 단위를 사전순으로 변환합니다.

예를 들어 단위 수식은 kg m s^-2m /s s * kg 모두 .로 kg m/s^2변환됩니다.

부동 소수점 식에서 측정 단위를 사용합니다. 부동 소수점 숫자를 연결된 측정 단위와 함께 사용하면 다른 수준의 형식 안전성이 추가되며 약한 형식의 부동 소수점 숫자를 사용할 때 수식에서 발생할 수 있는 단위 불일치 오류를 방지할 수 있습니다. 단위를 사용하는 부동 소수점 식을 작성하는 경우 식의 단위가 일치해야 합니다.

다음 예제와 같이 꺾쇠 괄호 안에 단위 수식을 사용하여 리터럴에 주석을 달 수 있습니다.

1.0<cm>
55.0<miles/hour>

숫자와 꺾쇠 괄호 사이에 공백을 두지 않습니다. 그러나 다음 예제와 같이 f리터럴 접미사를 포함할 수 있습니다.

// The f indicates single-precision floating point.
55.0f<miles/hour>

이러한 주석은 리터럴의 형식을 기본 형식(예: float)에서 차원 형식(예: 이 경우float<miles/hour>)으로 float<cm> 변경합니다. 단위 주석은 <1> 차원 없는 수량을 나타내며 해당 형식은 단위 매개 변수가 없는 기본 형식과 동일합니다.

측정 단위의 형식은 부동 소수점 또는 부호 있는 정수 계열 형식과 대괄호로 표시된 추가 단위 주석입니다. 따라서 변환 형식을 (그램)에서 g (킬로그램)으로 kg 작성하면 다음과 같이 형식을 설명합니다.

let convertg2kg (x : float<g>) = x / 1000.0<g/kg>

측정 단위는 컴파일 시간 단위 검사 데 사용되지만 런타임 환경에서는 유지되지 않습니다. 따라서 성능에 영향을 미치지 않습니다.

측정 단위는 부동 소수점 형식뿐만 아니라 모든 형식에 적용할 수 있습니다. 그러나 부동 소수점 형식, 부속 정수 형식 및 10진수 형식만 차원 수량을 지원합니다. 따라서 기본 형식 및 이러한 기본 형식을 포함하는 집계에서 측정 단위만 사용하는 것이 좋습니다.

다음 예제에서는 측정 단위의 사용을 보여 줍니다.

// Mass, grams.
[<Measure>] type g
// Mass, kilograms.
[<Measure>] type kg
// Weight, pounds.
[<Measure>] type lb

// Distance, meters.
[<Measure>] type m
// Distance, cm
[<Measure>] type cm

// Distance, inches.
[<Measure>] type inch
// Distance, feet
[<Measure>] type ft

// Time, seconds.
[<Measure>] type s

// Force, Newtons.
[<Measure>] type N = kg m / s^2

// Pressure, bar.
[<Measure>] type bar
// Pressure, Pascals
[<Measure>] type Pa = N / m^2

// Volume, milliliters.
[<Measure>] type ml
// Volume, liters.
[<Measure>] type L

// Define conversion constants.
let gramsPerKilogram : float<g kg^-1> = 1000.0<g/kg>
let cmPerMeter : float<cm/m> = 100.0<cm/m>
let cmPerInch : float<cm/inch> = 2.54<cm/inch>

let mlPerCubicCentimeter : float<ml/cm^3> = 1.0<ml/cm^3>
let mlPerLiter : float<ml/L> = 1000.0<ml/L>

// Define conversion functions.
let convertGramsToKilograms (x : float<g>) = x / gramsPerKilogram
let convertCentimetersToInches (x : float<cm>) = x / cmPerInch

다음 코드 예제에서는 차원 없는 부동 소수점 숫자에서 차원 부동 소수점 값으로 변환하는 방법을 보여 줍니다. 차원을 1.0에 적용하여 1.0을 곱하기만 하면 됩니다. 이를 다음과 같은 degreesFahrenheit함수로 추상화할 수 있습니다.

또한 차원 없는 부동 소수점 숫자가 예상되는 함수에 차원 값을 전달하는 경우 연산자를 사용하여 float 단위를 취소하거나 캐스팅 float 해야 합니다. 이 예제에서는 차원 없는 수량이 필요하기 때문에 printf 인수로 printf 나눕니다1.0<degC>.

[<Measure>] type degC // temperature, Celsius/Centigrade
[<Measure>] type degF // temperature, Fahrenheit

let convertCtoF ( temp : float<degC> ) = 9.0<degF> / 5.0<degC> * temp + 32.0<degF>
let convertFtoC ( temp: float<degF> ) = 5.0<degC> / 9.0<degF> * ( temp - 32.0<degF>)

// Define conversion functions from dimensionless floating point values.
let degreesFahrenheit temp = temp * 1.0<degF>
let degreesCelsius temp = temp * 1.0<degC>

printfn "Enter a temperature in degrees Fahrenheit."
let input = System.Console.ReadLine()
let parsedOk, floatValue = System.Double.TryParse(input)
if parsedOk
   then
      printfn "That temperature in Celsius is %8.2f degrees C." ((convertFtoC (degreesFahrenheit floatValue))/(1.0<degC>))
   else
      printfn "Error parsing input."

다음 예제 세션은 이 코드의 출력 및 입력을 보여 줍니다.

Enter a temperature in degrees Fahrenheit.
90
That temperature in degrees Celsius is    32.22.

측정 단위를 지원하는 기본 형식

다음 형식 또는 형식 약어 별칭은 측정 단위 주석을 지원합니다.

F# 별칭 CLR 형식
float32/single System.Single
float/double System.Double
decimal System.Decimal
sbyte/int8 System.SByte
int16 System.Int16
int/int32 System.Int32
int64 System.Int64
byte/uint8 System.Byte
uint16 System.UInt16
uint/uint32 System.UInt32
uint64 System.UIn64
nativeint System.IntPtr
unativeint System.UIntPtr

예를 들어 다음과 같이 부호 없는 정수에 주석을 달 수 있습니다.

[<Measure>]
type days

let better_age = 3u<days>

이 기능에 부호 없는 정수 형식을 추가하는 내용은 F# RFC FS-1091설명되어 있습니다.

미리 정의된 측정 단위

단위 라이브러리는 네임스페이스에서 FSharp.Data.UnitSystems.SI 사용할 수 있습니다. 하위 네임스페이스의 기호 형식(예 m : 미터) UnitSymbols 과 하위 네임스페이스의 전체 이름(예: meter 미터)에 UnitNames SI 단위가 모두 포함됩니다.

제네릭 단위 사용

연결된 측정 단위가 있는 데이터에 대해 작동하는 제네릭 함수를 작성할 수 있습니다. 다음 코드 예제와 같이 제네릭 단위와 함께 형식을 형식 매개 변수로 지정하여 이 작업을 수행합니다.

// Distance, meters.
[<Measure>] type m
// Time, seconds.
[<Measure>] type s

let genericSumUnits ( x : float<'u>) (y: float<'u>) = x + y

let v1 = 3.1<m/s>
let v2 = 2.7<m/s>
let x1 = 1.2<m>
let t1 = 1.0<s>

// OK: a function that has unit consistency checking.
let result1 = genericSumUnits v1 v2
// Error reported: mismatched units.
// Uncomment to see error.
// let result2 = genericSumUnits v1 x1

제네릭 단위를 사용하여 컬렉션 형식 만들기

다음 코드에서는 제네릭 단위가 있는 개별 부동 소수점 값으로 구성된 집계 형식을 만드는 방법을 보여 줍니다. 이렇게 하면 다양한 단위로 작동하는 단일 형식을 만들 수 있습니다. 또한 제네릭 단위는 하나의 단위 집합이 있는 제네릭 형식이 다른 단위 집합을 가진 동일한 제네릭 형식과 다른 형식인지 확인하여 형식 안전성을 유지합니다. 이 기술의 기초는 특성이 Measure 형식 매개 변수에 적용될 수 있다는 것입니다.

 // Distance, meters.
[<Measure>] type m
// Time, seconds.
[<Measure>] type s

// Define a vector together with a measure type parameter.
// Note the attribute applied to the type parameter.
type vector3D<[<Measure>] 'u> = { x : float<'u>; y : float<'u>; z : float<'u>}

// Create instances that have two different measures.
// Create a position vector.
let xvec : vector3D<m> = { x = 0.0<m>; y = 0.0<m>; z = 0.0<m> }
// Create a velocity vector.
let v1vec : vector3D<m/s> = { x = 1.0<m/s>; y = -1.0<m/s>; z = 0.0<m/s> }

런타임의 단위

측정 단위는 정적 형식 검사 데 사용됩니다. 부동 소수점 값이 컴파일되면 측정 단위가 제거되므로 런타임에 단위가 손실됩니다. 따라서 런타임에 단위를 검사 따라 달라지는 기능을 구현하려는 시도는 불가능합니다. 예를 들어 단위를 ToString 출력하는 함수를 구현할 수 없습니다.

변환

단위가 있는 형식(예 float<'u>: 단위가 없는 형식)을 변환하려면 표준 변환 함수를 사용할 수 있습니다. 예를 들어 다음 코드와 같이 단위가 없는 값으로 변환 float 하는 데 사용할 float 수 있습니다.

[<Measure>]
type cm
let length = 12.0<cm>
let x = float length

단위 없는 값을 단위가 있는 값으로 변환하려면 적절한 단위로 주석이 추가된 1 또는 1.0 값을 곱할 수 있습니다. 그러나 상호 운용성 계층을 작성하는 경우 단위 없는 값을 단위가 있는 값으로 변환하는 데 사용할 수 있는 몇 가지 명시적 함수도 있습니다. FSharp.Core.LanguagePrimitives 모듈에 있습니다. 예를 들어 다음 코드와 같이 Unitless float 에서 afloat<cm>로 변환하려면 FloatWithMeasure를 사용합니다.

open Microsoft.FSharp.Core
let height:float<cm> = LanguagePrimitives.FloatWithMeasure x

참고 항목