Skip to main content

An educational IEEE 754 floating-point library that stores every bit explicitly so you can watch the chaos unfold.

Project description

naive-ieee754

Ever wondered why 0.1 + 0.2 gives 0.30000000000000004? This library won't fix that — but it will let you watch it happen in slow motion.

naive-ieee754 is an educational Python library for exploring IEEE 754 floating-point representation. It stores every number explicitly as three separate fields — sign, exponent bits, and significand bits — as plain Python lists, and implements all arithmetic using explicit bit-by-bit loops.

The "naive" in the name is intentional. This is not fast. It is not memory-efficient. It would be an awful choice for production code. It is a magnifying glass for understanding what your CPU is actually doing when you type 1.5 + 2.3.


Explore

Two resources cover the full feature set of the library, side by side:

Format File Best for
Script examples/ieee754_overview.py Running in a terminal, reading annotated source
Notebook notebooks/ieee754_overview.ipynb Interactive exploration in VS Code or JupyterLab

Both walk through the same topics in the same order: constructors, bit inspection, special values, step-by-step arithmetic, the 0.1 + 0.2 gotcha, rounding modes, custom formats, and number-line visualization.

To run the script:

python examples/ieee754_overview.py

To open the notebook (requires dev dependencies):

uv sync --group dev
jupyter lab notebooks/ieee754_overview.ipynb

Why does this exist?

Floating-point arithmetic is one of those topics where everyone nods along in class and then spends the next decade slowly discovering that 0.1 is not 0.1, that -0 == 0 but they are different values, and that NaN != NaN is perfectly valid behavior and not a bug in your comparison logic.

naive-ieee754 makes all of this visible. You can inspect every bit, trace every rounding decision, and plot every representable number on a number line. Once you stare at the density gradient of Float8 values for a while, the weirdness starts to make a strange kind of sense.


Installation

pip install naive-ieee754

Or with uv:

uv add naive-ieee754

Quick start

from naive_ieee754 import Float32, Float8, number_line

# Convert a decimal to IEEE 754 and inspect the bit fields
a = Float32.from_decimal(0.1)
print(repr(a))
# Float32(sign=0 exp=[01111011] sig=[10011001100110011001101])

print(a.to_bit_string())
# 0 01111011 10011001100110011001101

print(a.to_hex())
# 3DCCCCCD

Step-by-step arithmetic

b = Float32.from_decimal(0.2)
result = a.add(b)          # verbose; returns an ArithmeticResult
print(result.explain())    # step-by-step breakdown of the addition
print(result.precision_report())
# exact (Python float64): 0.30000000447034836
# represented (Float32): 0.30000001192092896
# absolute error: 7.450580596923828e-09
# relative error: 2.48e-08

Using the + operator works too and returns a plain IEEEFloat:

c = a + b
print(str(c))
# 0.30000001192092896 (Float32)

Special values

from naive_ieee754 import Float32

print(Float32.positive_infinity())   # +Inf (Float32)
print(Float32.negative_zero())       # -0 (Float32)
print(Float32.nan())                 # NaN (Float32)

# IEEE 754 quirks in action
nan = Float32.nan()
print(nan == nan)    # False  (NaN is never equal to anything, including itself)

pz = Float32.positive_zero()
nz = Float32.negative_zero()
print(pz == nz)      # True   (IEEE 754: +0 == -0)
print(repr(pz))      # Float32(sign=0 exp=[00000000] sig=[00000000000000000000000])
print(repr(nz))      # Float32(sign=1 exp=[00000000] sig=[00000000000000000000000])

Number line visualization

from naive_ieee754 import Float8, number_line
from naive_ieee754.formats import FLOAT32_FORMAT

# Show every finite Float8 value (all 238 of them)
number_line(Float8.FORMAT)

# Sample Float32 values — 4 billion is too many to plot
number_line(FLOAT32_FORMAT, samples_per_exponent=8)

The plot uses a symmetric log scale so you can see how IEEE 754 values are distributed across the full ±∞ range. Float16 is plotted exactly; Float32 and Float64 are sampled — the title and legend report how many values exist and what fraction is shown.

Float16 — 63,488 finite values, all plotted (exact):

Float16 full range on symlog scale

Float32 — ~4.28 × 10⁹ finite values, sampled:

Float32 full range on symlog scale

Float64 — ~1.84 × 10¹⁹ finite values, sampled:

Float64 full range on symlog scale

Custom formats

Want a 9-bit float with 3 exponent bits and 5 significand bits? Sure, why not:

from naive_ieee754 import custom_float, number_line

MyFloat = custom_float(exponent_bits=3, significand_bits=5)
x = MyFloat.from_decimal(1.5)
print(repr(x))
# Custom(3e+5sig)(sign=0 exp=[011] sig=[10000])

number_line(MyFloat.FORMAT)

Supported formats

Class Bits Exponent Significand Bias Max value
Float8 8 4 3 7 240
Float16 16 5 10 15 65504
Float32 32 8 23 127 ~3.4 × 10³⁸
Float64 64 11 52 1023 ~1.8 × 10³⁰⁸

Custom formats can be created with custom_float(exponent_bits, significand_bits).


Rounding modes

By default all operations use round-to-nearest-even (IEEE 754's default). You can pass a different RoundingMode to the verbose .add(), .mul(), etc.:

from naive_ieee754 import Float32, RoundingMode

a = Float32.from_decimal(1.0)
b = Float32.from_decimal(3.0)
result = a.div(b, rounding=RoundingMode.ROUND_TOWARD_ZERO)
print(result.explain())

Available modes: ROUND_TO_NEAREST_EVEN, ROUND_TOWARD_ZERO, ROUND_TOWARD_POS_INF, ROUND_TOWARD_NEG_INF.

Verbose arithmetic results also expose IEEE 754 status flags:

from naive_ieee754 import FloatingPointFlag

result = Float32.from_decimal(1.0).div(Float32.from_decimal(3.0))
print(FloatingPointFlag.INEXACT in result.flags)
# True

Subnormal numbers

Subnormal numbers (values very close to zero with stored exponent = 0) are supported in conversion and arithmetic. The library uses gradual underflow: tiny exact results are rounded into the subnormal range when possible, and inexact tiny results raise the UNDERFLOW and INEXACT flags in verbose arithmetic results.


License

MIT — see LICENSE.

Author: Francisco Corrêa Dias — @fcdiass

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

naive_ieee754-0.1.0.tar.gz (26.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

naive_ieee754-0.1.0-py3-none-any.whl (31.5 kB view details)

Uploaded Python 3

File details

Details for the file naive_ieee754-0.1.0.tar.gz.

File metadata

  • Download URL: naive_ieee754-0.1.0.tar.gz
  • Upload date:
  • Size: 26.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for naive_ieee754-0.1.0.tar.gz
Algorithm Hash digest
SHA256 5c35f6bd938ed7141590cd73c33f6ec818a70c16e366e30d8c1b1be923665737
MD5 fb9d349b2d7a6887df835475c7b6c568
BLAKE2b-256 0c642fe67ab590179478f92d5a5bc96e27691f88f44e0f19f00b300063c2026c

See more details on using hashes here.

File details

Details for the file naive_ieee754-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: naive_ieee754-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 31.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for naive_ieee754-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4ae8019c7f8578c16dd414fbfd09f345accf5f9c914859d69ef7110b0333416d
MD5 40b26f028fd8a8ac96743d822599d3be
BLAKE2b-256 4a2da10da5b5efe6feeae6a669b134bfb4399e72e12a31438c08ffb6cc64a917

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page