# 5. Getting Started

In this section we will take a high-level look at the basic things you can do with bitmath. We’ll include the following topics:

## 5.1. Tables of Supported Operations

The following legend describes the two operands used in the tables below.

Operand | Description
--- | ---
`bm` | A bitmath object is required
`num` | An integer or decimal value is required

### 5.1.1. Arithmetic

Math works mostly like you expect it to, except for a few edge-cases:

- Mixing bitmath types with Number types (the result varies per-operation)

- Operations where two bitmath types would cancel out (such as dividing two bitmath types)

- Multiplying two bitmath instances together is supported, but the results may not make much sense.

See also

Appendix: Rules for Math

  For a discussion of the behavior of bitmath and number types.

Operation | Parameters | Result Type | Example
--- | --- | --- | ---
Addition | `bm1` + `bm2` | `type(bm1)` | `KiB(1) + MiB(2)` = `2049.0KiB`
Addition | `bm` + `num` | `type(num)` | `KiB(1) + 1` = `2.0`
Addition | `num` + `bm` | `type(num)` | `1 + KiB(1)` = `2.0`
Subtraction | `bm1` - `bm2` | `type(bm1)` | `KiB(1) - Byte(2048)` = `-1.0KiB`
Subtraction | `bm` - `num` | `type(num)` | `KiB(4) - 1` = `3.0`
Subtraction | `num` - `bm` | `type(num)` | `10 - KiB(1)` = `9.0`
Multiplication | `bm1` * `bm2` | `type(bm1)` | `KiB(1) * KiB(2)` = `2048.0KiB`
Multiplication | `bm` * `num` | `type(bm)` | `KiB(2) * 3` = `6.0KiB`
Multiplication | `num` * `bm` | `type(bm)` | `2 * KiB(3)` = `6.0KiB`
Division | `bm1` / `bm2` | `type(num)` | `KiB(1) / KiB(2)` = `0.5`
Division | `bm` / `num` | `type(bm)` | `KiB(6) / 4` = `KiB(1.5)`
Division | `num` / `bm` | `type(num)` | `3 / KiB(2)` = `1.5`
Floor Division | `bm1` // `bm2` | `int` | `GiB(1) // MiB(300)` = `3`
Floor Division | `bm` // `num` | `type(bm)` | `KiB(6) // 4` = `KiB(1.5)`2
Modulo | `bm1` % `bm2` | `type(bm1)` | `GiB(1) % MiB(300)` = `GiB(0.12...)`
Modulo | `bm` % `num` | `type(bm)` | `GiB(1) % 1000` = `GiB(2.23e-7)`2
divmod | `divmod(bm1, bm2)` | `(int, type(bm1))` | `divmod(GiB(1), MiB(300))` = `(3, GiB(0.12...))`

2. For `//` and `%` with a scalar RHS, the scalar operates on the internal byte count (consistent with how `/` is defined for `bm / num`). This is mostly useful for `bm op bm` forms; the `bm op num` forms are provided for completeness.

### 5.1.2. Bitwise Operations

See also

Bitwise Calculator

  A free online calculator for checking your math

Bitwise operations are also supported. Bitwise operations work directly on the `bits` attribute of a bitmath instance, not the number you see in an instances printed representation (`value`), to maintain accuracy.

Operation | Parameters | Result Type | Example1
--- | --- | --- | ---
Left Shift | `bm` << `num` | `type(bm)` | `MiB(1)` << `2` = `MiB(4.0)`
Right Shift | `bm` >> `num` | `type(bm)` | `MiB(1)` >> `2` = `MiB(0.25)`
AND | `bm` & `num` | `type(bm)` | `MiB(13.37)` & `1337` = `MiB(0.000126...)`
OR | `bm` | `num` | `type(bm)` | `MiB(13.37)` | `1337` = `MiB(13.3700...)`
XOR | `bm` ^ `num` | `type(bm)` | `MiB(13.37)` ^ `1337` = `MiB(13.369...)`

1. Give me a break here, it’s not easy coming up with compelling examples for bitwise operations…

## 5.2. Basic Math

bitmath supports all arithmetic operations

    1>>> eighty_four_mib = fourty_two_mib + fourty_two_mib_in_kib
    2>>> eighty_four_mib
    3MiB(84.0)
    4>>> eighty_four_mib == fourty_two_mib * 2
    5True

## 5.3. Capacity Math: Floor Division and Modulo

Floor division (`//`), modulo (`%`), and `divmod()` are useful for capacity-planning problems: “how many N-sized chunks fit into this device, and how much is left over?”

As with the other arithmetic operators, the left-hand operand’s type is preserved in the result. The one exception is `bm1 // bm2`, which returns a unitless `int` — a count of whole divisions — mirroring how `bm1 / bm2` returns a unitless ratio.

     1>>> from bitmath import GiB, MiB
     2>>> disk = GiB(1)
     3>>> chunk = MiB(300)
     4
     5>>> disk // chunk        # how many whole 300 MiB chunks fit in 1 GiB?
     63
     7>>> disk % chunk         # leftover, typed as the LHS (GiB)
     8GiB(0.12109375)
     9>>> divmod(disk, chunk)  # both at once
    10(3, GiB(0.12109375))
    11
    12>>> # Exact fits produce a zero-valued bitmath in the LHS unit:
    13>>> GiB(1) % MiB(1)
    14GiB(0.0)

Note

With a scalar RHS, the scalar operates on the internal byte count — consistent with how `bm / num` is defined. In practice the `bm op bm` forms above are what you want for capacity math; the `bm op num` forms are available but rarely useful.

The fundamental identity holds — `(a // b) * b + (a % b) == a`:

    >>> q, r = divmod(GiB(1), MiB(300))
    >>> (q * MiB(300)) + r == GiB(1)
    True

### 5.3.1. Coercing the Remainder with `best_prefix`

Because `%` preserves the LHS type, a small remainder can display with an awkwardly tiny `value`. Use `.best_prefix()` to re-express the result in a more human-readable unit without changing its size:

     1>>> leftover = GiB(1) % MiB(300)
     2>>> leftover
     3GiB(0.12109375)
     4>>> leftover.best_prefix()
     5MiB(124.0)
     6
     7>>> # Force a specific unit system:
     8>>> import bitmath
     9>>> leftover.best_prefix(system=bitmath.SI)
    10MB(130.02330...)
    11
    12>>> # Or coerce directly to a known unit:
    13>>> leftover.to_MiB()
    14MiB(124.0)

### 5.3.2. Formatting Remainders in a `bitmath.format` Context

The `bitmath.format` context manager pairs nicely with modulo results when you want consistent, human-readable display throughout a block of capacity calculations — including automatic best-prefix coercion:

     1>>> import bitmath
     2>>> from bitmath import GiB, MiB, TiB
     3
     4>>> volume = TiB(1)
     5>>> block = GiB(7)
     6>>> with bitmath.format(fmt_str="{value:.2f} {unit}", bestprefix=True):
     7...     whole = volume // block
     8...     leftover = volume % block
     9...     print(f"{whole} whole blocks of {block} fit in {volume}")
    10...     print(f"leftover: {leftover}")
    11146 whole blocks of 7.00 GiB fit in 1.00 TiB
    12leftover: 2.00 GiB
    13
    14>>> # divmod inside a context manager, reporting in plural form.
    15>>> # Note: bestprefix on a zero remainder collapses to bits ("b").
    16>>> with bitmath.format(fmt_str="{value:.1f} {unit}", plural=True, bestprefix=True):
    17...     q, r = divmod(GiB(10), MiB(256))
    18...     print(f"{q} chunks, {r} remaining")
    1940 chunks, 0.0 b remaining

Note

`bitmath.format` is thread-safe — settings are thread-local, so concurrent contexts in different threads do not interfere.

## 5.4. Unit Conversion

     1>>> from bitmath import *
     2>>> fourty_two_mib = MiB(42)
     3>>> fourty_two_mib_in_kib = fourty_two_mib.to_KiB()
     4>>> fourty_two_mib_in_kib
     5KiB(43008.0)
     6
     7>>> fourty_two_mib
     8MiB(42.0)
     9
    10>>> fourty_two_mib.KiB
    11KiB(43008.0)

Let’s convert a unit and show the differences. What happens if we convert `2048 MB` into GiBs? Let’s look the MB unit in closer detail:

    >>> from bitmath import *
    >>> MB(2048).base, MB(2048).power, MB(2048).bytes
    (10, 6, 2048000000.0)

An MB (megabyte) is an SI unit in the base-10 number system. A single megabyte is 10 raised to the power of 6. When you raise 10 to the power of 6 and multiply the result by 2048 you get the number of bytes in `MB(2048)`. We can check this by creating a byte object with that many bytes as the value and ask for the `MB` equivalent:

    >>> bitmath.Byte((10**6)*2048).MB
    MB(2048.0)

What about that conversion though, how about we convert this into GiBs? Those are NIST units, it is a base-2 number system. Let’s convert the MB to a GiB and look at those instance attributes again:

    >>> convert_demo = bitmath.MB(2048).GiB
    >>> convert_demo
    GiB(1.9073486328125)
    >>> convert_demo.base, convert_demo.power, convert_demo.bytes
    (2, 30, 2048000000.0)

We can see that the entire calculation has changed but the number of bytes has remained the same. Now we have 2 raised to the power of 6, times 1.9073486328125.

A cleaner looking conversion is possible if we convert this within the same unit system. If we look at the GB equivalent we get:

    >>> convert_demo.GB
    GB(2.048)

Because we aren’t shifting between different base number systems.

## 5.5. Rich Comparison

Rich Comparison (as per the Python Basic Customization magic methods) `<`, `<=`, `==`, `!=`, `>`, `>=` is fully supported:

     1>>> GB(1) < GiB(1)
     2True
     3>>> GB(1.073741824) == GiB(1)
     4True
     5>>> GB(1.073741824) <= GiB(1)
     6True
     7>>> Bit(1) == TiB(bits=1)
     8True
     9>>> kB(100) > EiB(bytes=1024)
    10True
    11>>> kB(100) >= EiB.from_other(kB(100))
    12True
    13>>> kB(100) >= EiB.from_other(kB(99))
    14True
    15>>> kB(100) >= EiB.from_other(kB(9999))
    16False
    17>>> KiB(100) != Byte(1)
    18True

## 5.6. Sorting

bitmath natively supports sorting.

Let’s make a list of the size (in bytes) of all the files in the present working directory (lines 4 and 5) and then print them out sorted by increasing magnitude (lines 10 and 11, and 13 → 15):

     1>>> from bitmath import *
     2>>> import os
     3>>> sizes = []
     4>>> for f in os.listdir('./tests/'):
     5...     sizes.append(KiB(os.path.getsize('./tests/' + f)))
     6
     7>>> print(sizes)
     8[KiB(7337.0), KiB(1441.0), KiB(2126.0), KiB(2178.0), KiB(2326.0), KiB(4003.0), KiB(48.0), KiB(1770.0), KiB(7892.0), KiB(4190.0)]
     9
    10>>> print(sorted(sizes))
    11[KiB(48.0), KiB(1441.0), KiB(1770.0), KiB(2126.0), KiB(2178.0), KiB(2326.0), KiB(4003.0), KiB(4190.0), KiB(7337.0), KiB(7892.0)]
    12
    13>>> human_sizes = [s.best_prefix() for s in sizes]
    14>>> print(sorted(human_sizes))
    15[KiB(48.0), MiB(1.4072265625), MiB(1.728515625), MiB(2.076171875), MiB(2.126953125), MiB(2.271484375), MiB(3.9091796875), MiB(4.091796875), MiB(7.1650390625), MiB(7.70703125)]

Now print them out in descending magnitude

    >>> print(sorted(human_sizes, reverse=True))
    [MiB(7.70703125), MiB(7.1650390625), MiB(4.091796875), MiB(3.9091796875), MiB(2.271484375), MiB(2.126953125), MiB(2.076171875), MiB(1.728515625), MiB(1.4072265625), KiB(48.0)]

## 5.7. Parsing Strings

`bitmath.parse_string()` converts a human-readable string into a bitmath instance. By default the unit must be an exact bitmath type name:

    >>> import bitmath
    >>> bitmath.parse_string("4.7 GiB")
    GiB(4.7)
    >>> bitmath.parse_string("1337 MB")
    MB(1337.0)
    >>> bitmath.parse_string("1 Mio")   # octet alias
    MiB(1.0)

When the input comes from a tool that produces ambiguous output (often-times single-letter units) use `strict=False`. Pass `system=bitmath.SI` or `system=bitmath.NIST` to tell the parser which system to use if the unit can not reliably be determined automatically:

    >>> bitmath.parse_string("4G", strict=False)             # NIST default
    GiB(4.0)
    >>> bitmath.parse_string("4G", strict=False, system=bitmath.SI)
    GB(4.0)
    >>> bitmath.parse_string("100", strict=False)            # plain number → bytes
    Byte(100.0)
    >>> bitmath.parse_string("100 GiB", strict=False, system=bitmath.SI)  # i-marker wins
    GiB(100.0)

See also

`bitmath.parse_string()` — full parameter reference and caveats.

## 5.8. Summing an Iterable

The built-in `sum()` works with bitmath objects. Because `0 + bm` returns `bm` itself (the identity element), accumulation starts correctly and the result type matches the first element in the iterable:

    >>> import bitmath
    >>> sum([bitmath.KiB(1), bitmath.KiB(2)])
    KiB(3.0)
    >>> sum([bitmath.Byte(1), bitmath.MiB(1), bitmath.GiB(1)])
    Byte(1074790401.0)

Results from mixing plain numbers and numbers with units yields a result with no units.

    >>> sum([bitmath.Byte(1), 0])
    1.0
    >>> sum([1, bitmath.KiB(2)])
    3.0

See also

Appendix: Rules for Math — for a thrilling discussion about the minute details when doing mixed-type math math. What it all boils down to is this: if we don’t provide a unit then bitmath won’t give us one back.

Use `bitmath.sum()` when you need the result normalised to a specific unit regardless of the input types. Without a `start` argument it accumulates into `bitmath.Byte`; pass `start` to choose a different accumulator (resultant unit):

    >>> bitmath.sum([bitmath.MiB(1), bitmath.GiB(1)])
    Byte(1074790400.0)
    >>> bitmath.sum([bitmath.KiB(1), bitmath.KiB(2)], start=bitmath.MiB(0))
    MiB(0.0029296875)
    >>> bitmath.sum([bitmath.MiB(100), bitmath.KiB(2000)], start=bitmath.GiB(0))
    GiB(0.0995635986328125)

## 5.9. Rounding

bitmath represents sizes as floating-point measurements. When an integer result is needed, Python’s `math.floor()`, `math.ceil()`, and `round()` all work directly on bitmath instances and return an instance of the same type:

    >>> import math, bitmath
    >>> math.floor(bitmath.KiB(1) / 3)
    KiB(0)
    >>> math.ceil(bitmath.KiB(1) / 3)
    KiB(1)
    >>> round(bitmath.MiB(1.75))
    MiB(2)
    >>> round(bitmath.GiB(1.23456), 2)
    GiB(1.23)

Warning

Rounding intermediate results is lossy. `math.floor(GiB(10) / 3) * 3` yields `GiB(9)`, not `GiB(10)`. Only round at the final output step.

See also

Appendix: Rules for Math — discussion of floating-point representation and when rounding is appropriate.

## 5.10. Choosing a Formatting Approach

bitmath offers several ways to control how instances are rendered as strings. They overlap deliberately — each suits a different situation. This section helps you pick the right one.

Quick reference

Approach | Best for | Avoid when
--- | --- | ---
Default `str()` | Printing, debugging, logging | You need custom precision or layout
`instance.format()` | Full control over layout using any instance attribute | You only need to format the number
f-strings / `format()` | Inline formatting in modern Python; columnar output | You need unit-aware attributes beyond `value`
`bitmath.format()` context manager | Consistent formatting across a block of code; threaded code | A one-off format on a single value
`bitmath.format_string` global | Changing the default for an entire script or session | Anything other than a top-level script (mutates global state)

### 5.10.1. Default `str()`

The simplest option. Just print or convert to string — no imports, no setup. Output follows the module-level `format_string` (default: `"{value} {unit}"`):

    >>> import bitmath
    >>> print(bitmath.MiB(1.5))
    1.5 MiB
    >>> str(bitmath.GiB(10))
    '10.0 GiB'

Use this when you just need a readable value and don’t care about precision or alignment.

### 5.10.2. `instance.format()`

The most expressive option. The format string has access to every instance attribute — `{value}`, `{unit}`, `{bits}`, `{bytes}`, `{system}`, `{base}`, `{power}`, and more:

    >>> size = bitmath.MiB(1 / 3.0)
    >>> size.format("{value:.2f} {unit} ({bits:.0f} bits)")
    '0.33 MiB (2796202 bits)'

Use this when you need the unit label, bit/byte counts, or any other instance attribute woven into the output string.

See also

Instance Formatting — full attribute reference.

### 5.10.3. f-strings and `format()`

Standard Python formatting. The format spec applies to `self.value` only; the unit is omitted unless you add it explicitly with `{size.unit}`:

    >>> size = bitmath.GiB(127.3)
    >>> f'{size:.2f} {size.unit}'
    '127.30 GiB'
    >>> f'{size}'           # no spec → same as str(size)
    '127.3 GiB'

This shines for columnar output where alignment matters:

    >>> rows = [("home", bitmath.GiB(127.3)), ("tmp", bitmath.MiB(843.7))]
    >>> for mount, size in rows:
    ...     print(f"{mount:<8} {size:>10.2f} {size.unit}")
    home        127.30 GiB
    tmp         843.70 MiB

Use this when you’re building formatted strings inline and only need the numeric value with a precision or alignment spec.

### 5.10.4. `bitmath.format()` context manager

Sets `fmt_str`, `plural`, and `bestprefix` for every bitmath `str()` call within the block, then restores the previous state automatically — even if an exception is raised. Safe to use in threaded code:

    >>> sizes = [bitmath.KiB(1024), bitmath.MiB(512)]
    >>> with bitmath.format(fmt_str="{value:.1f} {unit}", bestprefix=True):
    ...     for s in sizes:
    ...         print(s)
    1.0 MiB
    512.0 MiB

Use this when you want a consistent format across multiple `print()` or `str()` calls without touching each one individually, or when you’re in a threaded environment.

See also

bitmath.format() — full parameter reference.

### 5.10.5. `bitmath.format_string` global

Sets the default representation for all bitmath instances for the remainder of the process. Useful at the top of a script; a poor choice inside a library or threaded code:

    >>> import bitmath
    >>> bitmath.format_string = "{value:.2f} {unit}"
    >>> print(bitmath.MiB(1.5))
    1.50 MiB

Use this when you control the entire script and want a single format everywhere without wrapping everything in a context manager. Prefer the context manager for anything more targeted.

Warning

Mutating `bitmath.format_string` directly affects all threads. Use the `bitmath.format()` context manager instead in concurrent code.