다음을 통해 공유


측정 단위(F#)

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

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

설명

위 구문에서는 unit-name을 측정 단위로 정의합니다. 선택적 요소는 이전에 정의된 단위를 기반으로 새 측정 단위를 정의하는 데 사용됩니다. 예를 들어 다음 줄에서는 측정 단위 cm(센티미터)을 정의합니다.

[<Measure>] type cm

다음 줄에서는 측정 단위 ml(밀리리터)을 입방 센티미터(cm^3)로 정의합니다.

[<Measure>] type ml = cm^3

위 구문에서 measure는 단위와 관련된 수식입니다. 단위 관련 수식에는 정수 거듭제곱(양수 및 음수)이 지원됩니다. 단위 사이의 공백은 두 단위의 곱을 나타내며, * 기호도 단위의 곱을 나타냅니다. / 기호는 단위의 몫을 나타냅니다. 역단위에 대해서는 음의 정수 거듭제곱을 사용하거나 단위 수식의 분자와 분모 사이의 구분을 나타내는 /를 사용할 수 있습니다. 분모의 단위가 여러 개이면 단위를 괄호로 묶어야 합니다. / 뒤에 공백으로 구분한 단위는 분모의 일부인 것으로 해석되지만 * 뒤에 오는 단위는 모두 분자의 일부인 것으로 해석됩니다.

단위 식에 1을 단독으로 사용하여 치수 없는 수량을 나타내거나 분자의 경우와 같이 1을 다른 단위와 함께 사용할 수 있습니다. 예를 들어 속도를 나타내는 단위를 1/s로 작성할 수 있습니다. 여기서 s는 초를 나타냅니다. 단위 수식에 괄호는 사용되지 않습니다. 단위 수식에 숫자 변환 상수는 지정하지 않습니다. 그러나 단위와는 별도로 변환 상수를 정의한 다음 단위 검사 계산에 이를 사용할 수 있습니다.

의미가 같은 단위 수식을 여러 가지 방식으로 작성할 수 있습니다. 따라서 컴파일러에서는 단위 수식을 일관된 형식으로 변환합니다. 예를 들어 음의 거듭제곱은 역수로 변환되고, 여러 단위는 분자 한 개와 분모 한 개로 그룹화되며, 분자와 분모의 단위는 사전순으로 정렬됩니다.

예를 들어 kg m s^-2 및 m /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<cm> 같은 치수 형식으로 변경할 수 있습니다. 이 예제의 경우 변경 후의 형식은 float<miles/hour>입니다. <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 

// 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에 치수 없는 수량이 필요하므로 1.0<degC>로 나눈 값을 printf에 인수로 전달합니다.

[<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 mutable floatValue = 0.
if System.Double.TryParse(input, &floatValue)
   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.

제네릭 단위 사용

관련 측정 단위가 있는 데이터에 대해 실행되는 제네릭 함수를 작성할 수 있습니다. 이를 위해서는 다음 코드 예제에서와 같이 제네릭 단위를 형식 매개 변수로 삼아 형식을 지정하면 됩니다.

// 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 값으로 곱하면 됩니다. 한편 상호 운용성 계층을 작성하는 경우를 위해 단위 없는 값을 단위 있는 값으로 변환하는 데 사용 가능한 명시적 함수도 일부 있습니다. 이러한 함수는 Microsoft.FSharp.Core.LanguagePrimitives 모듈에 있습니다. 예를 들어 단위 없는 float에서 float<cm>으로 변환하려면 다음 코드에 표시된 대로 FloatWithMeasure를 사용합니다.

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

F# Power Pack의 측정 단위

F# PowerPack에서는 단위 라이브러리를 제공합니다. 이 단위 라이브러리에는 SI 단위와 물리적 상수가 포함됩니다.

참고 항목

기타 리소스

F# 언어 참조