about_Numeric_Literals
about_Numeric_Literals
PowerShell이 숫자 리터럴을 어떻게 쓰고 해석하는지, 그 규칙을 하나씩 풀어보는 문서예요. 정수는 물론 실수, 그리고 값을 곱해주는 접미사까지 다루니, 긴 숫자를 다뤄본 분이라면 특히 도움이 될 거예요.
본문
짧은 설명
이 문서는 PowerShell에서 숫자 값을 다루는 문법과 사용법을 설명해요.
자세한 설명
숫자 리터럴은 정수(integer) 와 실수(real) 두 종류가 있어요. 둘 다 타입 접미사와 배수(multiplier) 접미사를 달 수 있죠.
정수 리터럴
정수 리터럴은 10진수, 16진수, 2진수 세 가지 표기법으로 쓸 수 있어요. 16진수는 0x를, 2진수는 0b를 앞에 붙여서 10진수와 구분해요. 그리고 정수 리터럴에는 타입 접미사와 배수 접미사를 붙일 수 있어요.
| 접미사 | 의미 | 참고 |
|---|---|---|
y |
signed byte 데이터 타입 | PowerShell 6.2에서 추가 |
uy |
unsigned byte 데이터 타입 | PowerShell 6.2에서 추가 |
s |
short 데이터 타입 | PowerShell 6.2에서 추가 |
us |
unsigned short 데이터 타입 | PowerShell 6.2에서 추가 |
l |
long 데이터 타입 | |
u |
unsigned int 또는 long 데이터 타입 | PowerShell 6.2에서 추가 |
ul |
unsigned long 데이터 타입 | PowerShell 6.2에서 추가 |
n |
BigInteger 데이터 타입 | PowerShell 7.0에서 추가 |
kb |
kibibyte (1024¹) 배수 | |
mb |
mebibyte (1024²) 배수 | |
gb |
gigibyte (1024³) 배수 | |
tb |
teribyte (1024⁴) 배수 | |
pb |
petibyte (1024⁵) 배수 |
정수 리터럴의 타입은 값(value) 과 타입 접미사, 숫자 배수 접미사에 따라 결정돼요. 타입 접미사가 없는 정수 리터럴은 이렇게 타입이 정해져요.
- 값이
[int]타입으로 표현 가능하면 그게 타입이에요. - 아니라면
[long]타입으로 표현 가능한지 보는데, 가능하면 그게 타입이죠. - 그것도 아니라면
[decimal]로 표현 가능한지 보고, 가능하면 그게 타입이에요. - 그조차 아니라면
[double]타입으로 표현돼요.
타입 접미사가 있는 정수 리터럴은 이렇게 판단해요.
- 타입 접미사가
u이고 값이[uint]로 표현 가능하면 타입은[uint]예요. - 타입 접미사가
u이고 값이[ulong]으로 표현 가능하면 타입은[ulong]이에요. - 값이 접미사가 가리키는 타입으로 표현 가능하면 그게 타입이 돼요.
- 그 외의 경우에는 그 리터럴은 잘못된(malformed) 리터럴이에요.
실수 리터럴
실수 리터럴은 10진수 표기법으로만 쓸 수 있어요. 소수점 아래에 분수 값을 붙이거나, 지수 부분을 이용한 과학적 표기법도 가능하죠. 지수 부분은 e 다음에 부호(+/-, 선택)와 지수를 나타내는 숫자로 구성돼요. 예를 들어 리터럴 값 1e2는 숫자 값 100과 같아요. 실수 리터럴에도 타입 접미사와 배수 접미사를 붙일 수 있어요.
| 접미사 | 의미 |
|---|---|
d |
decimal 데이터 타입 |
kb |
kibibyte (1024¹) 배수 |
mb |
mebibyte (1024²) 배수 |
gb |
gigibyte (1024³) 배수 |
tb |
teribyte (1024⁴) 배수 |
pb |
petibyte (1024⁵) 배수 |
실수 리터럴에는 double과 decimal 두 종류가 있어요. 이 둘은 decimal 타입 접미사의 유무로 구분해요 — 접미사가 없으면 double, 있으면 decimal이에요. 참고로 PowerShell은 [float] 값의 리터럴 표현은 지원하지 않아요.
- double 실수 리터럴은 타입이
[double]이에요. - decimal 실수 리터럴은 타입이
[decimal]이에요.
decimal 실수 리터럴에서는 분수 부분의 뒤쪽 0이 의미를 가져요. [double] 실수 리터럴에서 지수 부분의 숫자 값이 지원하는 최솟값보다 작으면 그 리터럴의 값은 0이 되고, [decimal] 실수 리터럴에서 지수 부분의 숫자 값이 최솟값보다 작으면 그 리터럴은 잘못된 리터럴이 돼요. 반대로 지수 부분의 숫자 값이 최댓값보다 크면 double이든 decimal이든 잘못된 리터럴로 처리돼요.
참고 — 문법상으로는 double 실수 리터럴에 long 타입 접미사를 붙일 수 있어요. PowerShell은 이 경우를 값이
[long]타입으로 표현되는 정수 리터럴로 취급해요. 이 동작은 이전 버전 PowerShell과의 하위 호환성을 위해 유지된 건데요, 실제 값을 알아보기 어렵게 만들 수 있어서 프로그래머들이 이 형태의 정수 리터럴을 쓰는 건 권장하지 않아요. 예를 들어1.2L은 값이 1이고,1.2345e1L은 12,1.2345e-5L은 0이에요 — 어느 것도 눈에 바로 보이는 값이 아니죠.
숫자 배수(Numeric multipliers)
편의를 위해 정수와 실수 리터럴에는 흔히 쓰는 2의 거듭제곱을 나타내는 숫자 배수를 붙일 수 있어요. 배수는 대문자든 소문자든 아무 조합으로나 쓸 수 있어요. 배수 접미사는 어떤 타입 접미사와도 함께 쓸 수 있지만, 반드시 타입 접미사 뒤에 와야 해요. 예를 들어 100gbL은 잘못된 리터럴이지만 100Lgb는 유효해요.
만약 배수가 접미사가 지정한 숫자 타입으로 표현 가능한 범위를 넘어서는 값을 만들면, 그 리터럴은 잘못된 리터럴이 돼요. 예를 들어 1usgb는 잘못된 리터럴인데요, 그 이유는 1gb 값이 us 접미사가 지정하는 [ushort] 타입이 허용하는 범위보다 크기 때문이에요.
배수 예시
PS> 1kb
1024
PS> 1.30Dmb
1363148.80
PS> 0x10Gb
17179869184
PS> 1.4e23tb
1.5393162788864E+35
PS> 0x12Lpb
20266198323167232
숫자 타입 액셀러레이터(Numeric type accelerators)
PowerShell은 다음과 같은 타입 액셀러레이터를 지원해요.
| 액셀러레이터 | 참고 | 설명 |
|---|---|---|
[byte] |
Byte (unsigned) | |
[sbyte] |
Byte (signed) | |
[int16] |
16-bit integer | |
[short] |
[int16]의 별칭 |
16-bit integer |
[uint16] |
16-bit integer (unsigned) | |
[ushort] |
[uint16]의 별칭 |
16-bit integer (unsigned) |
[int32] |
32-bit integer | |
[int] |
[int32]의 별칭 |
32-bit integer |
[uint32] |
32-bit integer (unsigned) | |
[uint] |
[uint32]의 별칭 |
32-bit integer (unsigned) |
[int64] |
64-bit integer | |
[long] |
[int64]의 별칭 |
64-bit integer |
[uint64] |
64-bit integer (unsigned) | |
[ulong] |
[uint64]의 별칭 |
64-bit integer (unsigned) |
[bigint] |
BigInteger Struct 참고 | |
[single] |
Single precision floating point | |
[float] |
[single]의 별칭 |
Single precision floating point |
[double] |
Double precision floating point | |
[decimal] |
128-bit floating point |
참고 — 다음 타입 액셀러레이터들은 PowerShell 6.2에서 추가됐어요:
[short],[ushort],[uint],[ulong].
예시
다음 표는 숫자 리터럴의 여러 예시와 그 타입, 값을 보여줘요.
| 숫자 | 타입 | 값 |
|---|---|---|
| 100 | Int32 | 100 |
| 100u | UInt32 | 100 |
| 100D | Decimal | 100 |
| 100l | Int64 | 100 |
| 100uL | UInt64 | 100 |
| 100us | UInt16 | 100 |
| 100uy | Byte | 100 |
| 100y | SByte | 100 |
| 1e2 | Double | 100 |
| 1.e2 | Double | 100 |
| 0x1e2 | Int32 | 482 |
| 0x1e2L | Int64 | 482 |
| 0x1e2D | Int32 | 7725 |
| 482D | Decimal | 482 |
| 482gb | Int64 | 517543559168 |
| 482ngb | BigInteger | 517543559168 |
| 0x1e2lgb | Int64 | 517543559168 |
| 0b1011011 | Int32 | 91 |
| 0xFFFFs | Int16 | -1 |
| 0xFFFFFFFF | Int32 | -1 |
| -0xFFFFFFFF | Int32 | 1 |
| 0xFFFFFFFFu | UInt32 | 4294967295 |
2진수·16진수 다루기
지나치게 큰 2진수나 16진수 리터럴은 파싱에 실패하는 대신 [bigint]로 반환될 수 있어요 — 단, n 접미사가 지정된 경우에만 그렇죠. 다만 부호 비트는 [decimal] 범위를 넘어서도 여전히 존중돼요.
- 2진수 문자열의 길이가 8의 배수면, 가장 높은 비트를 부호 비트로 취급해요.
- 길이가 8의 배수인 16진수 문자열에서 첫 자리 숫자가 8 이상이면 그 숫자는 음수로 취급돼요.
2진수·16진수 리터럴에 unsigned 접미사를 지정하면 부호 비트를 무시해요. 예를 들어 0xFFFFFFFF는 -1을 반환하지만, 0xFFFFFFFFu는 [uint]::MaxValue인 4294967295를 반환해요.
PowerShell 7.1부터는 16진수 리터럴에 타입 접미사를 쓰면 그 타입의 부호 있는 값을 반환해요. 예를 들어 PowerShell 7.0에서는 0xFFFFs 표현식이 양수 값이 [int16] 타입에 너무 커서 오류를 반환했는데, PowerShell 7.1에서는 이를 [int16] 타입의 -1로 해석해요. 리터럴 앞에 0을 붙이면 이 동작을 건너뛰고 unsigned로 처리되죠. 예를 들면 0b011111111처럼요. u와 n 접미사는 함께 쓸 수 없어서, [bigint] 범위의 리터럴을 다룰 때 필요할 수 있어요.
- 접두사를 써서 2진수·16진수 리터럴을 부정할 수도 있어요. 부호 비트가 허용되기 때문에 이 경우 양수가 나올 수 있어요. 그리고 BigInteger 접미사가 붙은 숫자에서는 부호 비트가 이렇게 받아들여져요.
- BigInteger 접미사가 붙은 16진수는 길이가 8의 배수인 리터럴의 높은 비트를 부호 비트로 취급해요. 이때 길이는
0x접두사나 어떤 접미사도 포함하지 않아요. - BigInteger 접미사가 붙은 2진수는 96과 128자리에서, 또 그 뒤로 8자리마다 부호 비트를 받아들여요.
숫자 타입 변환
문자열이 숫자로 변환될 때는 추가적인 16진수 형식 표시가 지원돼요. 그 추가 형식들은 리터럴로는 인식되지 않아요.
[int] '0xF' -eq 0xF
[int] '&hF' -eq 0xF
[int] '#F' -eq 0xF
[int] '0b1111' -eq 0b1111
[int] '0b1111' -eq 15
숫자 리터럴처럼 보이는 명령
유효한 숫자 리터럴처럼 보이는 명령은 호출 연산자(&) 로 실행해야 해요. 그렇지 않으면 숫자로 해석되거든요. 문법이 유효한데 잘못된 리터럴(예: 1usgb)은 다음 같은 오류를 만들어요.
PS> 1usgb
At line:1 char:6
+ 1usgb
+ ~
The numeric constant 1usgb is not valid.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : BadNumericConstant
하지만 문법조차 유효하지 않은 잘못된 리터럴(예: 1gbus)은 일반적인 베어 문자열(bare string)로 해석돼요. 그래서 명령이 호출될 수 있는 상황이라면 유효한 명령 이름으로 해석될 수 있어요.
숫자 객체의 속성·메서드 접근하기
숫자 리터럴의 멤버에 접근할 때는 리터럴을 괄호로 감싸야 하는 경우가 있어요. 대체로 이런 경우에요.
- 리터럴에 소수점이 없고
- 소수점 뒤에 숫자가 없고
- 접미사가 없는 경우
예를 들어 다음 예시는 실패해요.
PS> 2.GetType().Name
At line:1 char:11
+ 2.GetType().Name
+ ~
An expression was expected after '('.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : ExpectedExpression
반면 다음 예시들은 잘 동작해요.
PS> 2uL.GetType().Name
UInt64
PS> 1.234.GetType().Name
Double
PS> (2).GetType().Name
Int32
처음 두 예시는 리터럴 값을 괄호로 감싸지 않아도 되는데요, PowerShell 파서가 숫자 리터럴이 끝나는 지점과 GetType 메서드가 시작되는 지점을 알아낼 수 있기 때문이에요.
PowerShell이 숫자 리터럴을 파싱하는 방법
PowerShell v7.0은 새 기능을 지원하기 위해 숫자 리터럴을 파싱하는 방식을 바꿨어요.
실수 리터럴 파싱
리터럴에 소수점이나 e-표기법이 있으면 그 리터럴 문자열은 실수로 파싱돼요.
- decimal 접미사가 있으면 바로
[decimal]로 파싱해요. - 아니라면
[double]로 파싱한 뒤 값에 배수를 적용해요. 그 다음 타입 접미사를 확인하고 적절한 타입으로 캐스팅을 시도해요. - 타입 접미사가 없으면
[double]로 파싱돼요.
정수 리터럴 파싱
정수 타입 리터럴은 다음 단계로 파싱돼요.
- 진법(radix) 형식을 확인해요.
- 2진수 형식이면
[bigint]로 파싱해요. - 16진수 형식이면, 값이
[int]나[long]범위에 있을 때 기존 동작을 유지하도록 특별한 경우를 적용해[bigint]로 파싱해요. - 2진수도 16진수도 아니면 일반적으로
[bigint]로 파싱해요. - 타입 경계를 오버플로 없이 제대로 확인할 수 있도록, 어떤 캐스팅을 시도하기 전에 배수 값을 적용해요.
- 타입 접미사를 확인해요.
- 타입 경계를 확인하고 그 타입으로 파싱을 시도해요.
- 접미사가 없으면 값을 다음 순서로 경계 검사해서, 첫 번째로 통과한 테스트가 숫자의 타입을 결정해요.
[int][long][decimal](10진 리터럴만)[double](10진 리터럴만)
16진수·2진수 숫자에서 값이 [long] 범위를 벗어나면 파싱이 실패해요. 10진 숫자에서 값이 [double] 범위를 벗어나도 파싱이 실패하죠. 더 큰 값은 리터럴을 BigInteger로 파싱하려면 n 접미사를 명시적으로 써야 해요.
큰 값 리터럴 파싱
이전에는 큰 정수 값이 다른 타입으로 캐스팅되기 전에 먼저 double로 파싱됐어요. 그 때문에 큰 값 범위에서 정밀도 손실이 생겼죠. 예를 들면 이런 식이에요.
PS> [bigint]111111111111111111111111111111111111111111111111111111
111111111100905595216014112456735339620444667904
이 문제를 피하려면 예전에는 값을 문자열로 쓴 다음 변환했어야 했어요.
PS> [bigint]'111111111111111111111111111111111111111111111111111111'
111111111111111111111111111111111111111111111111111111
PowerShell 7.0에서는 n 접미사를 쓰면 돼요.
PS> 111111111111111111111111111111111111111111111111111111n
111111111111111111111111111111111111111111111111111111
또한 [ulong]::MaxValue와 [decimal]::MaxValue 사이의 값은 정확도를 유지하기 위해 decimal 접미사 D로 표기해야 해요. 접미사가 없으면 그 값들은 실수 파싱 모드를 사용해 [double]로 파싱돼요.
더 알아보기
- 이 문서의 원문(출처)은 위 링크에서 볼 수 있어요.
- 이 콘텐츠의 소스는 GitHub에서 찾을 수 있고, 이슈나 풀 리퀘스트도 만들고 검토할 수 있어요. 자세한 내용은 기여자 가이드를 참고하세요.
- 제품 피드백은 PowerShell GitHub 이슈로 남겨주세요.