diff --git a/b_asic/quantization.py b/b_asic/quantization.py
new file mode 100644
index 0000000000000000000000000000000000000000..6fae9d2722aff3c99c39bfd98ac4efbe355b0a0a
--- /dev/null
+++ b/b_asic/quantization.py
@@ -0,0 +1,139 @@
+"""B-ASIC quantization module."""
+
+import math
+from enum import Enum
+
+from b_asic.types import Num
+
+
+class Quantization(Enum):
+    """Quantization types."""
+
+    ROUNDING = 1
+    "Standard two's complement rounding, i.e, tie rounds towards infinity."
+
+    TRUNCATION = 2
+    "Two's complement truncation, i.e., round towards negative infinity."
+
+    MAGNITUDE_TRUNCATION = 3
+    "Magnitude truncation, i.e., round towards zero."
+
+    JAMMING = 4
+    "Jamming/von Neumann rounding, i.e., set the LSB to one"
+
+    UNBIASED_ROUNDING = 5
+    "Unbiased rounding, i.e., tie rounds towards even."
+
+
+class Overflow(Enum):
+    """Overflow types."""
+
+    TWOS_COMPLEMENT = 1
+    "Two's complement overflow, i.e., remove the more significant bits."
+
+    SATURATION = 2
+    """
+    Two's complement saturation, i.e., overflow return the most postive/negative
+    number.
+    """
+
+
+def quantize(
+    value: Num,
+    fractional_bits: int,
+    integer_bits: int = 1,
+    quantization: Quantization = Quantization.TRUNCATION,
+    overflow: Overflow = Overflow.TWOS_COMPLEMENT,
+):
+    r"""
+    Quantize *value* assuming two's complement representation.
+
+    Quantization happens before overflow, so, e.g., rounding may lead to an overflow.
+
+    The total number of bits is *fractional_bits* + *integer_bits*. However, there is
+    no check that this will be a positive number. Note that the sign bit is included in these
+    bits. If *integer_bits* is not given, then use 1, i.e., the result is between
+
+    .. math::   -1 \leq \text{value} \leq 1-2^{-\text{fractional_bits}}
+
+    If *value* is a complex number, the real and imaginary parts are quantized separately.
+
+    Parameters
+    ----------
+    value : int, float, complex
+        The value to be quantized.
+    fractional_bits : int
+        Number of fractional bits, can be negative.
+    integer_bits : int, default: 1
+        Number of integer bits, can be negative.
+    quantization : :class:`Quantization`, default: :class:`Quantization.TRUNCATION`
+        Type of quantization.
+    overflow : :class:`Overflow`, default: :class:`Overflow.TWOS_COMPLEMENT`
+        Type of overflow.
+
+    Returns
+    -------
+    int, float, complex
+        The quantized value.
+
+    Examples
+    --------
+    >>> from b_asic.quantization import quantize, Quantization, Overflow
+    ...
+    ... quantize(0.3, 4)  # Truncate 0.3 using four fractional bits and one integer bit
+    0.25
+    >>> quantize(0.3, 4, quantization=Quantization.ROUNDING)  # As above, but round
+    0.3125
+    >>> quantize(1.3, 4)  # Will overflow
+    -0.75
+    >>> quantize(1.3, 4, 2)  # Use two integer bits
+    1.25
+    >>> quantize(1.3, 4, overflow=Overflow.SATURATION)  # use saturation
+    0.9375
+    >>> quantize(0.3, 4, -1)  # Three bits in total, will overflow
+    -0.25
+
+    """
+    if isinstance(value, complex):
+        return complex(
+            quantize(
+                value.real,
+                fractional_bits=fractional_bits,
+                integer_bits=integer_bits,
+                quantization=quantization,
+                overflow=overflow,
+            ),
+            quantize(
+                value.imag,
+                fractional_bits=fractional_bits,
+                integer_bits=integer_bits,
+                quantization=quantization,
+                overflow=overflow,
+            ),
+        )
+    b = 2**fractional_bits
+    v = b * value
+    if quantization is Quantization.TRUNCATION:
+        v = math.floor(v)
+    elif quantization is Quantization.ROUNDING:
+        v = math.floor(v + 0.5)
+    elif quantization is Quantization.MAGNITUDE_TRUNCATION:
+        if v >= 0:
+            v = math.floor(v)
+        else:
+            v = math.ceil(v)
+    elif quantization is Quantization.JAMMING:
+        v = math.floor(v) | 1
+    else:  # Quantization.UNBIASED_ROUNDING
+        v = round(v)
+
+    v = v / b
+    i = 2 ** (integer_bits - 1)
+    if overflow is Overflow.SATURATION:
+        pos_val = i - 1 / b
+        neg_val = -i
+        v = max(neg_val, min(v, pos_val))
+    else:  # Overflow.TWOS_COMPLEMENT
+        v = (v + i) % (2 * i) - i
+
+    return v
diff --git a/docs_sphinx/api/index.rst b/docs_sphinx/api/index.rst
index 35981a0622ae7aea46d716266c731f2542d2e8a4..bb4c23eb7f194358c4403546ed49bde56be91229 100644
--- a/docs_sphinx/api/index.rst
+++ b/docs_sphinx/api/index.rst
@@ -10,6 +10,7 @@ API
     operation.rst
     port.rst
     process.rst
+    quantization.rst
     resources.rst
     save_load_structure.rst
     schedule.rst
diff --git a/docs_sphinx/api/quantization.rst b/docs_sphinx/api/quantization.rst
new file mode 100644
index 0000000000000000000000000000000000000000..5a50b8b05ac19500a1db7819953b3d75716e8087
--- /dev/null
+++ b/docs_sphinx/api/quantization.rst
@@ -0,0 +1,7 @@
+***********************
+``b_asic.quantization``
+***********************
+
+.. automodule:: b_asic.quantization
+   :members:
+   :undoc-members:
diff --git a/test/test_quantization.py b/test/test_quantization.py
new file mode 100644
index 0000000000000000000000000000000000000000..2923787bfc9e51ba95f0b6dba70e99c47625067f
--- /dev/null
+++ b/test/test_quantization.py
@@ -0,0 +1,28 @@
+from b_asic.quantization import Overflow, Quantization, quantize
+
+
+def test_quantization():
+    a = 0.3
+    assert quantize(a, 4) == 0.25
+    assert quantize(a, 4, quantization=Quantization.TRUNCATION) == 0.25
+    assert quantize(a, 4, quantization=Quantization.ROUNDING) == 0.3125
+    assert quantize(a, 4, quantization=Quantization.MAGNITUDE_TRUNCATION) == 0.25
+    assert quantize(a, 4, quantization=Quantization.JAMMING) == 0.3125
+    assert quantize(-a, 4, quantization=Quantization.TRUNCATION) == -0.3125
+    assert quantize(-a, 4, quantization=Quantization.ROUNDING) == -0.3125
+    assert quantize(-a, 4, quantization=Quantization.MAGNITUDE_TRUNCATION) == -0.25
+    assert quantize(-a, 4, quantization=Quantization.JAMMING) == -0.3125
+    assert quantize(complex(a, -a), 4) == complex(0.25, -0.3125)
+    assert quantize(
+        complex(a, -a), 4, quantization=Quantization.MAGNITUDE_TRUNCATION
+    ) == complex(0.25, -0.25)
+
+    assert quantize(1.3, 4) == -0.75
+    assert quantize(1.3, 4, overflow=Overflow.SATURATION) == 0.9375
+    assert quantize(0.97, 4, quantization=Quantization.ROUNDING) == -1.0
+    assert (
+        quantize(
+            0.97, 4, quantization=Quantization.ROUNDING, overflow=Overflow.SATURATION
+        )
+        == 0.9375
+    )