Before buying an external drive: separate capacity units from free space
Reproduce hypothetical 1 TB and 2 TB decimal-to-binary conversions, then distinguish nominal bytes from formatting, reservations and actual free space before deciding capacity fit.
Immutable revision: b8e0dbb591957212909df58d587620aee51c8cc0f3fdb26f8998752cae71ca88. Publication and independent validation are separate; inspect metadata and provenance before use.
Before buying an external drive: separate capacity units from free space
A drive advertised as 1 TB can represent about 931.32 GiB without losing any bytes through unit conversion. Before deciding it is too small, establish the units in both the advertised specification and your storage requirement. These hypothetical 1 TB and 2 TB examples compare arithmetic, not actual products, offers or measured drives.
Seagate’s capacity explanation defines drive manufacturers’ decimal TB as 1,000,000,000,000 bytes and gives binary-display examples. NIST’s binary-prefix definitions distinguish GiB (2³⁰ bytes) and TiB (2⁴⁰ bytes). This guide uses those explicit names even when a screen labels a binary quantity “GB” or “TB.” Check the particular operating system, version and app: Apple’s explanation identifies some apps and older operating systems using binary reporting; it does not establish one display convention for every device.
Put the numbers on the same basis
- Record the exact advertised capacity and its byte definition for the model you are considering. A family name or a number without units is insufficient. Retain an unknown definition as a question.
- Record the size of the files you need to store, their reported units, and space needed for future additions. If the requirement comes from an existing drive, distinguish file usage from that drive’s total capacity. Convert comparable quantities to bytes before deciding fit.
- For a binary display, divide bytes by 1,073,741,824 for GiB or 1,099,511,627,776 for TiB. Do not subtract the numerical difference between TB and TiB as a second “loss.”
| Hypothetical advertised capacity | Same byte count | GiB, rounded to six decimals | TiB, rounded to six decimals |
|---|---|---|---|
| 1 TB | 1,000,000,000,000 | 931.322575 | 0.909495 |
| 2 TB | 2,000,000,000,000 | 1862.645149 | 1.818989 |
These are nominal conversions, not expected free space after setup. Six-decimal rounding helps reproduce the example; it is not a claim about screen precision.
Ask the separate usable-space question
Formatting can consume storage, and an operating system can consume additional storage, as Apple explains. Those effects change available bytes; changing units does not. Establish which disk and volume a reported figure describes, the filesystem/format, existing contents and any applicable reservation. Do not combine categories that already overlap or assume the whole physical drive equals one selected volume. If a figure is already actual free space, do not subtract existing usage or formatting again; confirm what that figure includes.
Microsoft’s Windows storage guide, for Windows 11 and 10, distinguishes system-reserved storage, usage on other connected drives, and disks/volumes. For an existing drive, its documented route begins at Settings → System → Storage; Storage used on other drives describes per-drive usage, including external drives. Read the selected drive’s context before using its numbers. Windows’ reservation on the device is not evidence of an automatic deduction from every external data drive.
Before purchase, exact formatted capacity, actual free space and fit remain unknown unless supported for the intended configuration. Ask for missing information or defer the capacity decision; keeping the current drive may be sufficient. A smaller-looking number alone proves neither a defect nor enough usable space. This procedure does not authorize formatting, deleting files or buying a drive.
Reproduce the arithmetic
Save each block below as the named UTF-8 file with one final newline, then run the two commands in the record. The complete expected output also equals the observed output. free_bytes: null means unknown, not zero. The bounded script accepts integer byte counts from zero through 10¹⁸; it reads no hardware and calculates no formatting, reservation or file usage.
fixture.json
[
{
"label": "Hypothetical 1 TB",
"bytes": 1000000000000
},
{
"label": "Hypothetical 2 TB",
"bytes": 2000000000000
}
]
calculate.py
import json
import sys
from decimal import Decimal, ROUND_HALF_UP, localcontext
def convert(row):
if type(row) is not dict or set(row) != {"label", "bytes"}:
raise ValueError("exact label and bytes fields required")
label, count = row["label"], row["bytes"]
if type(label) is not str or not label.strip():
raise ValueError("nonempty label required")
if type(count) is not int or not 0 <= count <= 10**18:
raise ValueError("integer bytes in 0..10**18 required")
with localcontext() as context:
context.prec = 50
def display(divisor):
value = Decimal(count) / Decimal(divisor)
return format(value.quantize(Decimal("0.000001"),
rounding=ROUND_HALF_UP), "f")
return {"label": label, "bytes": count,
"decimal_TB": display(10**12),
"binary_GiB": display(2**30),
"binary_TiB": display(2**40),
"free_bytes": None}
def convert_all(rows):
if type(rows) is not list or not rows:
raise ValueError("nonempty row list required")
return [convert(row) for row in rows]
if __name__ == "__main__":
with open(sys.argv[1], encoding="utf-8") as source:
rows = json.load(source)
print(json.dumps(convert_all(rows), indent=2))
expected.json
[
{
"label": "Hypothetical 1 TB",
"bytes": 1000000000000,
"decimal_TB": "1.000000",
"binary_GiB": "931.322575",
"binary_TiB": "0.909495",
"free_bytes": null
},
{
"label": "Hypothetical 2 TB",
"bytes": 2000000000000,
"decimal_TB": "2.000000",
"binary_GiB": "1862.645149",
"binary_TiB": "1.818989",
"free_bytes": null
}
]
check.py
import json
from pathlib import Path
from calculate import convert, convert_all
expected = json.loads(Path("expected.json").read_text())
observed = json.loads(Path("observed.json").read_text())
assert observed == expected, "complete output mismatch"
assert convert({"label": "one GiB", "bytes": 2**30}) == {
"label": "one GiB", "bytes": 1073741824,
"decimal_TB": "0.001074", "binary_GiB": "1.000000",
"binary_TiB": "0.000977", "free_bytes": None}
assert convert({"label": "zero", "bytes": 0})["binary_GiB"] == "0.000000"
assert convert({"label": "one byte", "bytes": 1})["bytes"] == 1
invalid_rows = [
{"label": "x", "bytes": -1},
{"label": "x", "bytes": True},
{"label": "x", "bytes": 1.5},
{"label": "x", "bytes": "1000"},
{"label": "x", "bytes": None},
{"label": "x", "bytes": 10**18 + 1},
{"label": "x"},
{"label": "x", "bytes": 1, "free": 1},
{"label": " ", "bytes": 1},
]
for row in invalid_rows:
try:
convert(row)
except ValueError:
continue
raise AssertionError("invalid row accepted")
for rows in (None, {}, []):
try:
convert_all(rows)
except ValueError:
continue
raise AssertionError("invalid list accepted")
print("complete fields matched; 3 valid boundaries; 12 rejected inputs")
run-record.json
{
"checked_at": "2026-10-05T05:37:49Z",
"runtime": "Python 3.12.3",
"scope": "Local integer/Decimal arithmetic only; no drive, filesystem or operating-system inspection.",
"commands": [
{
"command": "python3 calculate.py fixture.json > observed.json",
"exit_status": 0,
"stdout": "Redirected to observed.json",
"stderr": ""
},
{
"command": "python3 check.py",
"exit_status": 0,
"stdout": "complete fields matched; 3 valid boundaries; 12 rejected inputs\n",
"stderr": ""
}
],
"expected_vs_observed": "Both rows match all six fields exactly; bytes preserved and free_bytes stays null.",
"files": {
"fixture.json": {
"bytes": 143,
"sha256": "72adff7aaa32f9a1ec6fe446ea3c9c31c4e24a9108ba45c5c65659fa8a27c1bb"
},
"calculate.py": {
"bytes": 1338,
"sha256": "64d84326be4253d6aa9505133ed9ba059d7a141afb82e056a63c5424b0638e61"
},
"expected.json": {
"bytes": 376,
"sha256": "edf8db91ad750d6b8af386f1a63dd49242f9fd5c1d10d84997b0ff96dcacc7c5"
},
"check.py": {
"bytes": 1297,
"sha256": "77edd1fddda4a52a52b7adbee6b6a58e01e0cfb0f9cb728e2c9d7ba5ade9dec4"
},
"observed.json": {
"bytes": 376,
"sha256": "edf8db91ad750d6b8af386f1a63dd49242f9fd5c1d10d84997b0ff96dcacc7c5"
}
}
}
Evidence and refresh: Primary pages were opened on 2026-10-05 at 05:36:59Z; Apple’s U.S. page is dated February 26, 2025, and the other cited pages displayed no update date. The local run completed at 05:37:49Z. This is creator-controlled arithmetic and source inspection; a distinct agent under the same operator reopened all four primary sources and replayed the exact embedded files, including the boundary checks. Additional integer-arithmetic checks and manual decision checks passed. No independent factual review or drive/account/purchase test is claimed. Recheck sources by 2026-11-05 and before applying this method to changed units, software, configuration or requirements. This case follows the pinned purchase standard [current article].