“9.81 m/s²”에서 숫자와 단위 사이에 있는 공백은 보기 좋으라고 넣은 것이 아닙니다. 국제도량형총회가 펴내는 SI 안내서는 이 공백이 곱셈 기호라고 못 박습니다. 그래서 양은 쪼갤 수 없는 하나의 덩어리이며 줄 끝에서 끊어져서도 안 됩니다. LaTeX에서 이런 규칙 일습을 통째로 떠맡는 것이 siunitx 패키지입니다. 이 페이지에서는 현행 v3의 세 기둥인 \num, \unit, \qty를 따라가면서 단위가 왜 직립체로 조판되는지, 자릿수 구분이 왜 쉼표가 아니라 공백인지, 표의 소수점을 맞추는 S 열은 어떻게 쓰는지, 그리고 오래된 글에 나오는 \SI・\si를 어떻게 바꿔 읽어야 하는지까지 살펴봅니다.
\mathrm{kg}을 손으로 쓰면 안 되는 이유
손으로 쓰면 무너지는 이유는, 지켜야 할 것이 취향이 아니라 국제 규격이고 게다가 세 가지 규칙이 동시에 작용하기 때문입니다. 첫째는 서체입니다. SI 안내서는 단위 기호를 “주위 본문의 서체와 관계없이 직립체로 조판한다”고 정합니다. m, kg, s는 변수가 아니기 때문입니다. 그런데 LaTeX 수식 모드에서는 영문자가 기본적으로 기울어지므로, $9.81 kg$라고 그냥 쓰면 단위가 이탤릭 k와 g의 곱처럼 보입니다. \mathrm{kg}이라고 쓰면 그 한 곳은 고쳐지지만, 논문 한 편에는 그런 곳이 수십 군데 있습니다.
둘째는 공백입니다. SI 안내서 §5.4.3은 “수치는 언제나 단위에 앞서며, 둘을 나누기 위해 언제나 공백을 사용한다”고 정하고, 이어서 이 공백은 곱셈 기호로 간주된다고 설명합니다. 따라서 9.81kg도 9.81 kg도 규격 위반입니다. 규격이 유일하게 인정하는 예외는 평면각의 도·분·초(°, ′, ″)로, 여기서만 공백을 넣지 않습니다. 그래서 30.2 °C(섭씨온도는 공백 있음)와 22.20°(각도는 공백 없음)가 같은 문단 안에 나란히 놓입니다. 한 문서 안에 “° 앞에 공백을 넣는 경우”와 “넣지 않는 경우”가 함께 존재하는 셈인데, 이 구별을 수백 군데에서 손으로 유지하기란 솔직히 무리입니다.
셋째는 “끊어지지 않는다”는 것입니다. 양이 숫자와 단위의 곱인 이상, 줄 끝에 9.81만 남고 다음 줄에 m/s²가 넘어가는 조판은 허용되지 않습니다. siunitx는 기본적으로 이 분할을 금지하며, 꼭 허용하고 싶을 때만 allow-quantity-breaks를 켭니다. 그래서 좁은 단에서 underfull hbox 경고가 나오면 그것은 사고가 아니라 규칙이 지켜지고 있다는 증거입니다. 이 세 가지는 프리앰블에 \usepackage{siunitx} 한 줄을 넣으면 한꺼번에 해결됩니다. 나중에 설정 한 곳만 바꾸면 문서 전체의 표시 방식이 바뀐다는 이점도 따라옵니다.
\usepackage{siunitx}
% by hand: three separate things to remember, every time
$9.81\,\mathrm{m}\,\mathrm{s}^{-2}$
% with siunitx: one command, and the standard is applied for you
\qty{9.81}{\metre\per\second\squared}
\qty{100}{\degreeCelsius} % 100 °C - space kept before the degree
\qty{10}{\percent} % 10 % - space here too
\ang{22.20} % 22.20° - but no space for a plane angle\num — 맨 숫자에 일어나는 일
\num{…}은 숫자만 받아 자리 구분, 지수, 부호, 앞자리 0을 규격에 맞게 정리합니다. \num{12345}는 12 345, \num{1.234e5}는 1.234 × 10⁵, \num{.5}는 0.5가 됩니다. 마지막 것이 은근히 중요합니다. SI 안내서는 “수가 +1과 −1 사이에 있을 때 소수점 앞에는 반드시 0을 둔다”고 정하고 있어, .234가 아니라 0.234라고 써야 하기 때문입니다. 원고에는 .5라고 치고 출력에서 0.5를 얻을 수 있다는 점은 생각보다 손이 많이 덜 갑니다.
자릿수를 쉼표가 아니라 공백으로 나누는 것은 패키지 작성자의 취향이 아닙니다. 1948년 제9차 국제도량형총회 결의 7이 “수는 읽기 쉽도록 세 자리씩 묶을 수 있으며, 묶음과 묶음 사이의 공백에는 점이나 쉼표를 결코 넣지 않는다”고 정했기 때문입니다. 같은 결의는 소수점을 “쉼표(프랑스 관행) 또는 점(영국 관행)”이라고 적고 있는데, 지금 읽으면 제법 정겨운 표현입니다. 규격대로라면 43 279.168 29이고, 규격 위반은 43,279.168,29입니다. siunitx의 group-separator 기본값이 바로 그 얇은 공백 \,입니다.
반대로 입력 쪽은 너그럽습니다. input-decimal-markers의 기본값은 ., 두 글자여서 \num{0,1234}와 \num{0.1234}가 같은 결과를 냅니다. 지수 표시 input-exponent-markers의 기본값은 dDeE 네 글자라, 포트란 냄새가 나는 3.45d-4도 3.45 × 10⁻⁴로 읽힙니다. 실제로는 CSV나 계측기 로그에서 그대로 복사해 온 숫자를 형식을 맞추지 않고 그냥 넣어도 된다는 뜻입니다. \num이 하지 않는 일은 곱셈뿐입니다. v3에서 숫자끼리의 곱은 전용 명령 \numproduct{1.2 x 3.4}(x로 구분)가 맡습니다. 이 분업 역시 규격을 따른 것으로, SI 안내서는 수끼리 곱할 때는 곱셈 기호 ×만 쓰라고 정하고 있습니다.
\num{12345} % 12 345 - grouped with a thin space, never a comma
\num{43279.16829} % 43 279.168 29
\num{1.234e5} % 1.234 x 10^5
\num{3.45d-4} % 3.45 x 10^-4 - Fortran-style d also works
\num{0,1234} % 0.1234 - comma accepted on input
\num{.5} % 0.5 - leading zero supplied
\num{-15673} % -15 673
\numproduct{1.2 x 3.4} % 1.2 x 3.4 - products need their own command소수점은 점인가 쉼표인가 — locale과 output-decimal-marker
둘 다 옳다는 것이 규격의 답입니다. 2003년 제22차 국제도량형총회 결의 10은 소수점을 “행 위의 점 또는 행 위의 쉼표” 가운데 하나로 하고, 선택한 것은 “해당 언어와 문맥에서 관용적으로 쓰이는 쪽이어야 한다”고 정했습니다. 따라서 독일어·프랑스어·스페인어 문서에서 9,81 m/s²로 조판하는 것은, 영어 문서에서 9.81 m/s²로 조판하는 것과 똑같은 자격으로 옳습니다. 어느 한쪽이 “진짜”이고 다른 쪽이 “사투리”인 것이 아닙니다. siunitx의 설계는 이 점에 정직해서, 입력 형식과 출력 형식을 분리해 둡니다.
바꾸는 방법은 두 가지입니다. 세밀하게 지정하려면 출력 소수점은 output-decimal-marker, 자릿수 구분은 group-separator를 따로 설정합니다. 지역 관행을 통째로 바꾸려면 locale 옵션을 쓰며, 패키지에는 UK, US, DE(독일), PL(폴란드), FR(프랑스), SI(슬로베니아), ZA(남아프리카) 설정이 함께 들어 있습니다. 핵심은 원본을 고칠 필요가 없다는 점입니다. \qty[locale = DE]{6.789}{\metre}는 소스에는 점을 그대로 둔 채 6,789 m를 출력합니다. 같은 원고를 영어판과 독일어판으로 나누어 내는 일이 가능해지는 이유가 여기에 있습니다.
패키지에 들어 있지 않은 지역——스페인어권이나 이탈리아어권 등——은 locale로 지정할 수 없으므로 직접 씁니다. \sisetup{output-decimal-marker = {,}} 같은 식입니다. 여기에 빠지기 쉬운 함정이 하나 있습니다. 소수점을 쉼표로 바꾼 뒤 자릿수 구분까지 쉼표로 지정해 버리는 것입니다. group-separator = {,}와 output-decimal-marker = {,}를 함께 쓰면 \num{12345.678}이 12,345,678로 나오고, 어느 쉼표가 소수점인지 독자는 알 수 없습니다. 1948년 결의가 “묶음 사이에는 점도 쉼표도 넣지 않는다”고 굳이 못 박은 이유를 이때 몸으로 알게 됩니다. 자릿수 구분은 기본값인 얇은 공백 그대로 두는 편이 안전합니다.
\qty[locale = DE]{6.789}{\metre} % 6,789 m - source keeps the point
\num[output-decimal-marker = {,}]{1.23} % 1,23
\num[group-separator = {,}]{12345} % 12,345 - US/UK habit, not SI
% document-wide, for a locale siunitx does not ship
\sisetup{output-decimal-marker = {,}} % group-separator stays a thin space
% do NOT do this: the output 12,345,678 is unreadable
% \sisetup{output-decimal-marker = {,}, group-separator = {,}}\unit — 단위를 쓰는 두 가지 방식과 \per
\unit{…}은 단위만 조판하며, 인수를 쓰는 방식은 두 가지입니다. 리터럴 방식은 \unit{kg.m/s^2}처럼 기호를 그대로 치는 것으로, 마침표 .가 단위 사이의 곱, /가 몫, ^가 윗첨자입니다. 매크로 방식은 \unit{\kilo\gram\metre\per\second\squared}처럼 접두사·단위·거듭제곱을 한 낱말씩 조립하는 것으로, 영어로 단위 이름을 읽어 내려가는 느낌에 가깝습니다. 실무의 갈림길은 분명합니다. 그때그때 급히 쓰는 단위라면 리터럴, 나중에 문서 전체의 표시 방식을 한꺼번에 바꾸고 싶다면 매크로를 고릅니다. 옵션이 듣는 쪽은 매크로 방식이기 때문입니다.
| 매크로 | 의미 | 출력 |
|---|---|---|
\gram | 기본 단위 매크로. \metre \second \ampere \kelvin \mole \candela도 마찬가지 | g |
\kilo | 접두사. 단독으로는 쓸 수 없고 반드시 단위가 뒤따름 | k |
\kilogram | 접두사가 붙은 단위를 한 낱말로. \kilo\gram과 같은 결과 | kg |
\per | 뒤에 오는 단위를 분모로 보냄: \joule\per\mole | J mol⁻¹ |
\squared | 직전 단위를 제곱(후치). 세제곱은 \cubed | m² |
\square | 직후 단위를 제곱(전치). 세제곱은 \cubic | m² |
\degreeCelsius | 섭씨온도. 규격대로 앞에 공백이 들어감 | °C |
\percent | 백분율. SI가 인정하는 기호이며 역시 앞에 공백이 들어감 | % |
\per의 모양은 per-mode 옵션이 결정합니다. 오래된 해설 글이 가장 자주 틀리는 지점이 여기인데, 기본값은 음의 거듭제곱입니다. \unit{\metre\per\second\squared}는 m/s²가 아니라 m s⁻²로 나오고, \unit{\kilo\gram\per\cubic\metre}도 kg/m³가 아니라 kg m⁻³입니다. 슬래시로 하려면 per-mode = symbol, 세로로 쌓은 분수로 하려면 per-mode = fraction을 지정합니다. 프리앰블에 \sisetup{per-mode = symbol}을 한 번 써 두면 문서 안의 모든 단위가 그 방침을 따릅니다.
슬래시를 골랐을 때 siunitx는 조용히 괄호를 넣어 줍니다. SI 안내서 §5.4.6이 “슬래시로 나눌 때는 모호함을 피하기 위해 괄호를 쓴다. (a/b)/c는 되지만 a/b/c는 안 된다”고 정하고 있기 때문입니다. 그래서 \unit[per-mode = symbol]{\joule\per\mole\per\kelvin}은 J/mol/K가 아니라 J/(mol K)를 출력합니다. 손으로 쓸 때는 “두 번째 슬래시를 조심한다”고 외워야 했던 규칙이 구조적으로 지켜지는 셈입니다. 매뉴얼은 복잡한 경우에는 음의 지수가 더 바람직하다고 덧붙이는데, 기본값이 per-mode = power인 이유가 바로 그것입니다.
\unit{kg.m/s^2} % kg m/s^2 - literal input, slash kept
\unit{\kilo\gram\metre\per\second\squared} % kg m s^-2 - default per-mode = power
\unit[per-mode = symbol]{\kilo\gram\per\cubic\metre} % kg/m^3
\unit{\joule\per\mole\per\kelvin} % J mol^-1 K^-1
\unit[per-mode = symbol]{\joule\per\mole\per\kelvin} % J/(mol K) - brackets added
\sisetup{per-mode = symbol} % one policy for the whole document\qty로 숫자와 단위를 묶기 — 범위·목록·각도
\qty{숫자}{단위}는 첫 번째 인수를 \num에, 두 번째 인수를 \unit에 넘기고 그 사이에 규격대로의 공백을 둡니다. 그래서 새로운 표기를 익힐 필요가 없습니다. \num에 쓸 수 있던 것과 \unit에 쓸 수 있던 것을 그대로 나란히 놓기만 하면 됩니다. 단위 부분은 매크로 형태(\metre\per\second\squared)여도, 리터럴 형태(m/s)여도 됩니다. 이 페이지 첫머리의 생각——양은 숫자와 단위의 곱이다——을 그대로 명령으로 만든 것이 \qty입니다.
범위와 목록에도 전용 명령이 있는데, 눈길을 끄는 것은 \qtyrange{10}{20}{\metre}의 출력입니다. 10–20 m이 아니라 10 m to 20 m로 나옵니다. 이것도 규격에서 온 것입니다. SI 안내서는 물리량을 대시로 이으면 음수로 오독될 수 있고, 양은 하나의 수학적 덩어리이므로 값들을 en 대시로 잇고 단위를 하나만 붙이는 것도 잘못이며, “to”라는 낱말을 쓸 것을 강력히 권장한다고 설명합니다. 표 제목에 10–20 m이라고 쓰고 싶은 충동이 크지만, 그것은 규격 위반입니다. \qtylist{10;20;30}{\metre}는 10 m, 20 m and 30 m을 조판합니다.
각도만은 \qty가 아니라 \ang가 맡습니다. 앞서 말한 대로 \ang{45}는 공백 없는 45°를 내고, 세미콜론으로 도·분·초를 넘기면 \ang{45;30;15}가 45° 30′ 15″가 됩니다. 다만 기본으로 삼을 것은 앞쪽입니다. SI 안내서는 평면각의 경우 일반적으로 도를 십진으로 나누는 편이 바람직하다고 하며, 항해·지도 제작·천문학이나 매우 작은 각의 측정 같은 분야를 제외하면 22° 12′보다 22.20°가 좋다고 말합니다. 분과 초 표기는 그것이 필요한 분야를 위한 도구라고 생각해 두는 편이 무난합니다.
\qty{9.81}{\metre\per\second\squared} % 9.81 m s^-2
\qty{1.234e5}{\kilo\gram\per\cubic\metre} % 1.234 x 10^5 kg m^-3
\qty{2.998e8}{m/s} % literal units work here too
\qtyrange{10}{20}{\metre} % 10 m to 20 m - the word "to", not a dash
\qtylist{10;20;30}{\metre} % 10 m, 20 m and 30 m
\ang{22.20} % 22.20° - decimal degrees are preferred
\ang{45;30;15} % 45° 30' 15" - degrees; minutes; seconds불확도를 괄호로 쓰기 — \num{1.234(5)}
측정값에는 불확도가 따라붙습니다. siunitx는 입력 안의 소괄호를 그대로 불확도로 읽으므로 \num{1.234(5)}는 1.234(5)를 조판합니다. 이 괄호 표기는 siunitx가 만들어 낸 것이 아니라 SI 안내서 §5.4.5가 예로 드는 형식입니다. 거기서는 중성자의 질량을 mₙ = 1.674 927 471(21) × 10⁻²⁷ kg으로 적고, 괄호 안의 수는 인용한 값의 마지막 자리에 대한 표준불확도를 뜻합니다. 즉 \num에 (…)를 넘기는 것은 규격이 이미 상정한 대로 입력을 쓰는 일입니다.
표시 방식은 uncertainty-mode로 고릅니다. 기본값 compact는 괄호 안의 수를 최하위 자리의 숫자로 인쇄하고(\num{123.45(120)} → 123.45(120)), full은 불확도를 완전한 값으로 인쇄합니다(→ 123.45(1.20)). separate-uncertainty를 켜면 \pm로 나눈 1.234 ± 0.005 형태가 됩니다. 여기서 신경 쓸 것은 단위가 무엇에 걸리느냐입니다. 12.3 ± 0.4 kg이라고 쓰면 ±0.4 쪽에는 단위가 없는 것처럼 읽힙니다. siunitx는 이를 알고 있어서, \qty[separate-uncertainty]{12.3(4)}{\kilogram}은 스스로 괄호를 넣어 (12.3 ± 0.4) kg을 출력합니다.
\num{1.234(5)} % 1.234(5)
\num{123.45(120)} % 123.45(120) - compact, the default
\num[uncertainty-mode = full]{123.45(120)} % 123.45(1.20)
\num[separate-uncertainty]{1.234(5)} % 1.234 +- 0.005
\qty{12.3(4)}{\kilogram} % 12.3(4) kg
\qty[separate-uncertainty]{12.3(4)}{\kilogram} % (12.3 +- 0.4) kg - brackets added표를 소수점에 맞추기 — S 열과 table-format
열 지정에서 c, l, r 대신 S라고 쓰면 그 열의 숫자가 소수점에 맞춰 정렬됩니다. 셀 내용은 \num과 같은 파서가 읽으므로 1.2e3은 1.2 × 10³이 되고, 쉼표로 쓴 975,31은 975.31이 됩니다. CSV에서 흘려 넣은 열이 알아서 정돈된다는 뜻입니다. 이것 역시 규격의 요구에 응하는 장치로, SI 안내서는 한 문장으로 짧지만 분명하게 “표 안의 수에서는 한 열 안에서 사용하는 형식을 바꾸지 않아야 한다”고 적고 있습니다.
처음 걸려 넘어지는 곳은 거의 언제나 열 제목입니다. S 열의 셀에 글자를 넣으면 siunitx는 그것을 숫자의 일부로 읽으려 합니다. 그래서 제목은 중괄호로 {Mass}처럼 감싸야 하며, 이를 잊으면 그 행만 정렬이 무너집니다. 단위나 각주 표시를 포함한 제목도 마찬가지로 {Mass / \unit{\gram}}처럼 통째로 보호합니다. 열 너비를 안정시키려면 table-format으로 “정수부 자릿수.소수부 자릿수”를 선언합니다. S[table-format = 4.1]은 정수 4자리와 소수 1자리 자리를 미리 확보하므로, 나중에 행을 더해도 열 위치가 움직이지 않습니다. 불확도가 있으면 S[table-format = 2.2(1), separate-uncertainty], 지수가 있으면 S[table-format = 1.3e2]라고 씁니다.
\begin{tabular}{@{}cS[table-format = 4.1]@{}}
\toprule
Entry & {Mass / \unit{\gram}} \\ % braces protect the heading text
\midrule
1 & 1234.5 \\
2 & 12.0 \\
3 & 6.7 \\
\bottomrule
\end{tabular}
% uncertainties and exponents get their own formats
% S[table-format = 2.2(1), separate-uncertainty] -> 12.34 +- 0.05
% S[table-format = 1.3e2]제목에 단위를 적을 때의 정석도 있습니다. Length [m]이 아니라 Length / m——단위로 나눈 형태가 권장됩니다. 이유는 표기의 충돌입니다. 수학에서 [x]는 “x의 차원”을 뜻하기 때문입니다. 대괄호를 단위의 그릇으로 전용하면 [a]가 “가속도의 차원”인지 “단위가 m/s²”인지 구분되지 않습니다. 단위로 나눈 형태로 쓰면 표의 본문에는 무차원의 수만 남아 S 열이 하는 일과 깔끔하게 맞물립니다. 또 \multicolumn이나 \multirow 안에서 같은 정렬이 필요할 때는 S 열의 매크로판인 \tablenum[table-format = …]{…}을 씁니다.
\SI와 \qty의 차이 — v2에서 v3로 갈아타기
같은 일을 하는 명령의 옛 이름과 새 이름입니다. \SI가 v2, \qty가 v3입니다. siunitx의 작성자 Joseph Wright는 2021년 5월 17일에 배포한 v3.0.0에서 패키지를 내부부터 다시 쓰면서 문서용 명령의 이름을 “더 설명적인” 것으로 바꾸었습니다. 매뉴얼은 \SI, \si, \SIrange, \SIlist가 계속 쓸 수 있기는 하지만 새 문서에서는 권장하지 않는다며 대신 \qty… 계열을 쓰라고 밝힙니다. 이 변화에서 이름이 그대로 남은 것은 \num과 \ang뿐입니다.
| v2(옛 이름) | v3(현행) | 역할 |
|---|---|---|
\SI | \qty{9.81}{\metre\per\second\squared} | 숫자와 단위 |
\si | \unit{\kilo\gram} | 단위만 |
\SIrange | \qtyrange{10}{20}{\metre} | 범위(10 m to 20 m) |
\SIlist | \qtylist{10;20;30}{\metre} | 목록(10 m, 20 m and 30 m) |
\num | \num{1.234e5}(이름 그대로) | 숫자만 |
\ang | \ang{22.20}(이름 그대로) | 평면각 |
v3는 입력도 조금 더 엄격하게 만들었습니다. 눈에 띄는 것은 접두사로, 단위를 동반하지 않은 접두사는 더 이상 쓸 수 없습니다. \unit{\kilo}는 ! Package siunitx Error: Found prefix part with no unit.으로 멈춥니다. 이는 심술이 아니라 규격에 맞춘 변경입니다. SI 안내서 §5.2는 오래전부터 “접두사는 결코 단독으로 쓰지 않으며, 복합 접두사도 쓰지 않는다”고 정하고 있었습니다. 즉 v3의 “파괴적 변경”처럼 보이는 것 가운데 적어도 일부는 패키지가 규격을 따라잡은 결과입니다. 같은 방침으로 숫자끼리의 곱은 \numproduct, 양끼리의 곱은 \qtyproduct로 나뉘었고, 복소수는 전용 명령 \complexnum이 되었습니다.
오래된 문서가 v3에서 도무지 통과하지 않을 때는 읽어 들일 때 버전을 지정해 구버전 동작을 불러올 수 있습니다. \usepackage{siunitx}[=v2]입니다. 다만 이것은 연명책으로 생각하는 편이 좋습니다. v3는 많은 옛 옵션 이름을 내부에서 새 이름으로 옮겨 읽으며, 그때마다 로그에 경고를 남깁니다. 로그에 siunitx 경고가 줄줄이 찍히는 문서는 이름을 고쳐 쓸 때가 되었다는 신호입니다. 새로 시작한다면 익힐 명령은 \num, \unit, \qty 셋이면 충분합니다. 숫자만, 단위만, 그리고 둘 다. 이 페이지에서 살펴본 규격의 세부는 모두 그 셋 안에서 처리됩니다.
% v2 names: still work, no longer recommended for new documents
\SI{9.81}{\metre\per\second\squared}
\si{\kilo\gram}
% v3 names: use these
\qty{9.81}{\metre\per\second\squared}
\unit{\kilo\gram}
% a prefix on its own is now an error:
% ! Package siunitx Error: Found prefix part with no unit.
\unit{\kilo}
% last resort for a document that will not build with v3
\usepackage{siunitx}[=v2]