1TBが931GiBになる理由とnumfmtの切り上げ
「1TBのSSDを買ったのに、OSでは931GBしかない」という話は、容量の数え方が2通りあることで説明がつく。メーカーは 1TB = 10^12 バイト(SI 接頭辞)で表記し、OS やコマンドは 1GiB = 2^30 バイト(2進接頭辞)で割った値を出すことが多い。ここまでは広く知られている。
この記事で確かめるのは、その先の細かい点である。GNU coreutils の numfmt・df -h・ls -h は、換算結果を四捨五入ではなく切り上げで丸める。そのため同じ 1TB が 931.33G や 932G と表示され、手計算の 931.32 と1ずれる。--si や --round=nearest を付けたときに結果がどう変わるかを、手元の環境で実測した。
2進接頭辞の定義は NIST の「Prefixes for binary multiples」に載っている。kibi(Ki)=2^10、mebi(Mi)=2^20、gibi(Gi)=2^30 で、1 GiB = 1 073 741 824 B と書かれている。IEC が名前と記号を承認したのは1998年12月で、SI の kilo は1000倍のままである。NIST は2進接頭辞を SI の一部ではないとも明記している。
換算ツールとしては データサイズ単位変換(ハシトシステム) が B/KB/MB/GB/TB(1000基準)と KiB/MiB/GiB/TiB(1024基準)を並べて表示する。計算はブラウザ内で完結する。以下はそのロジックを手元で再現し、コマンド側の挙動と突き合わせる。
接頭辞が大きいほど差が開く
1000基準の量を1024基準で見ると、目減りの割合は接頭辞ごとに次のようになる。
| 接頭辞 | 1000基準 | 1024基準 | 目減り |
|---|---|---|---|
| K | 10^3 | 2^10 | 2.34% |
| M | 10^6 | 2^20 | 4.63% |
| G | 10^9 | 2^30 | 6.87% |
| T | 10^12 | 2^40 | 9.05% |
TB まで来ると約9%が消えたように見える。1TB は 931.32 GiB、2TB は 1.82 TiB になる。容量が減っているのではなく、同じバイト数を別の物差しで割っているだけである。
実際に試す
前提は Node.js と GNU coreutils(Linux、macOS の Homebrew 版、Windows なら Git Bash)。ここでは Windows 11 の Git Bash(GNU coreutils 8.32)と Node.js v24.11.1、Windows PowerShell 5.1 で実行した。次のファイルを bytes-units.mjs として保存する。
1 | |
1 | |
出力:
1 | |
真の値は 931.3225… なので、小数第2位までの四捨五入は 931.32、切り上げは 931.33 になる。次に、numfmt がどちらで丸めるかを見る。
numfmt は既定で切り上げる
numfmt は数値を人が読みやすい単位に変換するコマンドで、--to=si は1000基準、--to=iec は1024基準で割る。
1 | |
1 | |
--to=iecは932Gを返す。真の値 931.32 を整数に切り上げている。--format=%.2fを付けても931.33Gで、四捨五入の 931.32 にはならない。--round=nearestを付けると931.32Gになる。--roundにはup・down・from-zero・towards-zero・nearestを指定でき、numfmt --helpではfrom-zeroが既定とされている(正の数では切り上げと同じ)。実測では--round=upが931.33G、--round=downが931.32Gだった。--to=iecの出力に付く単位はGで、GiBではない。Gと書かれていても1024基準である。iec-iにするとGiと付く。
この切り上げは桁数が少ないほど目立つ。100万バイトは numfmt --to=iec で 977K、--round=nearest --format=%.1f で 976.6K、--to=si --format=%.1f で 1.0M になる。1,000,000 / 1024 = 976.5625 なので、977K は切り上げの結果である。
ls -h と df -h も同じ丸め
ls -l のサイズ欄でも同じことが起きる。1,000,000 バイトのファイルを作って確かめる。
1 | |
1 | |
ls -lhは1024基準で977K、ls --siは1000基準で1.0M。-hと--siを両方付けたときは後に書いた方が効く(-h --siで1.0M)。du -hは980Kで、ls -lhの977Kと違う。duは既定ではディスク上で確保されたブロック量を数える。ここでは確保量が 980KiB になっている。ファイル本来のバイト数は--apparent-sizeを付けると出て、977Kでlsと一致する。
df -h も1024基準の切り上げ表示である。この環境の C: ドライブは df -B1 で 999069577216 バイト(約 999.07 GB)だが、df -h は 931G と表示した。実際の値は 930.46 GiB で、これも切り上げられている。
単位の接尾辞を読み込む側の違い
数値を読み込む numfmt --from にも罠がある。1.5K が1500なのか1536なのかは、--from に何を指定したかで決まる。
1 | |
1 | |
--from=auto では K が1000倍、Ki が1024倍として扱われる。単位の綴りが K で終わる入力は、既定だと1000基準に読まれる点に注意が必要である。
PowerShell の GB は1024基準
Windows PowerShell には KB・MB・GB・TB という数値リテラルの接尾辞があるが、これは1024基準である。この名前は SI の記号と同じなので間違えやすい。
1 | |
1 | |
1GB は 1073741824(2^30)、1TB は 1099511627776(2^40)になる。同じ C: ドライブを /1GB で割ると 930.46、/1e9 で割ると 999.07 で、同じバイト数が別の数字になる。ここで言えるのは PowerShell のリテラルの挙動だけで、エクスプローラーなど他の画面の表示基準はここでは確かめていない。
まとめ
- 1TB(10^12 バイト)は 931.32 GiB。接頭辞が大きいほど差が開き、TB で約9.05%になる。
- GNU
numfmtは既定で切り上げる。--to=iecは932G、%.2fを付けても931.33G。四捨五入にするには--round=nearestを付ける。 ls -lhとdf -hは1024基準で、--siを付けると1000基準になる。GやKの表示だけでは基準が分からない。du -hはブロック数、ls -lはバイト数を数える。比べるときはdu --apparent-sizeを使う。numfmt --from=autoはKを1000倍、Kiを1024倍と読む。PowerShell のGBは1024基準である。
同じ手元実測の記事として、chmod 755でディレクトリのsetgidが消えない理由 も書いている。
ツール: データサイズ単位変換(ハシトシステム)。B/KB/MB/GB/TB(1000基準)と KiB/MiB/GiB/TiB(1024基準)、ビットを相互換算し、ストレージ表記と OS 表示のずれの理由も確認できる。処理はブラウザ内で完結する。