about_Numeric_Literals

about_Numeric_Literals

PowerShell이 숫자 리터럴을 어떻게 쓰고 해석하는지, 그 규칙을 하나씩 풀어보는 문서예요. 정수는 물론 실수, 그리고 값을 곱해주는 접미사까지 다루니, 긴 숫자를 다뤄본 분이라면 특히 도움이 될 거예요.

출처: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_numeric_literals

본문

짧은 설명

이 문서는 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처럼요. un 접미사는 함께 쓸 수 없어서, [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]로 파싱돼요.

정수 리터럴 파싱

정수 타입 리터럴은 다음 단계로 파싱돼요.

  1. 진법(radix) 형식을 확인해요.
  2. 2진수 형식이면 [bigint]로 파싱해요.
  3. 16진수 형식이면, 값이 [int][long] 범위에 있을 때 기존 동작을 유지하도록 특별한 경우를 적용해 [bigint]로 파싱해요.
  4. 2진수도 16진수도 아니면 일반적으로 [bigint]로 파싱해요.
  5. 타입 경계를 오버플로 없이 제대로 확인할 수 있도록, 어떤 캐스팅을 시도하기 전에 배수 값을 적용해요.
  6. 타입 접미사를 확인해요.
  7. 타입 경계를 확인하고 그 타입으로 파싱을 시도해요.
  8. 접미사가 없으면 값을 다음 순서로 경계 검사해서, 첫 번째로 통과한 테스트가 숫자의 타입을 결정해요.
    • [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 이슈로 남겨주세요.