Repository: apytypes/apytypes (language: python)

Issue:
Enable only providing one argument to cast
If there is only one word length that we want to change use the other word length. Below is my suggestion how to handle fixed-point. Floating-point is more direct. 

For fixed-point (this should be documented):
* `bits` => keep fractional bits(?)
* `int_bits` => keep fractional bits
* `frac_bits` => keep integer bits


Discussion / hints:

Fix patch:
diff --git a/benchmark/ci_fixed_array_benchmarks.py b/benchmark/ci_fixed_array_benchmarks.py
index 71ce1e30d..4bb074470 100644
--- a/benchmark/ci_fixed_array_benchmarks.py
+++ b/benchmark/ci_fixed_array_benchmarks.py
@@ -4,123 +4,123 @@
 
 
 def test_fixed_matrix_multiplication_20(benchmark):
-    a = APyFixedArray.from_float(np.random.rand(20, 20) - 0.5, 19, 1)
-    b = APyFixedArray.from_float(np.random.rand(20, 20) - 0.5, 19, 1)
+    a = APyFixedArray.from_float(np.random.rand(20, 20) - 0.5, bits=19, int_bits=1)
+    b = APyFixedArray.from_float(np.random.rand(20, 20) - 0.5, bits=19, int_bits=1)
 
     benchmark(lambda x, y: x @ y, a, b)
 
 
 # def test_fixed_matrix_multiplication_200(benchmark):
-#     a = APyFixedArray.from_float(np.random.rand(200, 200), 19, 1)
-#     b = APyFixedArray.from_float(np.random.rand(200, 200), 19, 1)
+#     a = APyFixedArray.from_float(np.random.rand(200, 200), bits=19, int_bits=1)
+#     b = APyFixedArray.from_float(np.random.rand(200, 200), bits=19, int_bits=1)
 
 #     benchmark(lambda x, y: x @ y, a, b)
 
 
 def test_fixed_matrix_addition_20(benchmark):
-    a = APyFixedArray.from_float(np.random.rand(20, 20) - 0.5, 19, 1)
-    b = APyFixedArray.from_float(np.random.rand(20, 20) - 0.5, 19, 1)
+    a = APyFixedArray.from_float(np.random.rand(20, 20) - 0.5, bits=19, int_bits=1)
+    b = APyFixedArray.from_float(np.random.rand(20, 20) - 0.5, bits=19, int_bits=1)
 
     benchmark(lambda x, y: x + y, a, b)
 
 
 def test_fixed_matrix_addition_200(benchmark):
-    a = APyFixedArray.from_float(np.random.rand(200, 200) - 0.5, 19, 1)
-    b = APyFixedArray.from_float(np.random.rand(200, 200) - 0.5, 19, 1)
+    a = APyFixedArray.from_float(np.random.rand(200, 200) - 0.5, bits=19, int_bits=1)
+    b = APyFixedArray.from_float(np.random.rand(200, 200) - 0.5, bits=19, int_bits=1)
 
     benchmark(lambda x, y: x + y, a, b)
 
 
 def test_fixed_matrix_addition_long_200(benchmark):
-    a = APyFixedArray.from_float(np.random.rand(200, 200) - 0.5, 200, 1)
-    b = APyFixedArray.from_float(np.random.rand(200, 200) - 0.5, 200, 1)
+    a = APyFixedArray.from_float(np.random.rand(200, 200) - 0.5, bits=200, int_bits=1)
+    b = APyFixedArray.from_float(np.random.rand(200, 200) - 0.5, bits=200, int_bits=1)
 
     benchmark(lambda x, y: x + y, a, b)
 
 
 def test_fixed_matrix_addition_different_wl_long_200(benchmark):
-    a = APyFixedArray.from_float(np.random.rand(200, 200) - 0.5, 200, 1)
-    b = APyFixedArray.from_float(np.random.rand(200, 200) - 0.5, 167, 13)
+    a = APyFixedArray.from_float(np.random.rand(200, 200) - 0.5, bits=200, int_bits=1)
+    b = APyFixedArray.from_float(np.random.rand(200, 200) - 0.5, bits=167, int_bits=13)
 
     benchmark(lambda x, y: x + y, a, b)
 
 
 def test_fixed_matrix_addition_20_different_wl(benchmark):
-    a = APyFixedArray.from_float(np.random.rand(20, 20) - 0.5, 19, 1)
-    b = APyFixedArray.from_float(np.random.rand(20, 20) - 0.5, 15, 3)
+    a = APyFixedArray.from_float(np.random.rand(20, 20) - 0.5, bits=19, int_bits=1)
+    b = APyFixedArray.from_float(np.random.rand(20, 20) - 0.5, bits=15, int_bits=3)
 
     benchmark(lambda x, y: x + y, a, b)
 
 
 def test_fixed_matrix_addition_200_different_wl(benchmark):
-    a = APyFixedArray.from_float(np.random.rand(200, 200) - 0.5, 19, 1)
-    b = APyFixedArray.from_float(np.random.rand(200, 200) - 0.5, 15, 3)
+    a = APyFixedArray.from_float(np.random.rand(200, 200) - 0.5, bits=19, int_bits=1)
+    b = APyFixedArray.from_float(np.random.rand(200, 200) - 0.5, bits=15, int_bits=3)
 
     benchmark(lambda x, y: x + y, a, b)
 
 
 def test_fixed_matrix_elementwise_multiplication_20(benchmark):
-    a = APyFixedArray.from_float(np.random.rand(20, 20) - 0.5, 19, 1)
-    b = APyFixedArray.from_float(np.random.rand(20, 20) - 0.5, 19, 1)
+    a = APyFixedArray.from_float(np.random.rand(20, 20) - 0.5, bits=19, int_bits=1)
+    b = APyFixedArray.from_float(np.random.rand(20, 20) - 0.5, bits=19, int_bits=1)
 
     benchmark(lambda x, y: x * y, a, b)
 
 
 def test_fixed_matrix_elementwise_multiplication_200(benchmark):
-    a = APyFixedArray.from_float(np.random.rand(200, 200) - 0.5, 19, 1)
-    b = APyFixedArray.from_float(np.random.rand(200, 200) - 0.5, 19, 1)
+    a = APyFixedArray.from_float(np.random.rand(200, 200) - 0.5, bits=19, int_bits=1)
+    b = APyFixedArray.from_float(np.random.rand(200, 200) - 0.5, bits=19, int_bits=1)
 
     benchmark(lambda x, y: x * y, a, b)
 
 
 def test_fixed_matrix_negation_20(benchmark):
-    a = APyFixedArray.from_float(np.random.rand(20, 20) - 0.5, 19, 1)
+    a = APyFixedArray.from_float(np.random.rand(20, 20) - 0.5, bits=19, int_bits=1)
 
     benchmark(lambda x: -x, a)
 
 
 def test_fixed_matrix_negation_200(benchmark):
-    a = APyFixedArray.from_float(np.random.rand(200, 200) - 0.5, 19, 1)
+    a = APyFixedArray.from_float(np.random.rand(200, 200) - 0.5, bits=19, int_bits=1)
 
     benchmark(lambda x: -x, a)
 
 
 def test_fixed_matrix_abs_20(benchmark):
-    a = APyFixedArray.from_float(np.random.rand(20, 20) - 0.5, 19, 1)
+    a = APyFixedArray.from_float(np.random.rand(20, 20) - 0.5, bits=19, int_bits=1)
 
     benchmark(abs, a)
 
 
 def test_fixed_matrix_abs_200(benchmark):
-    a = APyFixedArray.from_float(np.random.rand(200, 200), 19, 1)
+    a = APyFixedArray.from_float(np.random.rand(200, 200), bits=19, int_bits=1)
 
     benchmark(abs, a)
 
 
 def test_fixed_scalar_matrix_addition_20(benchmark):
-    a = APyFixedArray.from_float(np.random.rand(20, 20), 19, 1)
-    b = APyFixed.from_float(np.random.rand(1)[0], 19, 1)
+    a = APyFixedArray.from_float(np.random.rand(20, 20), bits=19, int_bits=1)
+    b = APyFixed.from_float(np.random.rand(1)[0], bits=19, int_bits=1)
 
     benchmark(lambda x, y: x + y, a, b)
 
 
 def test_fixed_scalar_matrix_addition_200(benchmark):
-    a = APyFixedArray.from_float(np.random.rand(200, 200), 19, 1)
-    b = APyFixed.from_float(np.random.rand(1)[0], 19, 1)
+    a = APyFixedArray.from_float(np.random.rand(200, 200), bits=19, int_bits=1)
+    b = APyFixed.from_float(np.random.rand(1)[0], bits=19, int_bits=1)
 
     benchmark(lambda x, y: x + y, a, b)
 
 
 def test_fixed_scalar_matrix_multiplication_20(benchmark):
-    a = APyFixedArray.from_float(np.random.rand(20, 20), 19, 1)
-    b = APyFixed.from_float(np.random.rand(1)[0], 19, 1)
+    a = APyFixedArray.from_float(np.random.rand(20, 20), bits=19, int_bits=1)
+    b = APyFixed.from_float(np.random.rand(1)[0], bits=19, int_bits=1)
 
     benchmark(lambda x, y: x * y, a, b)
 
 
 def test_fixed_scalar_matrix_multiplication_200(benchmark):
-    a = APyFixedArray.from_float(np.random.rand(200, 200), 19, 1)
-    b = APyFixed.from_float(np.random.rand(1)[0], 19, 1)
+    a = APyFixedArray.from_float(np.random.rand(200, 200), bits=19, int_bits=1)
+    b = APyFixed.from_float(np.random.rand(1)[0], bits=19, int_bits=1)
 
     benchmark(lambda x, y: x * y, a, b)
 
@@ -128,34 +128,34 @@ def test_fixed_scalar_matrix_multiplication_200(benchmark):
 def test_fixed_matrix_creation_20(benchmark):
     a = np.random.rand(20, 20)
 
-    benchmark(APyFixedArray.from_float, a, 19, 1)
+    benchmark(APyFixedArray.from_float, a, bits=19, int_bits=1)
 
 
 def test_fixed_matrix_creation_200(benchmark):
     a = np.random.rand(200, 200)
 
-    benchmark(APyFixedArray.from_float, a, 19, 1)
+    benchmark(APyFixedArray.from_float, a, bits=19, int_bits=1)
 
 
 def test_fixed_matrix_to_numpy_20(benchmark):
-    a = APyFixedArray.from_float(np.random.rand(20, 20), 19, 1)
+    a = APyFixedArray.from_float(np.random.rand(20, 20), bits=19, int_bits=1)
 
     benchmark(lambda x: x.to_numpy(), a)
 
 
 def test_fixed_matrix_to_numpy_200(benchmark):
-    a = APyFixedArray.from_float(np.random.rand(200, 200), 19, 1)
+    a = APyFixedArray.from_float(np.random.rand(200, 200), bits=19, int_bits=1)
 
     benchmark(lambda x: x.to_numpy(), a)
 
 
 def test_fixed_vector_sum_20(benchmark):
-    a = APyFixedArray.from_float(np.random.rand(20), 19, 1)
+    a = APyFixedArray.from_float(np.random.rand(20), bits=19, int_bits=1)
 
     benchmark(sum, a)
 
 
 def test_fixed_vector_max_20(benchmark):
-    a = APyFixedArray.from_float(np.random.rand(20), 19, 1)
+    a = APyFixedArray.from_float(np.random.rand(20), bits=19, int_bits=1)
 
     benchmark(max, a)
diff --git a/benchmark/ci_fixed_scalar_benchmarks.py b/benchmark/ci_fixed_scalar_benchmarks.py
index fe533a755..578fee3aa 100644
--- a/benchmark/ci_fixed_scalar_benchmarks.py
+++ b/benchmark/ci_fixed_scalar_benchmarks.py
@@ -4,71 +4,71 @@
 
 
 def test_fixed_scalar_multiplication_short(benchmark):
-    a = APyFixed.from_float(np.random.rand(1)[0] - 0.5, 20, 1)
-    b = APyFixed.from_float(np.random.rand(1)[0] - 0.5, 20, 1)
+    a = APyFixed.from_float(np.random.rand(1)[0] - 0.5, bits=20, int_bits=1)
+    b = APyFixed.from_float(np.random.rand(1)[0] - 0.5, bits=20, int_bits=1)
 
     benchmark(lambda x, y: x * y, a, b)
 
 
 def test_fixed_scalar_multiplication_long(benchmark):
-    a = APyFixed.from_float(np.random.rand(1)[0] - 0.5, 200, 1)
-    b = APyFixed.from_float(np.random.rand(1)[0] - 0.5, 200, 1)
+    a = APyFixed.from_float(np.random.rand(1)[0] - 0.5, bits=200, int_bits=1)
+    b = APyFixed.from_float(np.random.rand(1)[0] - 0.5, bits=200, int_bits=1)
 
     benchmark(lambda x, y: x * y, a, b)
 
 
 def test_fixed_scalar_multiplication_mixed(benchmark):
-    a = APyFixed.from_float(np.random.rand(1)[0] - 0.5, 20, 1)
-    b = APyFixed.from_float(np.random.rand(1)[0] - 0.5, 200, 1)
+    a = APyFixed.from_float(np.random.rand(1)[0] - 0.5, bits=20, int_bits=1)
+    b = APyFixed.from_float(np.random.rand(1)[0] - 0.5, bits=200, int_bits=1)
 
     benchmark(lambda x, y: x * y, a, b)
 
 
 def test_fixed_scalar_division_short(benchmark):
-    a = APyFixed.from_float(np.random.rand(1)[0] - 0.5, 20, 1)
-    b = APyFixed.from_float(np.random.rand(1)[0] - 0.5, 20, 1)
+    a = APyFixed.from_float(np.random.rand(1)[0] - 0.5, bits=20, int_bits=1)
+    b = APyFixed.from_float(np.random.rand(1)[0] - 0.5, bits=20, int_bits=1)
 
     benchmark(lambda x, y: x / y, a, b)
 
 
 def test_fixed_scalar_division_long(benchmark):
-    a = APyFixed.from_float(np.random.rand(1)[0] - 0.5, 200, 1)
-    b = APyFixed.from_float(np.random.rand(1)[0] - 0.5, 200, 1)
+    a = APyFixed.from_float(np.random.rand(1)[0] - 0.5, bits=200, int_bits=1)
+    b = APyFixed.from_float(np.random.rand(1)[0] - 0.5, bits=200, int_bits=1)
 
     benchmark(lambda x, y: x / y, a, b)
 
 
 def test_fixed_scalar_division_mixed(benchmark):
-    a = APyFixed.from_float(np.random.rand(1)[0] - 0.5, 20, 1)
-    b = APyFixed.from_float(np.random.rand(1)[0] - 0.5, 200, 1)
+    a = APyFixed.from_float(np.random.rand(1)[0] - 0.5, bits=20, int_bits=1)
+    b = APyFixed.from_float(np.random.rand(1)[0] - 0.5, bits=200, int_bits=1)
 
     benchmark(lambda x, y: x / y, a, b)
 
 
 def test_fixed_scalar_addition_short(benchmark):
-    a = APyFixed.from_float(np.random.rand(1)[0] - 0.5, 20, 1)
-    b = APyFixed.from_float(np.random.rand(1)[0] - 0.5, 20, 1)
+    a = APyFixed.from_float(np.random.rand(1)[0] - 0.5, bits=20, int_bits=1)
+    b = APyFixed.from_float(np.random.rand(1)[0] - 0.5, bits=20, int_bits=1)
 
     benchmark(lambda x, y: x + y, a, b)
 
 
 def test_fixed_scalar_addition_short_different_wl(benchmark):
-    a = APyFixed.from_float(np.random.rand(1)[0] - 0.5, 15, 3)
-    b = APyFixed.from_float(np.random.rand(1)[0] - 0.5, 20, 1)
+    a = APyFixed.from_float(np.random.rand(1)[0] - 0.5, bits=15, int_bits=3)
+    b = APyFixed.from_float(np.random.rand(1)[0] - 0.5, bits=20, int_bits=1)
 
     benchmark(lambda x, y: x + y, a, b)
 
 
 def test_fixed_scalar_addition_long(benchmark):
-    a = APyFixed.from_float(np.random.rand(1)[0] - 0.5, 200, 1)
-    b = APyFixed.from_float(np.random.rand(1)[0] - 0.5, 200, 1)
+    a = APyFixed.from_float(np.random.rand(1)[0] - 0.5, bits=200, int_bits=1)
+    b = APyFixed.from_float(np.random.rand(1)[0] - 0.5, bits=200, int_bits=1)
 
     benchmark(lambda x, y: x + y, a, b)
 
 
 def test_fixed_scalar_addition_mixed(benchmark):
-    a = APyFixed.from_float(np.random.rand(1)[0] - 0.5, 20, 1)
-    b = APyFixed.from_float(np.random.rand(1)[0] - 0.5, 200, 1)
+    a = APyFixed.from_float(np.random.rand(1)[0] - 0.5, bits=20, int_bits=1)
+    b = APyFixed.from_float(np.random.rand(1)[0] - 0.5, bits=200, int_bits=1)
 
     benchmark(lambda x, y: x + y, a, b)
 
@@ -76,40 +76,40 @@ def test_fixed_scalar_addition_mixed(benchmark):
 def test_fixed_scalar_creation_short(benchmark):
     a = np.random.rand(1)[0] - 0.5
 
-    benchmark(APyFixed.from_float, a, 20, 1)
+    benchmark(APyFixed.from_float, a, bits=20, int_bits=1)
 
 
 def test_fixed_scalar_creation_long(benchmark):
     a = np.random.rand(1)[0] - 0.5
 
-    benchmark(APyFixed.from_float, a, 200, 1)
+    benchmark(APyFixed.from_float, a, bits=200, int_bits=1)
 
 
 def test_fixed_scalar_to_float_short(benchmark):
-    a = APyFixed.from_float(np.random.rand(1)[0] - 0.5, 20, 1)
+    a = APyFixed.from_float(np.random.rand(1)[0] - 0.5, bits=20, int_bits=1)
 
     benchmark(float, a)
 
 
 def test_fixed_scalar_negation_short(benchmark):
-    a = APyFixed.from_float(np.random.rand(1)[0] - 0.5, 20, 1)
+    a = APyFixed.from_float(np.random.rand(1)[0] - 0.5, bits=20, int_bits=1)
 
     benchmark(lambda x: -x, a)
 
 
 def test_fixed_scalar_negation_long(benchmark):
-    a = APyFixed.from_float(np.random.rand(1)[0] - 0.5, 200, 1)
+    a = APyFixed.from_float(np.random.rand(1)[0] - 0.5, bits=200, int_bits=1)
 
     benchmark(lambda x: -x, a)
 
 
 def test_fixed_scalar_abs_short(benchmark):
-    a = APyFixed.from_float(np.random.rand(1)[0] - 0.5, 20, 1)
+    a = APyFixed.from_float(np.random.rand(1)[0] - 0.5, bits=20, int_bits=1)
 
     benchmark(abs, a)
 
 
 def test_fixed_scalar_abs_long(benchmark):
-    a = APyFixed.from_float(np.random.rand(1)[0] - 0.5, 200, 1)
+    a = APyFixed.from_float(np.random.rand(1)[0] - 0.5, bits=200, int_bits=1)
 
     benchmark(abs, a)
diff --git a/comparison/compare_apytypes.py b/comparison/compare_apytypes.py
index 1ecd4180f..8a50188f3 100644
--- a/comparison/compare_apytypes.py
+++ b/comparison/compare_apytypes.py
@@ -2,8 +2,8 @@
 
 
 def create_scalar(val, total_bits, integer_bits):
-    return APyFixed.from_float(val, total_bits, integer_bits)
+    return APyFixed.from_float(val, bits=total_bits, int_bits=integer_bits)
 
 
 def create_array(val, total_bits, integer_bits):
-    return APyFixedArray.from_float(val, total_bits, integer_bits)
+    return APyFixedArray.from_float(val, bits=total_bits, int_bits=integer_bits)
diff --git a/docs/_plots/overflow.py b/docs/_plots/overflow.py
index 3ebbbe668..e2fff846f 100644
--- a/docs/_plots/overflow.py
+++ b/docs/_plots/overflow.py
@@ -12,14 +12,14 @@
 ai = np.arange(-3, 2.1, 1)
 ah = np.arange(-2.5, 2.6, 1)
 bins = np.arange(-1, 1.1, 0.125)
-afx = APyFixedArray.from_float(a, 7, 4)
-aifx = APyFixedArray.from_float(ai, 7, 4)
-ahfx = APyFixedArray.from_float(ah, 7, 4)
+afx = APyFixedArray.from_float(a, int_bits=4, frac_bits=3)
+aifx = APyFixedArray.from_float(ai, int_bits=4, frac_bits=3)
+ahfx = APyFixedArray.from_float(ah, int_bits=4, frac_bits=3)
 
 for mode in modes:
     fig, ax = plt.subplots(layout="constrained", figsize=(8, 3.6))
-    aqfx = afx.cast(4, 1, overflow=eval(mode))
-    aiqfx = aifx.cast(4, 1, overflow=eval(mode))
+    aqfx = afx.cast(int_bits=1, frac_bits=3, overflow=eval(mode))
+    aiqfx = aifx.cast(int_bits=1, frac_bits=3, overflow=eval(mode))
     ax.set_aspect("equal")
     ax.plot((-3, 2.875), (-3, 2.875), "g")
     ax.plot(afx, aqfx, "o")
diff --git a/docs/_plots/performancescale.py b/docs/_plots/performancescale.py
index 4797ad5d1..265bcf657 100644
--- a/docs/_plots/performancescale.py
+++ b/docs/_plots/performancescale.py
@@ -1,9 +1,9 @@
 # %%
 import timeit
 
-CREATE_TWO_FIXED_VECTORS = "import numpy as np; a = APyFixedArray.from_float(np.random.rand({l}) - 0.5, 20, 10); b = APyFixedArray.from_float(np.random.rand({l}) - 0.5, 20, 10)"
-CREATE_TWO_LONG_FIXED_VECTORS = "import numpy as np; a = APyFixedArray.from_float(np.random.rand({l}) - 0.5, 300, 150); b = APyFixedArray.from_float(np.random.rand({l}) - 0.5, 300, 150)"
-CREATE_TWO_FIXED_VECTORS_DIFFERENT_WL = "import numpy as np; a = APyFixedArray.from_float(np.random.rand({l}) - 0.5, 32, 16); b = APyFixedArray.from_float(np.random.rand({l}) - 0.5, 12, 2)"
+CREATE_TWO_FIXED_VECTORS = "import numpy as np; a = APyFixedArray.from_float(np.random.rand({l}) - 0.5, int_bits=10, frac_bits=10); b = APyFixedArray.from_float(np.random.rand({l}) - 0.5, int_bits=10, frac_bits=10)"
+CREATE_TWO_LONG_FIXED_VECTORS = "import numpy as np; a = APyFixedArray.from_float(np.random.rand({l}) - 0.5, int_bits=150, frac_bits=150); b = APyFixedArray.from_float(np.random.rand({l}) - 0.5, int_bits=150, frac_bits=150)"
+CREATE_TWO_FIXED_VECTORS_DIFFERENT_WL = "import numpy as np; a = APyFixedArray.from_float(np.random.rand({l}) - 0.5, int_bits=16, frac_bits=16); b = APyFixedArray.from_float(np.random.rand({l}) - 0.5, int_bits=12, frac_bits=2)"
 CREATE_TWO_FLOAT_VECTORS = "import numpy as np; a = APyFloatArray.from_float(np.random.rand({l}) - 0.5, 5, 8); b = APyFloatArray.from_float(np.random.rand({l}) - 0.5, 5, 8)"
 benchmarks = {
     "Fixed-point addition, 20-bit": ("c = a + b", CREATE_TWO_FIXED_VECTORS),
diff --git a/docs/_plots/quantization.py b/docs/_plots/quantization.py
index dbd00685b..11b2c66c0 100644
--- a/docs/_plots/quantization.py
+++ b/docs/_plots/quantization.py
@@ -22,9 +22,9 @@
 ai = np.arange(-3, 2.1, 1)
 ah = np.arange(-2.5, 2.6, 1)
 bins = np.arange(-1, 1.1, 0.125)
-afx = APyFixedArray.from_float(a, 7, 4)
-aifx = APyFixedArray.from_float(ai, 7, 4)
-ahfx = APyFixedArray.from_float(ah, 7, 4)
+afx = APyFixedArray.from_float(a, int_bits=4, frac_bits=3)
+aifx = APyFixedArray.from_float(ai, int_bits=4, frac_bits=3)
+ahfx = APyFixedArray.from_float(ah, int_bits=4, frac_bits=3)
 fig, axs = plt.subplots(
     10,
     3,
@@ -33,9 +33,9 @@
     figsize=(8, 20),
 )
 for i, q in enumerate(modes):
-    aqfx = afx.cast(4, 4, eval(q))
-    aiqfx = aifx.cast(4, 4, eval(q))
-    ahqfx = ahfx.cast(4, 4, eval(q))
+    aqfx = afx.cast(int_bits=4, frac_bits=0, quantization=eval(q))
+    aiqfx = aifx.cast(int_bits=4, frac_bits=0, quantization=eval(q))
+    ahqfx = ahfx.cast(int_bits=4, frac_bits=0, quantization=eval(q))
     ax = axs[2 * (i // 3), i % 3]
     ax.set_aspect("equal")
     ax.plot((-3, 2.875), (-3, 2.875), "g")
@@ -78,9 +78,9 @@
 ai = np.arange(-4, 3.1, 1)
 ah = np.arange(-3.5, 3.6, 1)
 bins = np.arange(-1, 1.1, 0.125)
-afx = APyFixedArray.from_float(a, 7, 4)
-aifx = APyFixedArray.from_float(ai, 7, 4)
-ahfx = APyFixedArray.from_float(ah, 7, 4)
+afx = APyFixedArray.from_float(a, int_bits=4, frac_bits=3)
+aifx = APyFixedArray.from_float(ai, int_bits=4, frac_bits=3)
+ahfx = APyFixedArray.from_float(ah, int_bits=4, frac_bits=3)
 
 l = len(a) // 2
 for q in modes:
@@ -89,9 +89,9 @@
     fig.suptitle(name)
     gs = gridspec.GridSpec(3, 2, figure=fig)
     ax = fig.add_subplot(gs[:, 0])
-    aqfx = afx.cast(4, 4, eval(q))
-    aiqfx = aifx.cast(4, 4, eval(q))
-    ahqfx = ahfx.cast(4, 4, eval(q))
+    aqfx = afx.cast(int_bits=4, frac_bits=0, quantization=eval(q))
+    aiqfx = aifx.cast(int_bits=4, frac_bits=0, quantization=eval(q))
+    ahqfx = ahfx.cast(int_bits=4, frac_bits=0, quantization=eval(q))
     ax.set_aspect("equal")
     ax.plot((-4, 3.875), (-4, 3.875), "g")
     ax.plot(afx, aqfx, "o")
diff --git a/docs/performance.rst b/docs/performance.rst
index 9be4f6eec..1e75feb2f 100644
--- a/docs/performance.rst
+++ b/docs/performance.rst
@@ -39,6 +39,6 @@ use inplace shifting if possible.
 
 .. code-block:: Python
 
-    a = APyFixed(5, 6, 4)
+    a = APyFixed(5, bits=6, int_bits=4)
     a = a >> 1   # slower
     a >>= 1   # faster
diff --git a/lib/apytypes/_apytypes.pyi b/lib/apytypes/_apytypes.pyi
index 0a3aed5c2..0c8283846 100644
--- a/lib/apytypes/_apytypes.pyi
+++ b/lib/apytypes/_apytypes.pyi
@@ -33,9 +33,9 @@ class APyFixed:
     @staticmethod
     def from_float(
         value: float,
-        bits: int | None = None,
         int_bits: int | None = None,
         frac_bits: int | None = None,
+        bits: int | None = None,
     ) -> APyFixed:
         """
         Create an :class:`APyFixed` object from :class:`float`.
@@ -51,12 +51,12 @@ class APyFixed:
         ----------
         value : float
             Floating point value to initialize from
-        bits : int, optional
-            Total number of bits in the created fixed-point object
         int_bits : int, optional
             Number of integer bits in the created fixed-point object
         frac_bits : int, optional
             Number of fractional bits in the created fixed-point object
+        bits : int, optional
+            Total number of bits in the created fixed-point object
 
         Examples
         --------
@@ -72,10 +72,10 @@ class APyFixed:
     @staticmethod
     def from_str(
         string_value: str,
-        bits: int | None = None,
         int_bits: int | None = None,
-        base: int = 10,
         frac_bits: int | None = None,
+        base: int = 10,
+        bits: int | None = None,
     ) -> APyFixed:
         """
         Create an :class:`APyFixed` object from :class:`str`.
@@ -87,14 +87,14 @@ class APyFixed:
         ----------
         string_value : str
             String to initialize the value from
-        bits : int, optional
-            Total number of bits in the created fixed-point object
         int_bits : int, optional
             Number of integer bits in the created fixed-point object
-        base : int, default: 10
-            Numeric base used in `string_value`
         frac_bits : int, optional
             Number of fractional bits in the created fixed-point object
+        base : int, default: 10
+            Numeric base used in `string_value`
+        bits : int, optional
+            Total number of bits in the created fixed-point object
 
         Examples
         --------
@@ -137,9 +137,9 @@ class APyFixed:
     def __init__(
         self,
         bit_pattern: int,
-        bits: int | None = None,
         int_bits: int | None = None,
         frac_bits: int | None = None,
+        bits: int | None = None,
     ) -> None: ...
     @typing.overload
     def __le__(self, arg0: APyFixed) -> bool: ...
@@ -176,11 +176,11 @@ class APyFixed:
     def _repr_latex_(self) -> str: ...
     def cast(
         self,
-        bits: int | None = None,
         int_bits: int | None = None,
-        quantization: QuantizationMode = None,
-        overflow: OverflowMode = None,
         frac_bits: int | None = None,
+        quantization: QuantizationMode | None = None,
+        overflow: OverflowMode | None = None,
+        bits: int | None = None,
     ) -> APyFixed:
         """
         Create a new resized fixed-point number based on the bit pattern in this
@@ -194,16 +194,16 @@ class APyFixed:
 
         Parameters
         ----------
-        bits : int, optional
-            Total number of bits in the created fixed-point object
         int_bits : int, optional
             Number of integer bits in the created fixed-point object
-        quantization : :class:`QuantizationMode`, default: :class:`QuantizationMode.TRN`
-            Quantization mode to use in this cast
-        overflow : :class:`OverflowMode`, default: :class:`OverflowMode.WRAP`
-            Overflowing mode to use in this cast
         frac_bits : int, optional
             Number of fractional bits in the created fixed-point object
+        quantization : :class:`QuantizationMode`, optional
+            Quantization mode to use in this cast
+        overflow : :class:`OverflowMode`, optional
+            Overflowing mode to use in this cast
+        bits : int, optional
+            Total number of bits in the created fixed-point object
 
         Returns
         -------
@@ -367,9 +367,9 @@ class APyFixedArray:
     @staticmethod
     def from_float(
         float_sequence: typing.Sequence,
-        bits: int | None = None,
         int_bits: int | None = None,
         frac_bits: int | None = None,
+        bits: int | None = None,
     ) -> APyFixedArray:
         """
         Create an :class:`APyFixedArray` object from a sequence of :class:`float`.
@@ -383,12 +383,12 @@ class APyFixedArray:
         float_sequence : sequence of float
             Floating point values to initialize from. The tensor shape will be taken
             from the sequence shape.
-        bits : int, optional
-            Total number of bits in the created fixed-point tensor
         int_bits : int, optional
             Number of integer bits in the created fixed-point tensor
         frac_bits : int, optional
             Number of fractional bits in the created fixed-point tensor
+        bits : int, optional
+            Total number of bits in the created fixed-point tensor
 
         Returns
         -------
@@ -429,9 +429,9 @@ class APyFixedArray:
     def __init__(
         self,
         bit_pattern_sequence: typing.Sequence,
-        bits: int | None = None,
         int_bits: int | None = None,
         frac_bits: int | None = None,
+        bits: int | None = None,
     ) -> None: ...
     def __iter__(self) -> APyFixedArrayIterator: ...
     def __len__(self) -> int: ...
@@ -478,11 +478,11 @@ class APyFixedArray:
     def __truediv__(self, arg0: APyFixed) -> APyFixedArray: ...
     def cast(
         self,
-        bits: int | None = None,
         int_bits: int | None = None,
-        quantization: QuantizationMode = None,
-        overflow: OverflowMode = None,
         frac_bits: int | None = None,
+        quantization: QuantizationMode | None = None,
+        overflow: OverflowMode | None = None,
+        bits: int | None = None,
     ) -> APyFixedArray:
         """
         Create a new resized fixed-point array based on the bit pattern in this
@@ -496,16 +496,16 @@ class APyFixedArray:
 
         Parameters
         ----------
-        bits : int, optional
-            Total number of bits in the created fixed-point array.
         int_bits : int, optional
             Number of integer bits in the created fixed-point array-
-        quantization : :class:`QuantizationMode`, default: :class:`QuantizationMode.TRN`
-            Quantization mode to use in this cast.
-        overflow : :class:`OverflowMode`, default: :class:`OverflowMode.WRAP`
-            Overflowing mode to use in this cast.
         frac_bits : int, optional
             Number of fractional bits in the created fixed-point array.
+        quantization : :class:`QuantizationMode`, optional
+            Quantization mode to use in this cast.
+        overflow : :class:`OverflowMode`, optional
+            Overflowing mode to use in this cast.
+        bits : int, optional
+            Total number of bits in the created fixed-point array.
 
         Returns
         -------
@@ -1241,11 +1241,11 @@ class APyFixedAccumulatorContext(ContextManager):
     def __init__(
         self,
         *,
-        bits: int | None = None,
         int_bits: int | None = None,
         frac_bits: int | None = None,
         quantization: QuantizationMode | None = None,
         overflow: OverflowMode | None = None,
+        bits: int | None = None,
     ) -> None: ...
 
 class APyFixedCastContext(ContextManager):
diff --git a/meson.build b/meson.build
index f58ffbbe9..d9f0a4454 100644
--- a/meson.build
+++ b/meson.build
@@ -17,7 +17,13 @@ nanobind_dep = dependency('nanobind')
 cmake = import('cmake')
 cmake_opts = cmake.subproject_options()
 if get_option('buildtype') == 'release'
-    cmake_opts.add_cmake_defines({'CMAKE_BUILD_TYPE': 'Release', 'HWY_ENABLE_TESTS' : 'OFF', 'HWY_ENABLE_CONTRIB' : 'OFF', 'HWY_ENABLE_INSTALL' : 'OFF', 'HWY_ENABLE_EXAMPLES' : 'OFF'})
+    cmake_opts.add_cmake_defines({
+      'CMAKE_BUILD_TYPE'    : 'Release',
+      'HWY_ENABLE_TESTS'    : 'OFF',
+      'HWY_ENABLE_CONTRIB'  : 'OFF',
+      'HWY_ENABLE_INSTALL'  : 'OFF',
+      'HWY_ENABLE_EXAMPLES' : 'OFF'
+    })
 endif
 
 hwy = cmake.subproject('highway', options: cmake_opts)
diff --git a/src/apyfixed.cc b/src/apyfixed.cc
index 42a593955..7361de5c8 100644
--- a/src/apyfixed.cc
+++ b/src/apyfixed.cc
@@ -47,11 +47,11 @@ APyFixed::APyFixed(const APyFixed& other)
 
 APyFixed::APyFixed(
     nb::int_ python_long_int_bit_pattern,
-    std::optional<int> bits,
     std::optional<int> int_bits,
-    std::optional<int> frac_bits
+    std::optional<int> frac_bits,
+    std::optional<int> bits
 )
-    : APyFixed(bits, int_bits, frac_bits)
+    : APyFixed(int_bits, frac_bits, bits)
 {
     _data = python_long_to_limb_vec(python_long_int_bit_pattern, _data.size());
     _overflow_twos_complement(_data.begin(), _data.end(), _bits, _int_bits);
@@ -62,7 +62,7 @@ APyFixed::APyFixed(
  * ********************************************************************************** */
 
 APyFixed::APyFixed(
-    std::optional<int> bits, std::optional<int> int_bits, std::optional<int> frac_bits
+    std::optional<int> int_bits, std::optional<int> frac_bits, std::optional<int> bits
 )
     : _bits { bits_from_optional(bits, int_bits, frac_bits) }
     , _int_bits { int_bits.has_value() ? *int_bits : *bits - *frac_bits }
@@ -897,25 +897,25 @@ bool APyFixed::positive_greater_than_equal_pow2(int n) const
 
 APyFixed APyFixed::from_double(
     double value,
-    std::optional<int> bits,
     std::optional<int> int_bits,
-    std::optional<int> frac_bits
+    std::optional<int> frac_bits,
+    std::optional<int> bits
 )
 {
-    APyFixed result(bits, int_bits, frac_bits);
+    APyFixed result(int_bits, frac_bits, bits);
     result.set_from_double(value);
     return result;
 }
 
 APyFixed APyFixed::from_string(
     std::string string_value,
-    std::optional<int> bits,
     std::optional<int> int_bits,
+    std::optional<int> frac_bits,
     int base,
-    std::optional<int> frac_bits
+    std::optional<int> bits
 )
 {
-    APyFixed result(bits, int_bits, frac_bits);
+    APyFixed result(int_bits, frac_bits, bits);
     result.set_from_string(string_value, base);
     return result;
 }
@@ -925,16 +925,16 @@ APyFixed APyFixed::from_string(
  * ********************************************************************************** */
 
 APyFixed APyFixed::cast(
-    std::optional<int> bits,
     std::optional<int> int_bits,
+    std::optional<int> frac_bits,
     std::optional<QuantizationMode> quantization,
     std::optional<OverflowMode> overflow,
-    std::optional<int> frac_bits
+    std::optional<int> bits
 ) const
 {
-    // Sanitize the input (bit-specifier validity tested in `bits_from_optional()`)
-    int new_bits = bits_from_optional(bits, int_bits, frac_bits);
-    int new_int_bits = int_bits.has_value() ? *int_bits : *bits - *frac_bits;
+    // Sanitize the input (bit-specifier validity tested in `bits_from_optional_cast()`)
+    const auto [new_bits, new_int_bits]
+        = bits_from_optional_cast(bits, int_bits, frac_bits, _bits, _int_bits);
 
     const APyFixedCastOption cast_option = get_fixed_cast_mode();
     const auto quantization_mode = quantization.value_or(cast_option.quantization);
diff --git a/src/apyfixed.h b/src/apyfixed.h
index 997089498..84b48e9a1 100644
--- a/src/apyfixed.h
+++ b/src/apyfixed.h
@@ -68,9 +68,9 @@ class APyFixed {
     //! Main Python-exposed `APyFixed` constructor
     explicit APyFixed(
         nanobind::int_ python_long_int_bit_pattern,
-        std::optional<int> bits = std::nullopt,
         std::optional<int> int_bits = std::nullopt,
-        std::optional<int> frac_bits = std::nullopt
+        std::optional<int> frac_bits = std::nullopt,
+        std::optional<int> bits = std::nullopt
     );
 
     /* ****************************************************************************** *
@@ -90,9 +90,9 @@ class APyFixed {
     //! `int_bits`, `frac_bits`) are set, or if the resulting number of `bits` is less
     //! than one.
     explicit APyFixed(
-        std::optional<int> bits = std::nullopt,
         std::optional<int> int_bits = std::nullopt,
-        std::optional<int> frac_bits = std::nullopt
+        std::optional<int> frac_bits = std::nullopt,
+        std::optional<int> bits = std::nullopt
     );
 
     //! Construct a number with `bits` and `int_bits`, and initialize underlying
@@ -247,18 +247,18 @@ class APyFixed {
     //! Create APyFixed from double.
     static APyFixed from_double(
         double value,
-        std::optional<int> bits = std::nullopt,
         std::optional<int> int_bits = std::nullopt,
-        std::optional<int> frac_bits = std::nullopt
+        std::optional<int> frac_bits = std::nullopt,
+        std::optional<int> bits = std::nullopt
     );
 
     //! Create APyFixed from string.
     static APyFixed from_string(
         std::string string_value,
-        std::optional<int> bits = std::nullopt,
         std::optional<int> int_bits = std::nullopt,
+        std::optional<int> frac_bits = std::nullopt,
         int base = 10,
-        std::optional<int> frac_bits = std::nullopt
+        std::optional<int> bits = std::nullopt
     );
 
     /* ****************************************************************************** *
@@ -268,11 +268,11 @@ class APyFixed {
 public:
     //! Publicly exposed cast method
     APyFixed cast(
-        std::optional<int> bits = std::nullopt,
         std::optional<int> int_bits = std::nullopt,
+        std::optional<int> frac_bits = std::nullopt,
         std::optional<QuantizationMode> quantization = std::nullopt,
         std::optional<OverflowMode> overflow = std::nullopt,
-        std::optional<int> frac_bits = std::nullopt
+        std::optional<int> bits = std::nullopt
     ) const;
 
     //! Simplified cast methods for internal use when it is known that the result will
diff --git a/src/apyfixed_wrapper.cc b/src/apyfixed_wrapper.cc
index 4b0220b60..e22e49e4a 100644
--- a/src/apyfixed_wrapper.cc
+++ b/src/apyfixed_wrapper.cc
@@ -21,9 +21,9 @@ void bind_fixed(nb::module_& m)
                 std::optional<int>,
                 std::optional<int>>(),
             nb::arg("bit_pattern"),
-            nb::arg("bits") = nb::none(),
             nb::arg("int_bits") = nb::none(),
-            nb::arg("frac_bits") = nb::none()
+            nb::arg("frac_bits") = nb::none(),
+            nb::arg("bits") = nb::none()
         )
 
         /*
@@ -165,11 +165,11 @@ void bind_fixed(nb::module_& m)
         .def(
             "cast",
             &APyFixed::cast,
-            nb::arg("bits") = nb::none(),
             nb::arg("int_bits") = nb::none(),
+            nb::arg("frac_bits") = nb::none(),
             nb::arg("quantization") = nb::none(),
             nb::arg("overflow") = nb::none(),
-            nb::arg("frac_bits") = nb::none(),
+            nb::arg("bits") = nb::none(),
             R"pbdoc(
             Change format of the fixed-point number.
 
@@ -181,16 +181,16 @@ void bind_fixed(nb::module_& m)
 
             Parameters
             ----------
-            bits : int, optional
-                Total number of bits in the result.
             int_bits : int, optional
                 Number of integer bits in the result.
-            quantization : :class:`QuantizationMode`, default: :class:`QuantizationMode.TRN`
-                Quantization mode to use in this cast.
-            overflow : :class:`OverflowMode`, default: :class:`OverflowMode.WRAP`
-                Overflowing mode to use in this cast.
             frac_bits : int, optional
                 Number of fractional bits in the result.
+            quantization : :class:`QuantizationMode`, optional
+                Quantization mode to use in this cast.
+            overflow : :class:`OverflowMode`, optional
+                Overflowing mode to use in this cast.
+            bits : int, optional
+                Total number of bits in the result.
 
             Returns
             -------
@@ -291,9 +291,9 @@ void bind_fixed(nb::module_& m)
             "from_float",
             &APyFixed::from_double,
             nb::arg("value"),
-            nb::arg("bits") = nb::none(),
             nb::arg("int_bits") = nb::none(),
             nb::arg("frac_bits") = nb::none(),
+            nb::arg("bits") = nb::none(),
             R"pbdoc(
             Create an :class:`APyFixed` object from :class:`float`.
 
@@ -308,12 +308,12 @@ void bind_fixed(nb::module_& m)
             ----------
             value : float
                 Floating point value to initialize from
-            bits : int, optional
-                Total number of bits in the created fixed-point object
             int_bits : int, optional
                 Number of integer bits in the created fixed-point object
             frac_bits : int, optional
                 Number of fractional bits in the created fixed-point object
+            bits : int, optional
+                Total number of bits in the created fixed-point object
 
             Examples
             --------
@@ -330,10 +330,10 @@ void bind_fixed(nb::module_& m)
             "from_str",
             &APyFixed::from_string,
             nb::arg("string_value"),
-            nb::arg("bits") = nb::none(),
             nb::arg("int_bits") = nb::none(),
-            nb::arg("base") = 10,
             nb::arg("frac_bits") = nb::none(),
+            nb::arg("base") = 10,
+            nb::arg("bits") = nb::none(),
             R"pbdoc(
             Create an :class:`APyFixed` object from :class:`str`.
 
@@ -344,14 +344,14 @@ void bind_fixed(nb::module_& m)
             ----------
             string_value : str
                 String to initialize the value from
-            bits : int, optional
-                Total number of bits in the created fixed-point object
             int_bits : int, optional
                 Number of integer bits in the created fixed-point object
-            base : int, default: 10
-                Numeric base used in `string_value`
             frac_bits : int, optional
                 Number of fractional bits in the created fixed-point object
+            base : int, default: 10
+                Numeric base used in `string_value`
+            bits : int, optional
+                Total number of bits in the created fixed-point object
 
             Examples
             --------
diff --git a/src/apyfixedarray.cc b/src/apyfixedarray.cc
index 4cb04598d..a9ec9209c 100644
--- a/src/apyfixedarray.cc
+++ b/src/apyfixedarray.cc
@@ -40,12 +40,12 @@ namespace nb = nanobind;
 
 APyFixedArray::APyFixedArray(
     const nb::sequence& bit_pattern_sequence,
-    std::optional<int> bits,
     std::optional<int> int_bits,
-    std::optional<int> frac_bits
+    std::optional<int> frac_bits,
+    std::optional<int> bits
 )
     : APyFixedArray(
-          python_sequence_extract_shape(bit_pattern_sequence), bits, int_bits, frac_bits
+          python_sequence_extract_shape(bit_pattern_sequence), int_bits, frac_bits, bits
       )
 {
     // Specialized initialization for NumPy ndarrays
@@ -84,11 +84,20 @@ APyFixedArray::APyFixedArray(
  * *                       More C++ accessible constructors                         * *
  * ********************************************************************************** */
 
+APyFixedArray::APyFixedArray(
+    const std::vector<std::size_t>& shape, int bits, int int_bits
+)
+    : APyBuffer(shape, bits_to_limbs(bits))
+    , _bits { bits }
+    , _int_bits { int_bits }
+{
+}
+
 APyFixedArray::APyFixedArray(
     const std::vector<std::size_t>& shape,
-    std::optional<int> bits,
     std::optional<int> int_bits,
-    std::optional<int> frac_bits
+    std::optional<int> frac_bits,
+    std::optional<int> bits
 )
     : APyBuffer(shape, bits_to_limbs(bits_from_optional(bits, int_bits, frac_bits)))
     , _bits { bits.has_value() ? *bits : *int_bits + *frac_bits }
@@ -917,16 +926,16 @@ bool APyFixedArray::is_identical(const APyFixedArray& other) const
 }
 
 APyFixedArray APyFixedArray::cast(
-    std::optional<int> bits,
     std::optional<int> int_bits,
+    std::optional<int> frac_bits,
     std::optional<QuantizationMode> quantization,
     std::optional<OverflowMode> overflow,
-    std::optional<int> frac_bits
+    std::optional<int> bits
 ) const
 {
     // Sanitize the input (bit-specifier validity tested in `bits_from_optional()`)
-    int new_bits = bits_from_optional(bits, int_bits, frac_bits);
-    int new_int_bits = int_bits.has_value() ? *int_bits : *bits - *frac_bits;
+    const auto [new_bits, new_int_bits]
+        = bits_from_optional_cast(bits, int_bits, frac_bits, _bits, _int_bits);
 
     const APyFixedCastOption cast_option = get_fixed_cast_mode();
     const auto quantization_mode = quantization.value_or(cast_option.quantization);
@@ -967,9 +976,9 @@ APyFixedArray APyFixedArray::cast(
 
 APyFixedArray APyFixedArray::from_double(
     const nb::sequence& python_seq,
-    std::optional<int> bits,
     std::optional<int> int_bits,
-    std::optional<int> frac_bits
+    std::optional<int> frac_bits,
+    std::optional<int> bits
 )
 {
     if (nb::isinstance<nb::ndarray<nb::numpy>>(python_seq)) {
@@ -986,13 +995,13 @@ APyFixedArray APyFixedArray::from_double(
             shape[i] = ndarray.shape(i);
         }
 
-        APyFixedArray result(shape, bits, int_bits, frac_bits);
+        APyFixedArray result(shape, int_bits, frac_bits, bits);
         result._set_values_from_numpy_ndarray(ndarray);
         return result;
     }
 
     APyFixedArray result(
-        python_sequence_extract_shape(python_seq), bits, int_bits, frac_bits
+        python_sequence_extract_shape(python_seq), int_bits, frac_bits, bits
     );
 
     // Extract all Python doubles and integers
@@ -1192,7 +1201,7 @@ void APyFixedArray::_checked_inner_product_acc(
     );
 
     APyFixedArray hadamard_new = hadamard_scratch.cast(
-        mode.bits, mode.int_bits, mode.quantization, mode.overflow
+        mode.int_bits, mode.bits - mode.int_bits, mode.quantization, mode.overflow
     );
 
     // Accumulate the result
diff --git a/src/apyfixedarray.h b/src/apyfixedarray.h
index fc1f760a4..39f299026 100644
--- a/src/apyfixedarray.h
+++ b/src/apyfixedarray.h
@@ -64,21 +64,26 @@ class APyFixedArray : public APyBuffer<mp_limb_t> {
 
     explicit APyFixedArray(
         const nanobind::sequence& bit_pattern_sequence,
-        std::optional<int> bits = std::nullopt,
         std::optional<int> int_bits = std::nullopt,
-        std::optional<int> frac_bits = std::nullopt
+        std::optional<int> frac_bits = std::nullopt,
+        std::optional<int> bits = std::nullopt
     );
 
     /* ****************************************************************************** *
      * *                     Non-Python accessible constructors                     * *
      * ****************************************************************************** */
 
+    //! Constructor: specify only shape and word-length. Zero data on construction
+    explicit APyFixedArray(
+        const std::vector<std::size_t>& shape, int bits, int int_bits
+    );
+
     //! Constructor: specify only shape and word-length. Zero data on construction
     explicit APyFixedArray(
         const std::vector<std::size_t>& shape,
-        std::optional<int> bits = std::nullopt,
         std::optional<int> int_bits = std::nullopt,
-        std::optional<int> frac_bits = std::nullopt
+        std::optional<int> frac_bits = std::nullopt,
+        std::optional<int> bits = std::nullopt
     );
 
     /* ****************************************************************************** *
@@ -157,11 +162,11 @@ class APyFixedArray : public APyBuffer<mp_limb_t> {
      * options on narrowing casts.
      */
     APyFixedArray cast(
-        std::optional<int> bits = std::nullopt,
         std::optional<int> int_bits = std::nullopt,
-        std::optional<QuantizationMode> quantization = QuantizationMode::TRN,
-        std::optional<OverflowMode> overflow = OverflowMode::WRAP,
-        std::optional<int> frac_bits = std::nullopt
+        std::optional<int> frac_bits = std::nullopt,
+        std::optional<QuantizationMode> quantization = std::nullopt,
+        std::optional<OverflowMode> overflow = std::nullopt,
+        std::optional<int> bits = std::nullopt
     ) const;
 
     /*!
@@ -181,9 +186,9 @@ class APyFixedArray : public APyBuffer<mp_limb_t> {
     //! of `doubles`
     static APyFixedArray from_double(
         const nanobind::sequence& double_seq,
-        std::optional<int> bits = std::nullopt,
         std::optional<int> int_bits = std::nullopt,
-        std::optional<int> frac_bits = std::nullopt
+        std::optional<int> frac_bits = std::nullopt,
+        std::optional<int> bits = std::nullopt
     );
 
 private:
diff --git a/src/apyfixedarray_wrapper.cc b/src/apyfixedarray_wrapper.cc
index 8ebd0e2c1..cdfd09eba 100644
--- a/src/apyfixedarray_wrapper.cc
+++ b/src/apyfixedarray_wrapper.cc
@@ -14,7 +14,7 @@ void bind_fixed_array(nb::module_& m)
     nb::class_<APyFixedArray>(m, "APyFixedArray")
 
         /*
-         * Constructor: construct from a list of Python integers
+         * Constructor: construct from a Python sequence of integers
          */
         .def(
             nb::init<
@@ -23,9 +23,9 @@ void bind_fixed_array(nb::module_& m)
                 std::optional<int>,
                 std::optional<int>>(),
             nb::arg("bit_pattern_sequence"),
-            nb::arg("bits") = nb::none(),
             nb::arg("int_bits") = nb::none(),
-            nb::arg("frac_bits") = nb::none()
+            nb::arg("frac_bits") = nb::none(),
+            nb::arg("bits") = nb::none()
         )
 
         /*
@@ -305,11 +305,11 @@ void bind_fixed_array(nb::module_& m)
         .def(
             "cast",
             &APyFixedArray::cast,
-            nb::arg("bits") = nb::none(),
             nb::arg("int_bits") = nb::none(),
+            nb::arg("frac_bits") = nb::none(),
             nb::arg("quantization") = nb::none(),
             nb::arg("overflow") = nb::none(),
-            nb::arg("frac_bits") = nb::none(),
+            nb::arg("bits") = nb::none(),
             R"pbdoc(
             Change format of the fixed-point array.
 
@@ -321,16 +321,16 @@ void bind_fixed_array(nb::module_& m)
 
             Parameters
             ----------
-            bits : int, optional
-                Total number of bits in the result.
             int_bits : int, optional
                 Number of integer bits in the result.
-            quantization : :class:`QuantizationMode`, default: :class:`QuantizationMode.TRN`
-                Quantization mode to use in this cast.
-            overflow : :class:`OverflowMode`, default: :class:`OverflowMode.WRAP`
-                Overflowing mode to use in this cast.
             frac_bits : int, optional
                 Number of fractional bits in the result.
+            quantization : :class:`QuantizationMode`, optional
+                Quantization mode to use in this cast.
+            overflow : :class:`OverflowMode`, optional
+                Overflowing mode to use in this cast.
+            bits : int, optional
+                Total number of bits in the result.
 
             Returns
             -------
@@ -345,9 +345,9 @@ void bind_fixed_array(nb::module_& m)
             "from_float",
             &APyFixedArray::from_double,
             nb::arg("float_sequence"),
-            nb::arg("bits") = nb::none(),
             nb::arg("int_bits") = nb::none(),
             nb::arg("frac_bits") = nb::none(),
+            nb::arg("bits") = nb::none(),
             R"pbdoc(
             Create an :class:`APyFixedArray` object from a sequence of :class:`float`.
 
@@ -362,12 +362,12 @@ void bind_fixed_array(nb::module_& m)
             float_sequence : sequence of float
                 Floating point values to initialize from. The tensor shape will be taken
                 from the sequence shape.
-            bits : int, optional
-                Total number of bits in the created fixed-point tensor
             int_bits : int, optional
                 Number of integer bits in the created fixed-point tensor
             frac_bits : int, optional
                 Number of fractional bits in the created fixed-point tensor
+            bits : int, optional
+                Total number of bits in the created fixed-point tensor
 
             Returns
             -------
diff --git a/src/apytypes_common.cc b/src/apytypes_common.cc
index 20b99037f..3302ab4b2 100644
--- a/src/apytypes_common.cc
+++ b/src/apytypes_common.cc
@@ -124,11 +124,11 @@ std::optional<APyFixedAccumulatorOption> get_accumulator_mode_fixed()
 }
 
 APyFixedAccumulatorContext::APyFixedAccumulatorContext(
-    std::optional<int> bits,
     std::optional<int> int_bits,
     std::optional<int> frac_bits,
     std::optional<QuantizationMode> quantization,
-    std::optional<OverflowMode> overflow
+    std::optional<OverflowMode> overflow,
+    std::optional<int> bits
 )
 {
     // Store the previous accumulator mode
diff --git a/src/apytypes_common.h b/src/apytypes_common.h
index d22d974e6..fadb06dff 100644
--- a/src/apytypes_common.h
+++ b/src/apytypes_common.h
@@ -215,11 +215,11 @@ struct APyFixedAccumulatorOption {
 class APyFixedAccumulatorContext : public ContextManager {
 public:
     APyFixedAccumulatorContext(
-        std::optional<int> bits = std::nullopt,
         std::optional<int> int_bits = std::nullopt,
         std::optional<int> frac_bits = std::nullopt,
         std::optional<QuantizationMode> quantization = std::nullopt,
-        std::optional<OverflowMode> overflow = std::nullopt
+        std::optional<OverflowMode> overflow = std::nullopt,
+        std::optional<int> bits = std::nullopt
     );
     void enter_context() override;
     void exit_context() override;
diff --git a/src/apytypes_context_wrapper.cc b/src/apytypes_context_wrapper.cc
index e7a963a40..8ad8901d3 100644
--- a/src/apytypes_context_wrapper.cc
+++ b/src/apytypes_context_wrapper.cc
@@ -72,18 +72,18 @@ void bind_accumulator_context(nb::module_& m)
     )
         .def(
             nb::init<
-                std::optional<int>,
                 std::optional<int>,
                 std::optional<int>,
                 std::optional<QuantizationMode>,
-                std::optional<OverflowMode>>(),
+                std::optional<OverflowMode>,
+                std::optional<int>>(),
             // nb::kw_only() is added in NanoBind v2.0.0
             // nb::kw_only(), // All parameters are keyword only
-            nb::arg("bits") = nb::none(),
             nb::arg("int_bits") = nb::none(),
             nb::arg("frac_bits") = nb::none(),
             nb::arg("quantization") = nb::none(),
-            nb::arg("overflow") = nb::none()
+            nb::arg("overflow") = nb::none(),
+            nb::arg("bits") = nb::none()
         )
         .def("__enter__", &context_enter_handler)
         .def(
diff --git a/src/apytypes_util.h b/src/apytypes_util.h
index 8a2f8a791..365cbcfbf 100644
--- a/src/apytypes_util.h
+++ b/src/apytypes_util.h
@@ -18,7 +18,8 @@
 #include <regex>      // std::regex, std::regex_replace
 #include <sstream>    // std::stringstream
 #include <string>     // std::string
-#include <vector>     // std::vector
+#include <tuple>
+#include <vector> // std::vector
 
 /*
  * Include Microsoft intrinsics if using Microsoft Visual C/C++ compiler
@@ -745,16 +746,16 @@ template <class RANDOM_ACCESS_ITERATOR>
 
 //! Retrieve the `bits` specifier from user provided optional bit specifiers.
 //! Throws `nb::value_error` if the resulting number of bits is less than or equal to
-//! zero, or if not exactly two of three bit specifiers are present.
+//! zero, or if not exactly two of three bit specifiers are set.
 [[maybe_unused, nodiscard]] static APY_INLINE int bits_from_optional(
     std::optional<int> bits, std::optional<int> int_bits, std::optional<int> frac_bits
 )
 {
-    int num_bit_spec = bits.has_value() + int_bits.has_value() + frac_bits.has_value();
-    if (num_bit_spec != 2) {
+    int n_bit_spec = bits.has_value() + int_bits.has_value() + frac_bits.has_value();
+    if (n_bit_spec != 2) {
         throw nanobind::value_error(
             "Fixed-point bit specification needs exactly two of three bit specifiers "
-            "(bits, int_bits, frac_bits) set"
+            "(`bits`, `int_bits`, `frac_bits`) set"
         );
     }
 
@@ -768,6 +769,45 @@ template <class RANDOM_ACCESS_ITERATOR>
     return result;
 }
 
+//! Retrieve a two-tuple of ints (`bits`, `int_bits`) for a set of optional
+//! bit-specifiers used in the casting context. Throws `nanobind::value_error` if
+//! parameters do not add up, or if resulting `bits` is smaller than or equal to zero.
+[[maybe_unused, nodiscard]] static APY_INLINE std::tuple<int, int>
+bits_from_optional_cast(
+    std::optional<int> bits,
+    std::optional<int> int_bits,
+    std::optional<int> frac_bits,
+    int current_bits,
+    int current_int_bits
+)
+{
+    std::optional<std::tuple<int, int>> result = std::nullopt;
+    int n_bit_spec = bits.has_value() + int_bits.has_value() + frac_bits.has_value();
+    if (n_bit_spec == 1 && !bits.has_value()) {
+        if (int_bits.has_value()) {
+            result = { current_bits - current_int_bits + *int_bits, *int_bits };
+        } else { /* frac_bits.has_value() */
+            result = { current_int_bits + *frac_bits, current_int_bits };
+        }
+    } else if (n_bit_spec == 2) {
+        if (bits.has_value()) {
+            result = { *bits, int_bits.has_value() ? *int_bits : *bits - *frac_bits };
+        } else { /* int_bits.has_value() && frac_bits.has_value() */
+            result = { *int_bits + *frac_bits, *int_bits };
+        }
+    }
+
+    if (!result.has_value() || std::get<0>(*result) <= 0) {
+        throw nanobind::value_error(
+            "Fixed-point casting bit specification needs exactly one of `int_bits` or "
+            "`frac_bits` set, or exactly two of three specifiers (`bits`, `int_bits`, "
+            "`frac_bits`) set"
+        );
+    }
+
+    return *result;
+}
+
 //! Test if two's complement value in a limb vector is negative
 template <class RANDOM_ACCESS_ITERATOR>
 [[maybe_unused, nodiscard]] static APY_INLINE bool limb_vector_is_negative(


Test patch:
diff --git a/lib/test/apyfixed/test_arithmetic.py b/lib/test/apyfixed/test_arithmetic.py
index 7e44edd65..55b7c77e7 100644
--- a/lib/test/apyfixed/test_arithmetic.py
+++ b/lib/test/apyfixed/test_arithmetic.py
@@ -19,11 +19,11 @@ def test_arithmetic_operations():
 
 
 def test_overflow_twos_complement():
-    assert float(APyFixed(1 << 127, 128, 1)) == -1.0
-    assert float(APyFixed(1 << 126, 128, 1)) == 0.5
-    assert float(APyFixed(0xFFFFFFFF0 << 92, 96, 1)) == 0.0
-    assert float(APyFixed(0xFFFFFFFF8 << 92, 96, 1)) == -1.0
-    assert float(APyFixed(0xFFFFFFFF4 << 92, 96, 1)) == 0.5
+    assert float(APyFixed(1 << 127, 1, 127)) == -1.0
+    assert float(APyFixed(1 << 126, 1, 127)) == 0.5
+    assert float(APyFixed(0xFFFFFFFF0 << 92, 1, 95)) == 0.0
+    assert float(APyFixed(0xFFFFFFFF8 << 92, 1, 95)) == -1.0
+    assert float(APyFixed(0xFFFFFFFF4 << 92, 1, 95)) == 0.5
 
 
 def test_binary_comparison():
@@ -188,8 +188,8 @@ def test_mixed_width_operations():
     """
     Tests for mixed-width operations additions and subtractions
     """
-    fx_a = APyFixed(1779, 16, 8)
-    fx_b = APyFixed(17777779, 100, 80)
+    fx_a = APyFixed(1779, int_bits=8, frac_bits=8)
+    fx_b = APyFixed(17777779, int_bits=80, frac_bits=20)
     assert (fx_a + fx_b).is_identical(APyFixed(25064563, bits=101, int_bits=81))
     assert (fx_b + fx_a).is_identical(fx_a + fx_b)
 
@@ -210,8 +210,8 @@ def test_negative_fractional_bits_operations():
     """
     Tests for mixed-width operations additions and subtractions
     """
-    fx_a = APyFixed(1779, 16, 20)
-    fx_b = APyFixed(1779, 16, 30)
+    fx_a = APyFixed(1779, int_bits=20, frac_bits=-4)
+    fx_b = APyFixed(1779, int_bits=30, frac_bits=-14)
     s = APyFixed(1823475, bits=27, int_bits=31)
     assert (fx_a + fx_b).is_identical(s)
     assert (fx_b + fx_a).is_identical(s)
@@ -227,56 +227,56 @@ def test_negative_fractional_bits_operations():
 
 
 def test_unary_minus():
-    a = APyFixed(-3, 3, 2)
+    a = APyFixed(-3, int_bits=2, frac_bits=1)
     assert a._is_negative
     assert not a._is_positive
-    assert (-a).is_identical(APyFixed(3, 4, 3))
-    assert (--a).is_identical(APyFixed(-3, 5, 4))
+    assert (-a).is_identical(APyFixed(3, 3, 1))
+    assert (--a).is_identical(APyFixed(-3, 4, 1))
     assert not (-a)._is_negative
 
-    a = APyFixed(-3, 300, 2)
+    a = APyFixed(-3, int_bits=2, frac_bits=298)
     assert a._is_negative
     assert not a._is_positive
-    assert (-a).is_identical(APyFixed(3, 301, 3))
-    assert (--a).is_identical(APyFixed(-3, 302, 4))
+    assert (-a).is_identical(APyFixed(3, int_bits=3, frac_bits=298))
+    assert (--a).is_identical(APyFixed(-3, int_bits=4, frac_bits=298))
     assert not (-a)._is_negative
 
-    a = APyFixed(-3, 64, 5)
+    a = APyFixed(-3, int_bits=5, frac_bits=59)
     assert a._is_negative
     assert not a._is_positive
-    assert (-a).is_identical(APyFixed(3, 65, 6))
-    assert (--a).is_identical(APyFixed(-3, 66, 7))
+    assert (-a).is_identical(APyFixed(3, int_bits=6, frac_bits=59))
+    assert (--a).is_identical(APyFixed(-3, int_bits=7, frac_bits=59))
     assert not (-a)._is_negative
 
 
 def test_abs():
-    a = APyFixed(-3, 3, 2)
-    assert abs(a).is_identical(APyFixed(3, 4, 3))
+    a = APyFixed(-3, 2, 1)
+    assert abs(a).is_identical(APyFixed(3, 3, 1))
     assert not abs(a)._is_negative
-    a = APyFixed(-4, 3, 2)
+    a = APyFixed(-4, 2, 1)
     assert a._is_negative
-    assert abs(a).is_identical(APyFixed(4, 4, 3))
+    assert abs(a).is_identical(APyFixed(4, 3, 1))
     assert not abs(a)._is_negative
     assert abs(a)._is_positive
 
     # Both positive and negative fixed-point values have word length increased on
     # absolute value. Related GitHub issue: #15
-    a = APyFixed(3, 3, 2)
-    b = APyFixed(-3, 3, 2)
+    a = APyFixed(3, 2, 1)
+    b = APyFixed(-3, 2, 1)
     assert abs(a).to_bits() == 3
     assert abs(b).to_bits() == 3
     assert abs(a).is_identical(abs(b))
 
-    a = APyFixed(-3, 300, 2)
-    assert abs(a).is_identical(APyFixed(3, 301, 3))
+    a = APyFixed(-3, 2, 298)
+    assert abs(a).is_identical(APyFixed(3, 3, 298))
 
 
 def test_shift():
     a = APyFixed(-3, bits=3, int_bits=2)
-    assert (a >> 2).is_identical(APyFixed(-3, 3, 0))
-    assert (a << 7).is_identical(APyFixed(-3, 3, 9))
-    assert (a >> -2).is_identical(APyFixed(-3, 3, 4))
-    assert (a << -7).is_identical(APyFixed(-3, 3, -5))
+    assert (a >> 2).is_identical(APyFixed(-3, bits=3, int_bits=0))
+    assert (a << 7).is_identical(APyFixed(-3, bits=3, int_bits=9))
+    assert (a >> -2).is_identical(APyFixed(-3, bits=3, int_bits=4))
+    assert (a << -7).is_identical(APyFixed(-3, bits=3, int_bits=-5))
 
     a = APyFixed(-3, bits=3, int_bits=2)
     b = a << 2
@@ -318,8 +318,8 @@ def test_prod():
 def test_issue_198():
     # Smoke test for hang:
     # https://github.com/apytypes/apytypes/issues/198
-    a = APyFixed.from_float(0.37, 320, 160)
-    b = APyFixed.from_float(-1.54, 320, 160)
+    a = APyFixed.from_float(0.37, bits=320, int_bits=160)
+    b = APyFixed.from_float(-1.54, bits=320, int_bits=160)
     assert (a / b).is_identical(
         APyFixed(
             9124881235244390437282343211400582649786457014497119861158385035798550334417354773011825622634742286365594170616862341739107325461683793130579692109045501048385049337084316871381549559677925492,
diff --git a/lib/test/apyfixed/test_constructors.py b/lib/test/apyfixed/test_constructors.py
index 0e1231e60..617c84a96 100644
--- a/lib/test/apyfixed/test_constructors.py
+++ b/lib/test/apyfixed/test_constructors.py
@@ -36,11 +36,11 @@ def test_constructor():
 
     # Integers that dont fit a single Python digit
     assert (
-        APyFixed(1234567898765432123456789, 100, 50).to_bits()
+        APyFixed(1234567898765432123456789, int_bits=50, frac_bits=50).to_bits()
         == 1234567898765432123456789
     )
     assert (
-        APyFixed(-1234567898765432123456789, 100, 50).to_bits()
+        APyFixed(-1234567898765432123456789, int_bits=50, frac_bits=50).to_bits()
         == 2**100 - 1234567898765432123456789
     )
 
@@ -56,53 +56,53 @@ def test_floating_point_construction():
 
     # Zero floating point numbers
     assert APyFixed.from_float(0.0, bits=1, int_bits=0).to_bits() == 0
-    assert APyFixed.from_float(-0.0, 1234, -1000).to_bits() == 0
-    assert APyFixed.from_float(0.0, 1234, 1000).to_bits() == 0
-    assert APyFixed.from_float(0.0, 1234, 1000).to_bits() == 0
+    assert APyFixed.from_float(-0.0, bits=1234, int_bits=-1000).to_bits() == 0
+    assert APyFixed.from_float(0.0, bits=1234, int_bits=1000).to_bits() == 0
+    assert APyFixed.from_float(0.0, bits=1234, int_bits=1000).to_bits() == 0
 
     # Integer tests
-    assert APyFixed.from_float(123.0, 64, 64).to_bits() == 123
-    assert APyFixed.from_float(-123.0, 64, 64).to_bits() == 2**64 - 123
-    assert APyFixed.from_float(pow(2.0, 52.0) + 0.0, 64, 64).to_bits() == (1 << 52) + 0
-    assert APyFixed.from_float(pow(2.0, 52.0) + 1.0, 64, 64).to_bits() == (1 << 52) + 1
-    assert APyFixed.from_float(pow(2.0, 53.0) + 0.0, 64, 64).to_bits() == (1 << 53) + 0
+    assert APyFixed.from_float(123.0, 64, 0).to_bits() == 123
+    assert APyFixed.from_float(-123.0, 64, 0).to_bits() == 2**64 - 123
+    assert APyFixed.from_float(pow(2.0, 52.0) + 0.0, 64, 0).to_bits() == (1 << 52) + 0
+    assert APyFixed.from_float(pow(2.0, 52.0) + 1.0, 64, 0).to_bits() == (1 << 52) + 1
+    assert APyFixed.from_float(pow(2.0, 53.0) + 0.0, 64, 0).to_bits() == (1 << 53) + 0
     assert (
-        APyFixed.from_float(pow(2.0, 53.0) + 1.0, 64, 64).to_bits()
+        APyFixed.from_float(pow(2.0, 53.0) + 1.0, 64, 0).to_bits()
         == (1 << 53) + 0  # Precision was lost when adding 1 onto 2^53
     )
     assert (
-        APyFixed.from_float(pow(2.0, 123.0) - pow(2.0, 152), 30, 153).to_bits()
+        APyFixed.from_float(pow(2.0, 123.0) - pow(2.0, 152), 153, -123).to_bits()
         == (1 << 29) + 1
     )
-    assert APyFixed.from_float(pow(2.0, 123.0) - pow(2.0, 152), 29, 153).to_bits() == (
-        1 << 28
-    )
+    assert APyFixed.from_float(
+        pow(2.0, 123.0) - pow(2.0, 152), 153, -124
+    ).to_bits() == (1 << 28)
 
     # Fractional number testing
-    assert float(APyFixed.from_float(123.125, 64, 0)) == 0.125
-    assert APyFixed.from_float(-pow(2.0, -127.0), 1, -126).to_bits() == 1
+    assert float(APyFixed.from_float(123.125, 0, 64)) == 0.125
+    assert APyFixed.from_float(-pow(2.0, -127.0), bits=1, int_bits=-126).to_bits() == 1
     assert (
-        APyFixed.from_float(-1.0 + pow(2.0, -53), 55, 2).to_bits()
+        APyFixed.from_float(-1.0 + pow(2.0, -53), bits=55, int_bits=2).to_bits()
         == (1 << 54) + (1 << 53) + 1
     )
 
     # Round away from infinity on tie
-    assert APyFixed.from_float(0.24, 2, 1).to_bits() == 0  #  0.00
-    assert APyFixed.from_float(0.25, 2, 1).to_bits() == 1  #  0.25
-    assert APyFixed.from_float(-0.25, 2, 1).to_bits() == 3  # -0.25
-    assert APyFixed.from_float(-0.24, 2, 1).to_bits() == 0  #  0.00
+    assert APyFixed.from_float(0.24, 1, 1).to_bits() == 0  #  0.00
+    assert APyFixed.from_float(0.25, 1, 1).to_bits() == 1  #  0.25
+    assert APyFixed.from_float(-0.25, 1, 1).to_bits() == 3  # -0.25
+    assert APyFixed.from_float(-0.24, 1, 1).to_bits() == 0  #  0.00
 
 
 def test_string_construction():
-    assert APyFixed.from_str("511", 10, 10).to_bits() == 0x1FF
-    assert APyFixed.from_str("512", 10, 10).to_bits() == 0x200
-    assert APyFixed.from_str("-511", 10, 10).to_bits() == 0x201
-    assert APyFixed.from_str("-512", 10, 10).to_bits() == 0x200
-    assert APyFixed.from_str("512", 10, 14).to_bits() == 0x20
-    assert APyFixed.from_str("1.0", 10, 9).to_bits() == 2
-    assert APyFixed.from_str("1.000000", 10, 9).to_bits() == 2
-    assert APyFixed.from_str("10.00", 10, 9).to_bits() == 20
-    assert APyFixed.from_str(".0625000", 10, 2).to_bits() == 16
+    assert APyFixed.from_str("511", 10, 0).to_bits() == 0x1FF
+    assert APyFixed.from_str("512", 10, 0).to_bits() == 0x200
+    assert APyFixed.from_str("-511", 10, 0).to_bits() == 0x201
+    assert APyFixed.from_str("-512", 10, 0).to_bits() == 0x200
+    assert APyFixed.from_str("512", 14, -4).to_bits() == 0x20
+    assert APyFixed.from_str("1.0", 9, 1).to_bits() == 2
+    assert APyFixed.from_str("1.000000", 9, 1).to_bits() == 2
+    assert APyFixed.from_str("10.00", 9, 1).to_bits() == 20
+    assert APyFixed.from_str(".0625000", 2, 8).to_bits() == 16
 
     fx_a = APyFixed.from_str(
         "28948022309329048855892746252171976963317496166410141009892066118088846737408",
diff --git a/lib/test/apyfixed/test_methods.py b/lib/test/apyfixed/test_methods.py
index cee56b4cb..5983f9f81 100644
--- a/lib/test/apyfixed/test_methods.py
+++ b/lib/test/apyfixed/test_methods.py
@@ -20,20 +20,20 @@ def test_bit_specifier_getters():
       * `int_bits()`
       * `frac_bits()`
     """
-    assert APyFixed(0, 12345, 12).bits == 12345
-    assert APyFixed(0, 12345, 12).int_bits == 12
-    assert APyFixed(0, 12345, 12).frac_bits == 12345 - 12
+    assert APyFixed(0, bits=12345, int_bits=12).bits == 12345
+    assert APyFixed(0, bits=12345, int_bits=12).int_bits == 12
+    assert APyFixed(0, bits=12345, int_bits=12).frac_bits == 12345 - 12
 
 
 def test_to_float():
-    assert float(APyFixed(0, 1, 0)) == 0.0
-    assert float(APyFixed(0, 1234, 123)) == 0.0
-    assert float(APyFixed(0, 1234, -123)) == 0.0
-    assert float(APyFixed(0, 1234, 12345)) == 0.0
-    assert float(APyFixed(0b00100, 5, 1)) == 0.25
-    assert float(APyFixed(0b11100, 5, 1)) == -0.25
-    assert float(APyFixed(0x48, 8, 4)) == 4.5
-    assert float(APyFixed(0x558 << 128, 128 + 12, 8)) == 85.5
+    assert float(APyFixed(0, bits=1, int_bits=0)) == 0.0
+    assert float(APyFixed(0, bits=1234, int_bits=123)) == 0.0
+    assert float(APyFixed(0, bits=1234, int_bits=-123)) == 0.0
+    assert float(APyFixed(0, bits=1234, int_bits=12345)) == 0.0
+    assert float(APyFixed(0b00100, int_bits=1, frac_bits=4)) == 0.25
+    assert float(APyFixed(0b11100, int_bits=1, frac_bits=4)) == -0.25
+    assert float(APyFixed(0x48, int_bits=4, frac_bits=4)) == 4.5
+    assert float(APyFixed(0x558 << 128, bits=128 + 12, int_bits=8)) == 85.5
 
 
 def test_is_zero():
@@ -50,46 +50,73 @@ def test_to_string():
     Test `__str__` and `to_string` methods
     """
     assert (
-        str(APyFixed((1 << 512) + (1 << 123) + (1 << 64) + (1 << 63), 1000, 1000))
+        str(APyFixed((1 << 512) + (1 << 123) + (1 << 64) + (1 << 63), 1000, 0))
         == "13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486061487577849091273580847006241813168128"
     )
     assert (
-        str(APyFixed((1 << 512) + (1 << 123) + (1 << 64) + (1 << 63), 1000, 900))
+        str(APyFixed((1 << 512) + (1 << 123) + (1 << 64) + (1 << 63), 900, 100))
         == "10576895500643977583230644928524336637254474927428499508554380724390492659780981533203027367035444557561459392400373741256704.0000000000218278728425502777099609375"
     )
     assert (
-        str(APyFixed((1 << 999) + (1 << 123) + (1 << 64) + (1 << 63), 1000, 1000))
+        str(APyFixed((1 << 999) + (1 << 123) + (1 << 64) + (1 << 63), 1000, 0))
         == "-5357543035931336604742125245300009052807024058527668037218751941851755255624680612465991894078479290637973364587765734125935726428461570217992288787349287401967283887412115492710537302531185570938977091076523237491790970633699383779582771973038531457285598238843260450006248636499301292846010026950656"
     )
     assert (
-        str(APyFixed((1 << 999) + (1 << 123) + (1 << 64) + (1 << 63), 1000, 900))
+        str(APyFixed((1 << 999) + (1 << 123) + (1 << 64) + (1 << 63), 900, 100))
         == "-4226356249085321970818718279332132852150778608288972177023685672213391220453798875795338047101257503157395159946057029431058780476021484298004311827703516615267093471992040673349852141411411528424193863265689507233184226342012493910707175190136291811916308647181895598079.9999999999781721271574497222900390625"
     )
 
 
 def test_is_positive():
-    a = APyFixed(4, 3, 2)
+    a = APyFixed(4, int_bits=2, frac_bits=1)
     assert not a._is_positive
-    a = APyFixed(3, 3, 2)
+    a = APyFixed(3, int_bits=2, frac_bits=1)
     assert a._is_positive
-    a = APyFixed(0, 3, 2)
+    a = APyFixed(0, int_bits=2, frac_bits=1)
     assert not a._is_positive
-    a = APyFixed(-3, 3, 2)
+    a = APyFixed(-3, int_bits=2, frac_bits=1)
     assert not a._is_positive
 
 
 def test_is_negative():
-    a = APyFixed(4, 3, 2)
+    a = APyFixed(4, int_bits=2, frac_bits=1)
     assert a._is_negative
-    a = APyFixed(3, 3, 2)
+    a = APyFixed(3, int_bits=2, frac_bits=1)
     assert not a._is_negative
-    a = APyFixed(0, 3, 2)
+    a = APyFixed(0, int_bits=2, frac_bits=1)
     assert not a._is_negative
-    a = APyFixed(-3, 3, 2)
+    a = APyFixed(-3, int_bits=2, frac_bits=1)
     assert a._is_negative
 
 
 def test_round_trip_conversion():
     for bits in range(256):
-        a = APyFixed(bits, 8, 4)
-        assert (APyFixed.from_float(float(a), 8, 4)).is_identical(a)
+        a = APyFixed(bits, bits=8, int_bits=4)
+        assert (APyFixed.from_float(float(a), bits=8, int_bits=4)).is_identical(a)
+
+
+def test_fixed_cast_throws():
+    # Only specifying `bits` in a cast raises
+    with pytest.raises(ValueError, match="Fixed-point casting bit specification needs"):
+        APyFixed(0, int_bits=10, frac_bits=5).cast(bits=7)
+
+    # Specifying `bits`, `int_bits` and `frac_bits` in a cast raises
+    with pytest.raises(ValueError, match="Fixed-point casting bit specification needs"):
+        APyFixed(0, int_bits=10, frac_bits=5).cast(bits=7, int_bits=2, frac_bits=5)
+
+    # Casting `bits` to zero or less raises exception
+    for i in range(-5, 0 + 1):
+        with pytest.raises(ValueError, match="Fixed-point casting bit specification"):
+            APyFixed(0, int_bits=10, frac_bits=5).cast(bits=0, int_bits=0)
+
+    # Only specifying `int_bits` or `frac_bits` does *not* throw
+    APyFixed(0, int_bits=10, frac_bits=5).cast(7)
+    APyFixed(0, int_bits=10, frac_bits=5).cast(int_bits=7)
+    APyFixed(0, int_bits=10, frac_bits=5).cast(frac_bits=7)
+
+    # Any two-combination of bit-specifiers does not throw
+    APyFixed(0, int_bits=10, frac_bits=5).cast(bits=5, int_bits=2)
+    APyFixed(0, int_bits=10, frac_bits=5).cast(bits=5, frac_bits=2)
+    APyFixed(0, int_bits=10, frac_bits=5).cast(int_bits=5, frac_bits=2)
+
+    # Casting to a negative number of `bits` casts
diff --git a/lib/test/apyfixed/test_overflow.py b/lib/test/apyfixed/test_overflow.py
index 5e6653576..f5f643113 100644
--- a/lib/test/apyfixed/test_overflow.py
+++ b/lib/test/apyfixed/test_overflow.py
@@ -6,200 +6,200 @@
 
 def test_overflow_twos_complement():
     print(float(APyFixed(0xFF, 8, 8)))
-    assert float(APyFixed(0xC3, 8, 8).cast(8, 8, overflow=OverflowMode.WRAP)) == -61.0
-    assert float(APyFixed(0xC3, 8, 8).cast(7, 7, overflow=OverflowMode.WRAP)) == -61.0
-    assert float(APyFixed(0xC3, 8, 8).cast(6, 6, overflow=OverflowMode.WRAP)) == 3.0
+    assert float(APyFixed(0xC3, 8, 0).cast(8, 0, overflow=OverflowMode.WRAP)) == -61.0
+    assert float(APyFixed(0xC3, 8, 0).cast(7, 0, overflow=OverflowMode.WRAP)) == -61.0
+    assert float(APyFixed(0xC3, 8, 0).cast(6, 0, overflow=OverflowMode.WRAP)) == 3.0
 
 
 def test_overflow_saturation():
     # Negative single non-full limb
-    assert float(APyFixed(0xC3, 8, 8).cast(8, 8, overflow=OverflowMode.SAT)) == -61.0
-    assert float(APyFixed(0xC3, 8, 8).cast(7, 7, overflow=OverflowMode.SAT)) == -61.0
-    assert float(APyFixed(0xC3, 8, 8).cast(6, 6, overflow=OverflowMode.SAT)) == -32.0
-    assert float(APyFixed(0xC3, 8, 8).cast(5, 5, overflow=OverflowMode.SAT)) == -16.0
-    assert float(APyFixed(0xC3, 8, 8).cast(1, 1, overflow=OverflowMode.SAT)) == -1.0
+    assert float(APyFixed(0xC3, 8, 0).cast(8, 0, overflow=OverflowMode.SAT)) == -61.0
+    assert float(APyFixed(0xC3, 8, 0).cast(7, 0, overflow=OverflowMode.SAT)) == -61.0
+    assert float(APyFixed(0xC3, 8, 0).cast(6, 0, overflow=OverflowMode.SAT)) == -32.0
+    assert float(APyFixed(0xC3, 8, 0).cast(5, 0, overflow=OverflowMode.SAT)) == -16.0
+    assert float(APyFixed(0xC3, 8, 0).cast(1, 0, overflow=OverflowMode.SAT)) == -1.0
 
     # Positive single non-full limb
-    assert float(APyFixed(0x13, 8, 8).cast(8, 8, overflow=OverflowMode.SAT)) == 19.0
-    assert float(APyFixed(0x13, 8, 8).cast(7, 7, overflow=OverflowMode.SAT)) == 19.0
-    assert float(APyFixed(0x13, 8, 8).cast(6, 6, overflow=OverflowMode.SAT)) == 19.0
-    assert float(APyFixed(0x13, 8, 8).cast(5, 5, overflow=OverflowMode.SAT)) == 15.0
-    assert float(APyFixed(0x13, 8, 8).cast(1, 1, overflow=OverflowMode.SAT)) == 0.0
+    assert float(APyFixed(0x13, 8, 0).cast(8, 0, overflow=OverflowMode.SAT)) == 19.0
+    assert float(APyFixed(0x13, 8, 0).cast(7, 0, overflow=OverflowMode.SAT)) == 19.0
+    assert float(APyFixed(0x13, 8, 0).cast(6, 0, overflow=OverflowMode.SAT)) == 19.0
+    assert float(APyFixed(0x13, 8, 0).cast(5, 0, overflow=OverflowMode.SAT)) == 15.0
+    assert float(APyFixed(0x13, 8, 0).cast(1, 0, overflow=OverflowMode.SAT)) == 0.0
 
     # Negative multi-limb
     assert (
-        APyFixed(0xC0000000000000003, 68, 68)
-        .cast(68, 68, overflow=OverflowMode.SAT)
-        .is_identical(APyFixed(0xC0000000000000003, 68, 68))
+        APyFixed(0xC0000000000000003, 68, 0)
+        .cast(68, 0, overflow=OverflowMode.SAT)
+        .is_identical(APyFixed(0xC0000000000000003, 68, 0))
     )
     assert (
-        APyFixed(0xC0000000000000003, 68, 68)
-        .cast(67, 67, overflow=OverflowMode.SAT)
-        .is_identical(APyFixed(0x40000000000000003, 67, 67))
+        APyFixed(0xC0000000000000003, 68, 0)
+        .cast(67, 0, overflow=OverflowMode.SAT)
+        .is_identical(APyFixed(0x40000000000000003, 67, 0))
     )
     assert (
-        APyFixed(0xC0000000000000003, 68, 68)
-        .cast(66, 66, overflow=OverflowMode.SAT)
-        .is_identical(APyFixed(0x20000000000000000, 66, 66))
+        APyFixed(0xC0000000000000003, 68, 0)
+        .cast(66, 0, overflow=OverflowMode.SAT)
+        .is_identical(APyFixed(0x20000000000000000, 66, 0))
     )
     assert (
-        APyFixed(0xC0000000000000003, 68, 68)
-        .cast(65, 65, overflow=OverflowMode.SAT)
-        .is_identical(APyFixed(0x10000000000000000, 65, 65))
+        APyFixed(0xC0000000000000003, 68, 0)
+        .cast(65, 0, overflow=OverflowMode.SAT)
+        .is_identical(APyFixed(0x10000000000000000, 65, 0))
     )
     assert (
-        APyFixed(0xC0000000000000003, 68, 68)
-        .cast(64, 64, overflow=OverflowMode.SAT)
-        .is_identical(APyFixed(0x8000000000000000, 64, 64))
+        APyFixed(0xC0000000000000003, 68, 0)
+        .cast(64, 0, overflow=OverflowMode.SAT)
+        .is_identical(APyFixed(0x8000000000000000, 64, 0))
     )
     assert (
-        APyFixed(0xC0000000000000003, 68, 68)
-        .cast(63, 63, overflow=OverflowMode.SAT)
-        .is_identical(APyFixed(0x4000000000000000, 63, 63))
+        APyFixed(0xC0000000000000003, 68, 0)
+        .cast(63, 0, overflow=OverflowMode.SAT)
+        .is_identical(APyFixed(0x4000000000000000, 63, 0))
     )
 
     # Positive multi-limb
     assert (
-        APyFixed(0x10000000000000003, 68, 68)
-        .cast(68, 68, overflow=OverflowMode.SAT)
-        .is_identical(APyFixed(0x10000000000000003, 68, 68))
+        APyFixed(0x10000000000000003, 68, 0)
+        .cast(68, 0, overflow=OverflowMode.SAT)
+        .is_identical(APyFixed(0x10000000000000003, 68, 0))
     )
     assert (
-        APyFixed(0x10000000000000003, 68, 68)
-        .cast(67, 67, overflow=OverflowMode.SAT)
-        .is_identical(APyFixed(0x10000000000000003, 67, 67))
+        APyFixed(0x10000000000000003, 68, 0)
+        .cast(67, 0, overflow=OverflowMode.SAT)
+        .is_identical(APyFixed(0x10000000000000003, 67, 0))
     )
     assert (
-        APyFixed(0x10000000000000003, 68, 68)
-        .cast(66, 66, overflow=OverflowMode.SAT)
-        .is_identical(APyFixed(0x10000000000000003, 66, 66))
+        APyFixed(0x10000000000000003, 68, 0)
+        .cast(66, 0, overflow=OverflowMode.SAT)
+        .is_identical(APyFixed(0x10000000000000003, 66, 0))
     )
     assert (
-        APyFixed(0x10000000000000003, 68, 68)
-        .cast(65, 65, overflow=OverflowMode.SAT)
-        .is_identical(APyFixed(0xFFFFFFFFFFFFFFFF, 65, 65))
+        APyFixed(0x10000000000000003, 68, 0)
+        .cast(65, 0, overflow=OverflowMode.SAT)
+        .is_identical(APyFixed(0xFFFFFFFFFFFFFFFF, 65, 0))
     )
     assert (
-        APyFixed(0x10000000000000003, 68, 68)
-        .cast(64, 64, overflow=OverflowMode.SAT)
-        .is_identical(APyFixed(0x7FFFFFFFFFFFFFFF, 64, 64))
+        APyFixed(0x10000000000000003, 68, 0)
+        .cast(64, 0, overflow=OverflowMode.SAT)
+        .is_identical(APyFixed(0x7FFFFFFFFFFFFFFF, 64, 0))
     )
     assert (
-        APyFixed(0x10000000000000003, 68, 68)
-        .cast(63, 63, overflow=OverflowMode.SAT)
-        .is_identical(APyFixed(0x3FFFFFFFFFFFFFFF, 63, 63))
+        APyFixed(0x10000000000000003, 68, 0)
+        .cast(63, 0, overflow=OverflowMode.SAT)
+        .is_identical(APyFixed(0x3FFFFFFFFFFFFFFF, 63, 0))
     )
 
 
 def test_overflow_numeric_std():
     # Negative single non-full limb
     assert (
-        float(APyFixed(0xC3, 8, 8).cast(8, 8, overflow=OverflowMode.NUMERIC_STD))
+        float(APyFixed(0xC3, 8, 0).cast(8, 0, overflow=OverflowMode.NUMERIC_STD))
         == -61.0
     )
     assert (
-        float(APyFixed(0xC3, 8, 8).cast(7, 7, overflow=OverflowMode.NUMERIC_STD))
+        float(APyFixed(0xC3, 8, 0).cast(7, 0, overflow=OverflowMode.NUMERIC_STD))
         == -61.0
     )
     assert (
-        float(APyFixed(0xC3, 8, 8).cast(6, 6, overflow=OverflowMode.NUMERIC_STD))
+        float(APyFixed(0xC3, 8, 0).cast(6, 0, overflow=OverflowMode.NUMERIC_STD))
         == -29.0
     )
     assert (
-        float(APyFixed(0xC3, 8, 8).cast(5, 5, overflow=OverflowMode.NUMERIC_STD))
+        float(APyFixed(0xC3, 8, 0).cast(5, 0, overflow=OverflowMode.NUMERIC_STD))
         == -13.0
     )
     assert (
-        float(APyFixed(0xC3, 8, 8).cast(1, 1, overflow=OverflowMode.NUMERIC_STD))
+        float(APyFixed(0xC3, 8, 0).cast(1, 0, overflow=OverflowMode.NUMERIC_STD))
         == -1.0
     )
 
     # Positive single non-full limb
     assert (
-        float(APyFixed(0x13, 8, 8).cast(8, 8, overflow=OverflowMode.NUMERIC_STD))
+        float(APyFixed(0x13, 8, 0).cast(8, 0, overflow=OverflowMode.NUMERIC_STD))
         == 19.0
     )
     assert (
-        float(APyFixed(0x13, 8, 8).cast(7, 7, overflow=OverflowMode.NUMERIC_STD))
+        float(APyFixed(0x13, 8, 0).cast(7, 0, overflow=OverflowMode.NUMERIC_STD))
         == 19.0
     )
     assert (
-        float(APyFixed(0x13, 8, 8).cast(6, 6, overflow=OverflowMode.NUMERIC_STD))
+        float(APyFixed(0x13, 8, 0).cast(6, 0, overflow=OverflowMode.NUMERIC_STD))
         == 19.0
     )
     assert (
-        float(APyFixed(0x13, 8, 8).cast(5, 5, overflow=OverflowMode.NUMERIC_STD)) == 3.0
+        float(APyFixed(0x13, 8, 0).cast(5, 0, overflow=OverflowMode.NUMERIC_STD)) == 3.0
     )
     assert (
-        float(APyFixed(0x13, 8, 8).cast(4, 4, overflow=OverflowMode.NUMERIC_STD)) == 3.0
+        float(APyFixed(0x13, 8, 0).cast(4, 0, overflow=OverflowMode.NUMERIC_STD)) == 3.0
     )
     assert (
-        float(APyFixed(0x13, 8, 8).cast(2, 2, overflow=OverflowMode.NUMERIC_STD)) == 1.0
+        float(APyFixed(0x13, 8, 0).cast(2, 0, overflow=OverflowMode.NUMERIC_STD)) == 1.0
     )
     assert (
-        float(APyFixed(0x13, 8, 8).cast(1, 1, overflow=OverflowMode.NUMERIC_STD)) == 0.0
+        float(APyFixed(0x13, 8, 0).cast(1, 0, overflow=OverflowMode.NUMERIC_STD)) == 0.0
     )
 
     # Negative multi-limb
     assert (
-        APyFixed(0xC0000000000000003, 68, 68)
-        .cast(68, 68, overflow=OverflowMode.NUMERIC_STD)
-        .is_identical(APyFixed(0xC0000000000000003, 68, 68))
+        APyFixed(0xC0000000000000003, 68, 0)
+        .cast(68, 0, overflow=OverflowMode.NUMERIC_STD)
+        .is_identical(APyFixed(0xC0000000000000003, 68, 0))
     )
     assert (
-        APyFixed(0xC0000000000000003, 68, 68)
-        .cast(67, 67, overflow=OverflowMode.NUMERIC_STD)
-        .is_identical(APyFixed(0x40000000000000003, 67, 67))
+        APyFixed(0xC0000000000000003, 68, 0)
+        .cast(67, 0, overflow=OverflowMode.NUMERIC_STD)
+        .is_identical(APyFixed(0x40000000000000003, 67, 0))
     )
     assert (
-        APyFixed(0xC0000000000000003, 68, 68)
-        .cast(66, 66, overflow=OverflowMode.NUMERIC_STD)
-        .is_identical(APyFixed(0x20000000000000003, 66, 66))
+        APyFixed(0xC0000000000000003, 68, 0)
+        .cast(66, 0, overflow=OverflowMode.NUMERIC_STD)
+        .is_identical(APyFixed(0x20000000000000003, 66, 0))
     )
     assert (
-        APyFixed(0xC0000000000000003, 68, 68)
-        .cast(65, 65, overflow=OverflowMode.NUMERIC_STD)
-        .is_identical(APyFixed(0x10000000000000003, 65, 65))
+        APyFixed(0xC0000000000000003, 68, 0)
+        .cast(65, 0, overflow=OverflowMode.NUMERIC_STD)
+        .is_identical(APyFixed(0x10000000000000003, 65, 0))
     )
     assert (
-        APyFixed(0xC0000000000000003, 68, 68)
-        .cast(64, 64, overflow=OverflowMode.NUMERIC_STD)
-        .is_identical(APyFixed(0x8000000000000003, 64, 64))
+        APyFixed(0xC0000000000000003, 68, 0)
+        .cast(64, 0, overflow=OverflowMode.NUMERIC_STD)
+        .is_identical(APyFixed(0x8000000000000003, 64, 0))
     )
     assert (
-        APyFixed(0xC0000000000000003, 68, 68)
-        .cast(63, 63, overflow=OverflowMode.NUMERIC_STD)
-        .is_identical(APyFixed(0x4000000000000003, 63, 63))
+        APyFixed(0xC0000000000000003, 68, 0)
+        .cast(63, 0, overflow=OverflowMode.NUMERIC_STD)
+        .is_identical(APyFixed(0x4000000000000003, 63, 0))
     )
 
     # Positive multi-limb
     assert (
-        APyFixed(0x10000000000000003, 68, 68)
-        .cast(68, 68, overflow=OverflowMode.NUMERIC_STD)
-        .is_identical(APyFixed(0x10000000000000003, 68, 68))
+        APyFixed(0x10000000000000003, 68, 0)
+        .cast(68, 0, overflow=OverflowMode.NUMERIC_STD)
+        .is_identical(APyFixed(0x10000000000000003, 68, 0))
     )
     assert (
-        APyFixed(0x10000000000000003, 68, 68)
-        .cast(67, 67, overflow=OverflowMode.NUMERIC_STD)
-        .is_identical(APyFixed(0x10000000000000003, 67, 67))
+        APyFixed(0x10000000000000003, 68, 0)
+        .cast(67, 0, overflow=OverflowMode.NUMERIC_STD)
+        .is_identical(APyFixed(0x10000000000000003, 67, 0))
     )
     assert (
-        APyFixed(0x10000000000000003, 68, 68)
-        .cast(66, 66, overflow=OverflowMode.NUMERIC_STD)
-        .is_identical(APyFixed(0x10000000000000003, 66, 66))
+        APyFixed(0x10000000000000003, 68, 0)
+        .cast(66, 0, overflow=OverflowMode.NUMERIC_STD)
+        .is_identical(APyFixed(0x10000000000000003, 66, 0))
     )
     assert (
-        APyFixed(0x10000000000000003, 68, 68)
-        .cast(65, 65, overflow=OverflowMode.NUMERIC_STD)
-        .is_identical(APyFixed(0x03, 65, 65))
+        APyFixed(0x10000000000000003, 68, 0)
+        .cast(65, 0, overflow=OverflowMode.NUMERIC_STD)
+        .is_identical(APyFixed(0x03, 65, 0))
     )
     assert (
-        APyFixed(0x10000000000000003, 68, 68)
-        .cast(64, 64, overflow=OverflowMode.NUMERIC_STD)
-        .is_identical(APyFixed(0x03, 64, 64))
+        APyFixed(0x10000000000000003, 68, 0)
+        .cast(64, 0, overflow=OverflowMode.NUMERIC_STD)
+        .is_identical(APyFixed(0x03, 64, 0))
     )
     assert (
-        APyFixed(0x10000000000000003, 68, 68)
-        .cast(63, 63, overflow=OverflowMode.NUMERIC_STD)
-        .is_identical(APyFixed(0x03, 63, 63))
+        APyFixed(0x10000000000000003, 68, 0)
+        .cast(63, 0, overflow=OverflowMode.NUMERIC_STD)
+        .is_identical(APyFixed(0x03, 63, 0))
     )
diff --git a/lib/test/apyfixed/test_quantization.py b/lib/test/apyfixed/test_quantization.py
index d4547f3ad..d266fd625 100644
--- a/lib/test/apyfixed/test_quantization.py
+++ b/lib/test/apyfixed/test_quantization.py
@@ -6,422 +6,421 @@
 
 def test_trn():
     mode = QuantizationMode.TRN
-    assert float(APyFixed.from_float(-0.75, 3, 1).cast(5, 1, mode)) == -0.75
-    assert float(APyFixed.from_float(-0.75, 3, 1).cast(2, 1, mode)) == -1.0
-    assert float(APyFixed.from_float(-0.75, 4, 1).cast(3, 1, mode)) == -0.75
-    assert float(APyFixed.from_float(-0.875, 4, 1).cast(3, 1, mode)) == -1.0
-    assert float(APyFixed.from_float(0.75, 3, 1).cast(2, 1, mode)) == 0.5
-    assert float(APyFixed.from_float(0.75, 4, 1).cast(3, 1, mode)) == 0.75
-    assert float(APyFixed.from_float(0.875, 4, 1).cast(3, 1, mode)) == 0.75
-
-    assert float(APyFixed(0b10000, 5, 0).cast(5, 5, mode)) == -1.0
-    assert float(APyFixed(0b10001, 5, 0).cast(5, 5, mode)) == -1.0
-    assert float(APyFixed(0b11111, 5, 0).cast(5, 5, mode)) == -1.0
-    assert float(APyFixed(0b01001, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01000, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00001, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00000, 5, 0).cast(5, 5, mode)) == 0.0
-
-    assert float(APyFixed(0b10000, 5, -1).cast(5, 5, mode)) == -1.0
-    assert float(APyFixed(0b10001, 5, -1).cast(5, 5, mode)) == -1.0
-    assert float(APyFixed(0b11111, 5, -1).cast(5, 5, mode)) == -1.0
-    assert float(APyFixed(0b01001, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01000, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00001, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00000, 5, -1).cast(5, 5, mode)) == 0.0
+    assert float(APyFixed.from_float(-0.75, 1, 2).cast(1, 4, mode)) == -0.75
+    assert float(APyFixed.from_float(-0.75, 1, 2).cast(2, 1, mode)) == -1.0
+    assert float(APyFixed.from_float(-0.75, 1, 3).cast(1, 2, mode)) == -0.75
+    assert float(APyFixed.from_float(-0.875, 1, 3).cast(1, 2, mode)) == -1.0
+    assert float(APyFixed.from_float(0.75, 1, 2).cast(1, 1, mode)) == 0.5
+    assert float(APyFixed.from_float(0.75, 1, 3).cast(1, 2, mode)) == 0.75
+    assert float(APyFixed.from_float(0.875, 1, 3).cast(1, 2, mode)) == 0.75
+
+    assert float(APyFixed(0b10000, 0, 5).cast(5, 0, mode)) == -1.0
+    assert float(APyFixed(0b10001, 0, 5).cast(5, 0, mode)) == -1.0
+    assert float(APyFixed(0b11111, 0, 5).cast(5, 0, mode)) == -1.0
+    assert float(APyFixed(0b01001, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01000, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00001, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00000, 0, 5).cast(5, 0, mode)) == 0.0
+
+    assert float(APyFixed(0b10000, -1, 6).cast(5, 0, mode)) == -1.0
+    assert float(APyFixed(0b10001, -1, 6).cast(5, 0, mode)) == -1.0
+    assert float(APyFixed(0b11111, -1, 6).cast(5, 0, mode)) == -1.0
+    assert float(APyFixed(0b01001, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01000, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00001, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00000, -1, 6).cast(5, 0, mode)) == 0.0
 
 
 def test_trn_inf():
     mode = QuantizationMode.TRN_INF
-    assert float(APyFixed.from_float(-0.75, 3, 1).cast(5, 1, mode)) == -0.75
-    assert float(APyFixed.from_float(-0.75, 3, 1).cast(2, 1, mode)) == -0.5
-    assert float(APyFixed.from_float(-0.75, 4, 1).cast(3, 1, mode)) == -0.75
-    assert float(APyFixed.from_float(-0.875, 4, 1).cast(3, 1, mode)) == -0.75
-    assert float(APyFixed.from_float(0.75, 3, 1).cast(2, 2, mode)) == 1.0
-    assert float(APyFixed.from_float(0.75, 3, 1).cast(2, 1, mode)) == -1.0
-    assert float(APyFixed.from_float(0.75, 4, 1).cast(3, 1, mode)) == 0.75
-    assert float(APyFixed.from_float(0.875, 4, 1).cast(3, 1, mode)) == -1.0
-    assert float(APyFixed.from_float(0.875, 4, 1).cast(3, 2, mode)) == 1.0
-
-    assert float(APyFixed(0b10000, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b10001, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b11111, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01001, 5, 0).cast(5, 5, mode)) == 1.0
-    assert float(APyFixed(0b01000, 5, 0).cast(5, 5, mode)) == 1.0
-    assert float(APyFixed(0b00001, 5, 0).cast(5, 5, mode)) == 1.0
-    assert float(APyFixed(0b00000, 5, 0).cast(5, 5, mode)) == 0.0
-
-    assert float(APyFixed(0b10000, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b10001, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b11111, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01001, 5, -1).cast(5, 5, mode)) == 1.0
-    assert float(APyFixed(0b01000, 5, -1).cast(5, 5, mode)) == 1.0
-    assert float(APyFixed(0b00001, 5, -1).cast(5, 5, mode)) == 1.0
-    assert float(APyFixed(0b00000, 5, -1).cast(5, 5, mode)) == 0.0
+    assert float(APyFixed.from_float(-0.75, 1, 2).cast(1, 4, mode)) == -0.75
+    assert float(APyFixed.from_float(-0.75, 1, 2).cast(1, 1, mode)) == -0.5
+    assert float(APyFixed.from_float(-0.75, 1, 3).cast(1, 2, mode)) == -0.75
+    assert float(APyFixed.from_float(-0.875, 1, 3).cast(1, 2, mode)) == -0.75
+    assert float(APyFixed.from_float(0.75, 1, 2).cast(2, 0, mode)) == 1.0
+    assert float(APyFixed.from_float(0.75, 1, 2).cast(1, 1, mode)) == -1.0
+    assert float(APyFixed.from_float(0.75, 1, 3).cast(1, 2, mode)) == 0.75
+    assert float(APyFixed.from_float(0.875, 1, 3).cast(1, 2, mode)) == -1.0
+    assert float(APyFixed.from_float(0.875, 1, 3).cast(2, 1, mode)) == 1.0
+
+    assert float(APyFixed(0b10000, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b10001, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b11111, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01001, 0, 5).cast(5, 0, mode)) == 1.0
+    assert float(APyFixed(0b01000, 0, 5).cast(5, 0, mode)) == 1.0
+    assert float(APyFixed(0b00001, 0, 5).cast(5, 0, mode)) == 1.0
+    assert float(APyFixed(0b00000, 0, 5).cast(5, 0, mode)) == 0.0
+
+    assert float(APyFixed(0b10000, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b10001, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b11111, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01001, -1, 6).cast(5, 0, mode)) == 1.0
+    assert float(APyFixed(0b01000, -1, 6).cast(5, 0, mode)) == 1.0
+    assert float(APyFixed(0b00001, -1, 6).cast(5, 0, mode)) == 1.0
+    assert float(APyFixed(0b00000, -1, 6).cast(5, 0, mode)) == 0.0
 
 
 def test_trn_away():
     mode = QuantizationMode.TRN_AWAY
-    assert float(APyFixed.from_float(-0.75, 3, 1).cast(5, 1, mode)) == -0.75
-    assert float(APyFixed.from_float(-0.75, 3, 1).cast(2, 1, mode)) == -1.0
-    assert float(APyFixed.from_float(-0.75, 4, 1).cast(3, 1, mode)) == -0.75
-    assert float(APyFixed.from_float(-0.875, 4, 1).cast(3, 1, mode)) == -1.0
-    assert float(APyFixed.from_float(0.75, 3, 1).cast(2, 2, mode)) == 1.0
-    assert float(APyFixed.from_float(0.75, 3, 1).cast(2, 1, mode)) == -1.0
-    assert float(APyFixed.from_float(0.75, 4, 1).cast(3, 1, mode)) == 0.75
-    assert float(APyFixed.from_float(0.875, 4, 1).cast(3, 1, mode)) == -1.0
-    assert float(APyFixed.from_float(0.875, 4, 1).cast(3, 2, mode)) == 1.0
-
-    assert float(APyFixed(0b10000, 5, 0).cast(5, 5, mode)) == -1.0
-    assert float(APyFixed(0b10001, 5, 0).cast(5, 5, mode)) == -1.0
-    assert float(APyFixed(0b11111, 5, 0).cast(5, 5, mode)) == -1.0
-    assert float(APyFixed(0b01001, 5, 0).cast(5, 5, mode)) == 1.0
-    assert float(APyFixed(0b01000, 5, 0).cast(5, 5, mode)) == 1.0
-    assert float(APyFixed(0b00001, 5, 0).cast(5, 5, mode)) == 1.0
-    assert float(APyFixed(0b00000, 5, 0).cast(5, 5, mode)) == 0.0
-
-    assert float(APyFixed(0b10000, 5, -1).cast(5, 5, mode)) == -1.0
-    assert float(APyFixed(0b10001, 5, -1).cast(5, 5, mode)) == -1.0
-    assert float(APyFixed(0b11111, 5, -1).cast(5, 5, mode)) == -1.0
-    assert float(APyFixed(0b01001, 5, -1).cast(5, 5, mode)) == 1.0
-    assert float(APyFixed(0b01000, 5, -1).cast(5, 5, mode)) == 1.0
-    assert float(APyFixed(0b00001, 5, -1).cast(5, 5, mode)) == 1.0
-    assert float(APyFixed(0b00000, 5, -1).cast(5, 5, mode)) == 0.0
+    assert float(APyFixed.from_float(-0.75, 1, 2).cast(1, 4, mode)) == -0.75
+    assert float(APyFixed.from_float(-0.75, 1, 2).cast(1, 1, mode)) == -1.0
+    assert float(APyFixed.from_float(-0.75, 1, 3).cast(1, 2, mode)) == -0.75
+    assert float(APyFixed.from_float(-0.875, 1, 3).cast(1, 2, mode)) == -1.0
+    assert float(APyFixed.from_float(0.75, 1, 2).cast(2, 0, mode)) == 1.0
+    assert float(APyFixed.from_float(0.75, 1, 2).cast(1, 1, mode)) == -1.0
+    assert float(APyFixed.from_float(0.75, 1, 3).cast(1, 2, mode)) == 0.75
+    assert float(APyFixed.from_float(0.875, 1, 3).cast(1, 2, mode)) == -1.0
+    assert float(APyFixed.from_float(0.875, 1, 3).cast(2, 1, mode)) == 1.0
+
+    assert float(APyFixed(0b10000, 0, 5).cast(5, 0, mode)) == -1.0
+    assert float(APyFixed(0b10001, 0, 5).cast(5, 0, mode)) == -1.0
+    assert float(APyFixed(0b11111, 0, 5).cast(5, 0, mode)) == -1.0
+    assert float(APyFixed(0b01001, 0, 5).cast(5, 0, mode)) == 1.0
+    assert float(APyFixed(0b01000, 0, 5).cast(5, 0, mode)) == 1.0
+    assert float(APyFixed(0b00001, 0, 5).cast(5, 0, mode)) == 1.0
+    assert float(APyFixed(0b00000, 0, 5).cast(5, 0, mode)) == 0.0
+
+    assert float(APyFixed(0b10000, -1, 6).cast(5, 0, mode)) == -1.0
+    assert float(APyFixed(0b10001, -1, 6).cast(5, 0, mode)) == -1.0
+    assert float(APyFixed(0b11111, -1, 6).cast(5, 0, mode)) == -1.0
+    assert float(APyFixed(0b01001, -1, 6).cast(5, 0, mode)) == 1.0
+    assert float(APyFixed(0b01000, -1, 6).cast(5, 0, mode)) == 1.0
+    assert float(APyFixed(0b00001, -1, 6).cast(5, 0, mode)) == 1.0
+    assert float(APyFixed(0b00000, -1, 6).cast(5, 0, mode)) == 0.0
 
 
 def test_trn_zero():
     mode = QuantizationMode.TRN_ZERO
-    assert float(APyFixed.from_float(-0.75, 3, 1).cast(5, 1, mode)) == -0.75
-    assert float(APyFixed.from_float(-0.75, 3, 1).cast(2, 1, mode)) == -0.5
-    assert float(APyFixed.from_float(-0.75, 4, 1).cast(3, 1, mode)) == -0.75
-    assert float(APyFixed.from_float(-0.875, 4, 1).cast(3, 1, mode)) == -0.75
-    assert float(APyFixed.from_float(0.75, 3, 1).cast(2, 2, mode)) == 0.0
-    assert float(APyFixed.from_float(0.75, 3, 1).cast(2, 1, mode)) == 0.5
-    assert float(APyFixed.from_float(0.75, 4, 1).cast(3, 1, mode)) == 0.75
-    assert float(APyFixed.from_float(0.875, 4, 1).cast(3, 1, mode)) == 0.75
-    assert float(APyFixed.from_float(0.875, 4, 1).cast(3, 2, mode)) == 0.5
-
-    assert float(APyFixed(0b10000, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b10001, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b11111, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01001, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01000, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00001, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00000, 5, 0).cast(5, 5, mode)) == 0.0
-
-    assert float(APyFixed(0b10000, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b10001, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b11111, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01001, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01000, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00001, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00000, 5, -1).cast(5, 5, mode)) == 0.0
+    assert float(APyFixed.from_float(-0.75, 1, 2).cast(1, 4, mode)) == -0.75
+    assert float(APyFixed.from_float(-0.75, 1, 2).cast(1, 1, mode)) == -0.5
+    assert float(APyFixed.from_float(-0.75, 1, 3).cast(1, 2, mode)) == -0.75
+    assert float(APyFixed.from_float(-0.875, 1, 3).cast(1, 2, mode)) == -0.75
+    assert float(APyFixed.from_float(0.75, 1, 2).cast(2, 0, mode)) == 0.0
+    assert float(APyFixed.from_float(0.75, 1, 2).cast(1, 1, mode)) == 0.5
+    assert float(APyFixed.from_float(0.75, 1, 3).cast(1, 2, mode)) == 0.75
+    assert float(APyFixed.from_float(0.875, 1, 3).cast(1, 2, mode)) == 0.75
+    assert float(APyFixed.from_float(0.875, 1, 3).cast(2, 1, mode)) == 0.5
+
+    assert float(APyFixed(0b10000, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b10001, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b11111, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01001, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01000, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00001, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00000, 0, 5).cast(5, 0, mode)) == 0.0
+
+    assert float(APyFixed(0b10000, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b10001, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b11111, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01001, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01000, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00001, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00000, -1, 6).cast(5, 0, mode)) == 0.0
 
 
 def test_trn_mag():
     mode = QuantizationMode.TRN_MAG
-    assert float(APyFixed.from_float(-0.75, 3, 1).cast(5, 1, mode)) == -0.75
-    assert float(APyFixed.from_float(-0.75, 3, 1).cast(2, 1, mode)) == -0.5
-    assert float(APyFixed.from_float(-0.75, 4, 1).cast(3, 1, mode)) == -0.5
-    assert float(APyFixed.from_float(-0.875, 4, 1).cast(3, 1, mode)) == -0.75
-    assert float(APyFixed.from_float(0.75, 3, 1).cast(2, 1, mode)) == 0.5
-    assert float(APyFixed.from_float(0.75, 4, 1).cast(3, 1, mode)) == 0.75
-    assert float(APyFixed.from_float(0.875, 4, 1).cast(3, 1, mode)) == 0.75
-
-    assert float(APyFixed(0b10000, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b10001, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b11111, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01001, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01000, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00001, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00000, 5, 0).cast(5, 5, mode)) == 0.0
-
-    assert float(APyFixed(0b10000, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b10001, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b11111, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01001, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01000, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00001, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00000, 5, -1).cast(5, 5, mode)) == 0.0
+    assert float(APyFixed.from_float(-0.75, 1, 2).cast(1, 4, mode)) == -0.75
+    assert float(APyFixed.from_float(-0.75, 1, 2).cast(1, 1, mode)) == -0.5
+    assert float(APyFixed.from_float(-0.75, 1, 3).cast(1, 2, mode)) == -0.5
+    assert float(APyFixed.from_float(-0.875, 1, 3).cast(1, 2, mode)) == -0.75
+    assert float(APyFixed.from_float(0.75, 1, 2).cast(1, 1, mode)) == 0.5
+    assert float(APyFixed.from_float(0.75, 1, 3).cast(1, 2, mode)) == 0.75
+    assert float(APyFixed.from_float(0.875, 1, 3).cast(1, 2, mode)) == 0.75
+
+    assert float(APyFixed(0b10000, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b10001, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b11111, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01001, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01000, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00001, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00000, 0, 5).cast(5, 0, mode)) == 0.0
+
+    assert float(APyFixed(0b10000, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b10001, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b11111, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01001, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01000, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00001, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00000, -1, 6).cast(5, 0, mode)) == 0.0
 
 
 def test_rnd():
     mode = QuantizationMode.RND
-    assert float(APyFixed.from_float(-0.75, 3, 1).cast(5, 1, mode)) == -0.75
-    assert float(APyFixed.from_float(-0.75, 3, 1).cast(2, 1, mode)) == -0.5
-    assert float(APyFixed.from_float(-0.75, 4, 1).cast(3, 1, mode)) == -0.75
-    assert float(APyFixed.from_float(-0.875, 4, 1).cast(3, 1, mode)) == -0.75
-    assert float(APyFixed.from_float(0.75, 3, 1).cast(2, 2, mode)) == 1.0
-    assert float(APyFixed.from_float(0.75, 3, 1).cast(2, 1, mode)) == -1.0
-    assert float(APyFixed.from_float(0.75, 4, 1).cast(3, 1, mode)) == 0.75
-    assert float(APyFixed.from_float(0.875, 4, 1).cast(3, 2, mode)) == 1.0
-    assert float(APyFixed.from_float(0.875, 4, 1).cast(3, 1, mode)) == -1.0
-
-    assert float(APyFixed(0b10000, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b10001, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b11111, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01001, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01000, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00001, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00000, 5, 0).cast(5, 5, mode)) == 0.0
-
-    assert float(APyFixed(0b10000, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b10001, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b11111, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01001, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01000, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00001, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00000, 5, -1).cast(5, 5, mode)) == 0.0
+    assert float(APyFixed.from_float(-0.75, 1, 2).cast(1, 4, mode)) == -0.75
+    assert float(APyFixed.from_float(-0.75, 1, 2).cast(1, 1, mode)) == -0.5
+    assert float(APyFixed.from_float(-0.75, 1, 3).cast(1, 2, mode)) == -0.75
+    assert float(APyFixed.from_float(-0.875, 1, 3).cast(1, 2, mode)) == -0.75
+    assert float(APyFixed.from_float(0.75, 1, 2).cast(2, 0, mode)) == 1.0
+    assert float(APyFixed.from_float(0.75, 1, 2).cast(1, 1, mode)) == -1.0
+    assert float(APyFixed.from_float(0.75, 1, 3).cast(1, 2, mode)) == 0.75
+    assert float(APyFixed.from_float(0.875, 1, 3).cast(2, 1, mode)) == 1.0
+    assert float(APyFixed.from_float(0.875, 1, 3).cast(1, 2, mode)) == -1.0
+
+    assert float(APyFixed(0b10000, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b10001, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b11111, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01001, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01000, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00001, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00000, 0, 5).cast(5, 0, mode)) == 0.0
+
+    assert float(APyFixed(0b10000, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b10001, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b11111, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01001, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01000, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00001, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00000, -1, 6).cast(5, 0, mode)) == 0.0
 
 
 def test_rnd_zero():
     mode = QuantizationMode.RND_ZERO
-    assert float(APyFixed.from_float(-0.75, 3, 1).cast(5, 1, mode)) == -0.75
-    assert float(APyFixed.from_float(-0.75, 3, 1).cast(2, 1, mode)) == -0.5
-    assert float(APyFixed.from_float(-0.75, 4, 1).cast(3, 1, mode)) == -0.75
-    assert float(APyFixed.from_float(-0.875, 4, 1).cast(3, 1, mode)) == -0.75
-    assert float(APyFixed.from_float(0.75, 3, 1).cast(2, 2, mode)) == 1.0
-    assert float(APyFixed.from_float(0.75, 3, 1).cast(2, 1, mode)) == 0.5
-    assert float(APyFixed.from_float(0.75, 4, 1).cast(3, 1, mode)) == 0.75
-    assert float(APyFixed.from_float(0.875, 4, 1).cast(3, 2, mode)) == 1.0
-    assert float(APyFixed.from_float(0.875, 4, 1).cast(3, 1, mode)) == 0.75
-
-    assert float(APyFixed(0b10000, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b10001, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b11111, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01001, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01000, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00001, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00000, 5, 0).cast(5, 5, mode)) == 0.0
-
-    assert float(APyFixed(0b10000, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b10001, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b11111, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01001, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01000, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00001, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00000, 5, -1).cast(5, 5, mode)) == 0.0
+    assert float(APyFixed.from_float(-0.75, 1, 2).cast(1, 4, mode)) == -0.75
+    assert float(APyFixed.from_float(-0.75, 1, 2).cast(1, 1, mode)) == -0.5
+    assert float(APyFixed.from_float(-0.75, 1, 3).cast(1, 2, mode)) == -0.75
+    assert float(APyFixed.from_float(-0.875, 1, 3).cast(1, 2, mode)) == -0.75
+    assert float(APyFixed.from_float(0.75, 1, 2).cast(2, 0, mode)) == 1.0
+    assert float(APyFixed.from_float(0.75, 1, 2).cast(1, 1, mode)) == 0.5
+    assert float(APyFixed.from_float(0.75, 1, 3).cast(1, 2, mode)) == 0.75
+    assert float(APyFixed.from_float(0.875, 1, 3).cast(2, 1, mode)) == 1.0
+    assert float(APyFixed.from_float(0.875, 1, 3).cast(1, 2, mode)) == 0.75
+
+    assert float(APyFixed(0b10000, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b10001, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b11111, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01001, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01000, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00001, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00000, 0, 5).cast(5, 0, mode)) == 0.0
+
+    assert float(APyFixed(0b10000, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b10001, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b11111, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01001, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01000, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00001, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00000, -1, 6).cast(5, 0, mode)) == 0.0
 
 
 def test_rnd_inf():
     mode = QuantizationMode.RND_INF
-    assert float(APyFixed.from_float(-0.75, 3, 1).cast(5, 1, mode)) == -0.75
-    assert float(APyFixed.from_float(-0.75, 3, 1).cast(2, 1, mode)) == -1.0
-    assert float(APyFixed.from_float(-0.75, 4, 1).cast(3, 1, mode)) == -0.75
-    assert float(APyFixed.from_float(-0.875, 4, 1).cast(3, 1, mode)) == -1.0
-    assert float(APyFixed.from_float(0.75, 3, 1).cast(2, 2, mode)) == 1.0
-    assert float(APyFixed.from_float(0.75, 3, 1).cast(2, 1, mode)) == -1.0
-    assert float(APyFixed.from_float(0.75, 4, 1).cast(3, 1, mode)) == 0.75
-    assert float(APyFixed.from_float(0.875, 4, 1).cast(3, 2, mode)) == 1.0
-    assert float(APyFixed.from_float(0.875, 4, 1).cast(3, 1, mode)) == -1.0
-    assert float(APyFixed.from_float(0.875, 4, 1).cast(2, 1, mode)) == -1.0
-    assert float(APyFixed.from_float(0.25, 4, 2).cast(2, 2, mode)) == 0.0
-    assert float(APyFixed.from_float(0.50, 4, 2).cast(2, 2, mode)) == 1.0
-    assert float(APyFixed.from_float(0.75, 4, 2).cast(2, 2, mode)) == 1.0
-    assert float(APyFixed.from_float(-0.25, 4, 2).cast(2, 2, mode)) == 0.0
-    assert float(APyFixed.from_float(-0.50, 4, 2).cast(2, 2, mode)) == -1.0
-    assert float(APyFixed.from_float(-0.75, 4, 2).cast(2, 2, mode)) == -1.0
-
-    assert float(APyFixed(0b10000, 5, 0).cast(5, 5, mode)) == -1.0
-    assert float(APyFixed(0b10001, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b11111, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01001, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01000, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00001, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00000, 5, 0).cast(5, 5, mode)) == 0.0
-
-    assert float(APyFixed(0b10000, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b10001, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b11111, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01001, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01000, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00001, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00000, 5, -1).cast(5, 5, mode)) == 0.0
+    assert float(APyFixed.from_float(-0.75, 1, 2).cast(1, 4, mode)) == -0.75
+    assert float(APyFixed.from_float(-0.75, 1, 2).cast(1, 1, mode)) == -1.0
+    assert float(APyFixed.from_float(-0.75, 1, 3).cast(1, 2, mode)) == -0.75
+    assert float(APyFixed.from_float(-0.875, 1, 3).cast(1, 2, mode)) == -1.0
+    assert float(APyFixed.from_float(0.75, 1, 2).cast(2, 0, mode)) == 1.0
+    assert float(APyFixed.from_float(0.75, 1, 2).cast(1, 1, mode)) == -1.0
+    assert float(APyFixed.from_float(0.75, 1, 3).cast(1, 2, mode)) == 0.75
+    assert float(APyFixed.from_float(0.875, 1, 3).cast(2, 1, mode)) == 1.0
+    assert float(APyFixed.from_float(0.875, 1, 3).cast(1, 2, mode)) == -1.0
+    assert float(APyFixed.from_float(0.875, 1, 3).cast(1, 1, mode)) == -1.0
+    assert float(APyFixed.from_float(0.25, 2, 2).cast(2, 0, mode)) == 0.0
+    assert float(APyFixed.from_float(0.50, 2, 2).cast(2, 0, mode)) == 1.0
+    assert float(APyFixed.from_float(0.75, 2, 2).cast(2, 0, mode)) == 1.0
+    assert float(APyFixed.from_float(-0.25, 2, 2).cast(2, 0, mode)) == 0.0
+    assert float(APyFixed.from_float(-0.50, 2, 2).cast(2, 0, mode)) == -1.0
+    assert float(APyFixed.from_float(-0.75, 2, 2).cast(2, 0, mode)) == -1.0
+
+    assert float(APyFixed(0b10000, 0, 5).cast(5, 0, mode)) == -1.0
+    assert float(APyFixed(0b10001, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b11111, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01001, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01000, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00001, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00000, 0, 5).cast(5, 0, mode)) == 0.0
+
+    assert float(APyFixed(0b10000, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b10001, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b11111, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01001, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01000, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00001, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00000, -1, 6).cast(5, 0, mode)) == 0.0
 
 
 def test_rnd_min_inf():
     mode = QuantizationMode.RND_MIN_INF
-    assert float(APyFixed.from_float(-0.75, 3, 1).cast(5, 1, mode)) == -0.75
-    assert float(APyFixed.from_float(-0.75, 3, 1).cast(2, 1, mode)) == -1.0
-    assert float(APyFixed.from_float(-0.75, 4, 1).cast(3, 1, mode)) == -0.75
-    assert float(APyFixed.from_float(-0.875, 4, 1).cast(3, 1, mode)) == -1.0
-    assert float(APyFixed.from_float(0.75, 3, 1).cast(2, 2, mode)) == 1.0
-    assert float(APyFixed.from_float(0.75, 3, 1).cast(2, 1, mode)) == 0.5
-    assert float(APyFixed.from_float(0.75, 4, 1).cast(3, 1, mode)) == 0.75
-    assert float(APyFixed.from_float(0.875, 4, 1).cast(3, 2, mode)) == 1.0
-    assert float(APyFixed.from_float(0.875, 4, 1).cast(3, 1, mode)) == 0.75
-    assert float(APyFixed.from_float(0.875, 4, 1).cast(2, 1, mode)) == -1.0
-    assert float(APyFixed.from_float(0.875, 4, 1).cast(2, 1, mode)) == -1.0
-    assert float(APyFixed.from_float(0.25, 4, 2).cast(2, 2, mode)) == 0.0
-    assert float(APyFixed.from_float(0.50, 4, 2).cast(2, 2, mode)) == 0.0
-    assert float(APyFixed.from_float(0.75, 4, 2).cast(2, 2, mode)) == 1.0
-    assert float(APyFixed.from_float(-0.25, 4, 2).cast(2, 2, mode)) == 0.0
-    assert float(APyFixed.from_float(-0.50, 4, 2).cast(2, 2, mode)) == -1.0
-    assert float(APyFixed.from_float(-0.75, 4, 2).cast(2, 2, mode)) == -1.0
-
-    assert float(APyFixed(0b10000, 5, 0).cast(5, 5, mode)) == -1.0
-    assert float(APyFixed(0b10001, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b11111, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01001, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01000, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00001, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00000, 5, 0).cast(5, 5, mode)) == 0.0
-
-    assert float(APyFixed(0b10000, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b10001, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b11111, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01001, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01000, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00001, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00000, 5, -1).cast(5, 5, mode)) == 0.0
+    assert float(APyFixed.from_float(-0.75, 1, 2).cast(1, 4, mode)) == -0.75
+    assert float(APyFixed.from_float(-0.75, 1, 2).cast(1, 1, mode)) == -1.0
+    assert float(APyFixed.from_float(-0.75, 1, 3).cast(1, 2, mode)) == -0.75
+    assert float(APyFixed.from_float(-0.875, 1, 3).cast(1, 2, mode)) == -1.0
+    assert float(APyFixed.from_float(0.75, 1, 2).cast(2, 0, mode)) == 1.0
+    assert float(APyFixed.from_float(0.75, 1, 2).cast(1, 1, mode)) == 0.5
+    assert float(APyFixed.from_float(0.75, 1, 3).cast(1, 2, mode)) == 0.75
+    assert float(APyFixed.from_float(0.875, 1, 3).cast(2, 1, mode)) == 1.0
+    assert float(APyFixed.from_float(0.875, 1, 3).cast(1, 2, mode)) == 0.75
+    assert float(APyFixed.from_float(0.875, 1, 3).cast(1, 1, mode)) == -1.0
+    assert float(APyFixed.from_float(0.25, 2, 2).cast(2, 0, mode)) == 0.0
+    assert float(APyFixed.from_float(0.50, 2, 2).cast(2, 0, mode)) == 0.0
+    assert float(APyFixed.from_float(0.75, 2, 2).cast(2, 0, mode)) == 1.0
+    assert float(APyFixed.from_float(-0.25, 2, 2).cast(2, 0, mode)) == 0.0
+    assert float(APyFixed.from_float(-0.50, 2, 2).cast(2, 0, mode)) == -1.0
+    assert float(APyFixed.from_float(-0.75, 2, 2).cast(2, 0, mode)) == -1.0
+
+    assert float(APyFixed(0b10000, 0, 5).cast(5, 0, mode)) == -1.0
+    assert float(APyFixed(0b10001, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b11111, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01001, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01000, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00001, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00000, 0, 5).cast(5, 0, mode)) == 0.0
+
+    assert float(APyFixed(0b10000, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b10001, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b11111, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01001, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01000, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00001, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00000, -1, 6).cast(5, 0, mode)) == 0.0
 
 
 def test_rnd_conv():
     mode = QuantizationMode.RND_CONV
-    assert float(APyFixed.from_float(-0.75, 3, 1).cast(5, 1, mode)) == -0.75
-    assert float(APyFixed.from_float(-0.25, 5, 3).cast(3, 3, mode)) == 0.0
-    assert float(APyFixed.from_float(-0.50, 5, 3).cast(3, 3, mode)) == 0.0
-    assert float(APyFixed.from_float(-0.75, 5, 3).cast(3, 3, mode)) == -1.0
-    assert float(APyFixed.from_float(-1.25, 5, 3).cast(3, 3, mode)) == -1.0
-    assert float(APyFixed.from_float(-1.50, 5, 3).cast(3, 3, mode)) == -2.0
-    assert float(APyFixed.from_float(-1.75, 5, 3).cast(3, 3, mode)) == -2.0
-    assert float(APyFixed.from_float(0.25, 5, 3).cast(3, 3, mode)) == 0.0
-    assert float(APyFixed.from_float(0.50, 5, 3).cast(3, 3, mode)) == 0.0
-    assert float(APyFixed.from_float(0.75, 5, 3).cast(3, 3, mode)) == 1.0
-    assert float(APyFixed.from_float(1.25, 5, 3).cast(3, 3, mode)) == 1.0
-    assert float(APyFixed.from_float(1.50, 5, 3).cast(3, 3, mode)) == 2.0
-    assert float(APyFixed.from_float(1.75, 5, 3).cast(3, 3, mode)) == 2.0
-
-    assert float(APyFixed(0b10000, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b10001, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b11111, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01001, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01000, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00001, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00000, 5, 0).cast(5, 5, mode)) == 0.0
-
-    assert float(APyFixed(0b10000, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b10001, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b11111, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01001, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01000, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00001, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00000, 5, -1).cast(5, 5, mode)) == 0.0
+    assert float(APyFixed.from_float(-0.75, 1, 2).cast(1, 4, mode)) == -0.75
+    assert float(APyFixed.from_float(-0.25, 3, 2).cast(3, 0, mode)) == 0.0
+    assert float(APyFixed.from_float(-0.50, 3, 2).cast(3, 0, mode)) == 0.0
+    assert float(APyFixed.from_float(-0.75, 3, 2).cast(3, 0, mode)) == -1.0
+    assert float(APyFixed.from_float(-1.25, 3, 2).cast(3, 0, mode)) == -1.0
+    assert float(APyFixed.from_float(-1.50, 3, 2).cast(3, 0, mode)) == -2.0
+    assert float(APyFixed.from_float(-1.75, 3, 2).cast(3, 0, mode)) == -2.0
+    assert float(APyFixed.from_float(0.25, 3, 2).cast(3, 0, mode)) == 0.0
+    assert float(APyFixed.from_float(0.50, 3, 2).cast(3, 0, mode)) == 0.0
+    assert float(APyFixed.from_float(0.75, 3, 2).cast(3, 0, mode)) == 1.0
+    assert float(APyFixed.from_float(1.25, 3, 2).cast(3, 0, mode)) == 1.0
+    assert float(APyFixed.from_float(1.50, 3, 2).cast(3, 0, mode)) == 2.0
+    assert float(APyFixed.from_float(1.75, 3, 2).cast(3, 0, mode)) == 2.0
+
+    assert float(APyFixed(0b10000, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b10001, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b11111, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01001, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01000, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00001, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00000, 0, 5).cast(5, 0, mode)) == 0.0
+
+    assert float(APyFixed(0b10000, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b10001, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b11111, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01001, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01000, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00001, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00000, -1, 6).cast(5, 0, mode)) == 0.0
 
 
 def test_rnd_conv_odd():
     mode = QuantizationMode.RND_CONV_ODD
-    assert float(APyFixed.from_float(-0.75, 3, 1).cast(5, 1, mode)) == -0.75
-    assert float(APyFixed.from_float(-0.25, 5, 3).cast(3, 3, mode)) == 0.0
-    assert float(APyFixed.from_float(-0.50, 5, 3).cast(3, 3, mode)) == -1.0
-    assert float(APyFixed.from_float(-0.75, 5, 3).cast(3, 3, mode)) == -1.0
-    assert float(APyFixed.from_float(-1.25, 5, 3).cast(3, 3, mode)) == -1.0
-    assert float(APyFixed.from_float(-1.50, 5, 3).cast(3, 3, mode)) == -1.0
-    assert float(APyFixed.from_float(-1.75, 5, 3).cast(3, 3, mode)) == -2.0
-    assert float(APyFixed.from_float(0.25, 5, 3).cast(3, 3, mode)) == 0.0
-    assert float(APyFixed.from_float(0.50, 5, 3).cast(3, 3, mode)) == 1.0
-    assert float(APyFixed.from_float(0.75, 5, 3).cast(3, 3, mode)) == 1.0
-    assert float(APyFixed.from_float(1.25, 5, 3).cast(3, 3, mode)) == 1.0
-    assert float(APyFixed.from_float(1.50, 5, 3).cast(3, 3, mode)) == 1.0
-    assert float(APyFixed.from_float(1.75, 5, 3).cast(3, 3, mode)) == 2.0
-
-    assert float(APyFixed(0b10000, 5, 0).cast(5, 5, mode)) == -1.0
-    assert float(APyFixed(0b10001, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b11111, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01001, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01000, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00001, 5, 0).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00000, 5, 0).cast(5, 5, mode)) == 0.0
-
-    assert float(APyFixed(0b10000, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b10001, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b11111, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01001, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b01000, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00001, 5, -1).cast(5, 5, mode)) == 0.0
-    assert float(APyFixed(0b00000, 5, -1).cast(5, 5, mode)) == 0.0
+    assert float(APyFixed.from_float(-0.75, 1, 2).cast(1, 4, mode)) == -0.75
+    assert float(APyFixed.from_float(-0.25, 3, 2).cast(3, 0, mode)) == 0.0
+    assert float(APyFixed.from_float(-0.50, 3, 2).cast(3, 0, mode)) == -1.0
+    assert float(APyFixed.from_float(-0.75, 3, 2).cast(3, 0, mode)) == -1.0
+    assert float(APyFixed.from_float(-1.25, 3, 2).cast(3, 0, mode)) == -1.0
+    assert float(APyFixed.from_float(-1.50, 3, 2).cast(3, 0, mode)) == -1.0
+    assert float(APyFixed.from_float(-1.75, 3, 2).cast(3, 0, mode)) == -2.0
+    assert float(APyFixed.from_float(0.25, 3, 2).cast(3, 0, mode)) == 0.0
+    assert float(APyFixed.from_float(0.50, 3, 2).cast(3, 0, mode)) == 1.0
+    assert float(APyFixed.from_float(0.75, 3, 2).cast(3, 0, mode)) == 1.0
+    assert float(APyFixed.from_float(1.25, 3, 2).cast(3, 0, mode)) == 1.0
+    assert float(APyFixed.from_float(1.50, 3, 2).cast(3, 0, mode)) == 1.0
+    assert float(APyFixed.from_float(1.75, 3, 2).cast(3, 0, mode)) == 2.0
+
+    assert float(APyFixed(0b10000, 0, 5).cast(5, 0, mode)) == -1.0
+    assert float(APyFixed(0b10001, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b11111, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01001, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01000, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00001, 0, 5).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00000, 0, 5).cast(5, 0, mode)) == 0.0
+
+    assert float(APyFixed(0b10000, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b10001, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b11111, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01001, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b01000, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00001, -1, 6).cast(5, 0, mode)) == 0.0
+    assert float(APyFixed(0b00000, -1, 6).cast(5, 0, mode)) == 0.0
 
 
 def test_jam():
     mode = QuantizationMode.JAM
-    assert float(APyFixed.from_float(-0.75, 3, 1).cast(5, 1, mode)) == -0.6875
-
-    assert float(APyFixed.from_float(-2.25, 5, 3).cast(3, 3, mode)) == -3.0
-    assert float(APyFixed.from_float(-2.00, 5, 3).cast(3, 3, mode)) == -1.0
-    assert float(APyFixed.from_float(-1.75, 5, 3).cast(3, 3, mode)) == -1.0
-    assert float(APyFixed.from_float(-1.50, 5, 3).cast(3, 3, mode)) == -1.0
-    assert float(APyFixed.from_float(-1.25, 5, 3).cast(3, 3, mode)) == -1.0
-    assert float(APyFixed.from_float(-1.00, 5, 3).cast(3, 3, mode)) == -1.0
-    assert float(APyFixed.from_float(-0.75, 5, 3).cast(3, 3, mode)) == -1.0
-    assert float(APyFixed.from_float(-0.50, 5, 3).cast(3, 3, mode)) == -1.0
-    assert float(APyFixed.from_float(-0.25, 5, 3).cast(3, 3, mode)) == -1.0
-    assert float(APyFixed.from_float(0.00, 5, 3).cast(3, 3, mode)) == 1.0
-    assert float(APyFixed.from_float(0.25, 5, 3).cast(3, 3, mode)) == 1.0
-    assert float(APyFixed.from_float(0.50, 5, 3).cast(3, 3, mode)) == 1.0
-    assert float(APyFixed.from_float(0.75, 5, 3).cast(3, 3, mode)) == 1.0
-    assert float(APyFixed.from_float(1.00, 5, 3).cast(3, 3, mode)) == 1.0
-    assert float(APyFixed.from_float(1.25, 5, 3).cast(3, 3, mode)) == 1.0
-    assert float(APyFixed.from_float(1.50, 5, 3).cast(3, 3, mode)) == 1.0
-    assert float(APyFixed.from_float(1.75, 5, 3).cast(3, 3, mode)) == 1.0
-    assert float(APyFixed.from_float(2.00, 5, 3).cast(3, 3, mode)) == 3.0
-    assert float(APyFixed.from_float(2.25, 5, 3).cast(3, 3, mode)) == 3.0
-
-    assert float(APyFixed(0b10000, 5, 0).cast(5, 5, mode)) == -1.0
-    assert float(APyFixed(0b10001, 5, 0).cast(5, 5, mode)) == -1.0
-    assert float(APyFixed(0b11111, 5, 0).cast(5, 5, mode)) == -1.0
-    assert float(APyFixed(0b01001, 5, 0).cast(5, 5, mode)) == 1.0
-    assert float(APyFixed(0b01000, 5, 0).cast(5, 5, mode)) == 1.0
-    assert float(APyFixed(0b00001, 5, 0).cast(5, 5, mode)) == 1.0
-    assert float(APyFixed(0b00000, 5, 0).cast(5, 5, mode)) == 1.0
-
-    assert float(APyFixed(0b10000, 5, -1).cast(5, 5, mode)) == -1.0
-    assert float(APyFixed(0b10001, 5, -1).cast(5, 5, mode)) == -1.0
-    assert float(APyFixed(0b11111, 5, -1).cast(5, 5, mode)) == -1.0
-    assert float(APyFixed(0b01001, 5, -1).cast(5, 5, mode)) == 1.0
-    assert float(APyFixed(0b01000, 5, -1).cast(5, 5, mode)) == 1.0
-    assert float(APyFixed(0b00001, 5, -1).cast(5, 5, mode)) == 1.0
-    assert float(APyFixed(0b00000, 5, -1).cast(5, 5, mode)) == 1.0
+    assert float(APyFixed.from_float(-0.75, 1, 2).cast(1, 4, mode)) == -0.6875
+
+    assert float(APyFixed.from_float(-2.25, 3, 2).cast(3, 0, mode)) == -3.0
+    assert float(APyFixed.from_float(-2.00, 3, 2).cast(3, 0, mode)) == -1.0
+    assert float(APyFixed.from_float(-1.75, 3, 2).cast(3, 0, mode)) == -1.0
+    assert float(APyFixed.from_float(-1.50, 3, 2).cast(3, 0, mode)) == -1.0
+    assert float(APyFixed.from_float(-1.25, 3, 2).cast(3, 0, mode)) == -1.0
+    assert float(APyFixed.from_float(-1.00, 3, 2).cast(3, 0, mode)) == -1.0
+    assert float(APyFixed.from_float(-0.75, 3, 2).cast(3, 0, mode)) == -1.0
+    assert float(APyFixed.from_float(-0.50, 3, 2).cast(3, 0, mode)) == -1.0
+    assert float(APyFixed.from_float(-0.25, 3, 2).cast(3, 0, mode)) == -1.0
+    assert float(APyFixed.from_float(0.00, 3, 2).cast(3, 0, mode)) == 1.0
+    assert float(APyFixed.from_float(0.25, 3, 2).cast(3, 0, mode)) == 1.0
+    assert float(APyFixed.from_float(0.50, 3, 2).cast(3, 0, mode)) == 1.0
+    assert float(APyFixed.from_float(0.75, 3, 2).cast(3, 0, mode)) == 1.0
+    assert float(APyFixed.from_float(1.00, 3, 2).cast(3, 0, mode)) == 1.0
+    assert float(APyFixed.from_float(1.25, 3, 2).cast(3, 0, mode)) == 1.0
+    assert float(APyFixed.from_float(1.50, 3, 2).cast(3, 0, mode)) == 1.0
+    assert float(APyFixed.from_float(1.75, 3, 2).cast(3, 0, mode)) == 1.0
+    assert float(APyFixed.from_float(2.00, 3, 2).cast(3, 0, mode)) == 3.0
+    assert float(APyFixed.from_float(2.25, 3, 2).cast(3, 0, mode)) == 3.0
+
+    assert float(APyFixed(0b10000, 0, 5).cast(5, 0, mode)) == -1.0
+    assert float(APyFixed(0b10001, 0, 5).cast(5, 0, mode)) == -1.0
+    assert float(APyFixed(0b11111, 0, 5).cast(5, 0, mode)) == -1.0
+    assert float(APyFixed(0b01001, 0, 5).cast(5, 0, mode)) == 1.0
+    assert float(APyFixed(0b01000, 0, 5).cast(5, 0, mode)) == 1.0
+    assert float(APyFixed(0b00001, 0, 5).cast(5, 0, mode)) == 1.0
+    assert float(APyFixed(0b00000, 0, 5).cast(5, 0, mode)) == 1.0
+
+    assert float(APyFixed(0b10000, -1, 6).cast(5, 0, mode)) == -1.0
+    assert float(APyFixed(0b10001, -1, 6).cast(5, 0, mode)) == -1.0
+    assert float(APyFixed(0b11111, -1, 6).cast(5, 0, mode)) == -1.0
+    assert float(APyFixed(0b01001, -1, 6).cast(5, 0, mode)) == 1.0
+    assert float(APyFixed(0b01000, -1, 6).cast(5, 0, mode)) == 1.0
+    assert float(APyFixed(0b00001, -1, 6).cast(5, 0, mode)) == 1.0
+    assert float(APyFixed(0b00000, -1, 6).cast(5, 0, mode)) == 1.0
 
 
 def test_jam_unbiased():
     mode = QuantizationMode.JAM_UNBIASED
-    assert float(APyFixed.from_float(-0.75, 3, 1).cast(5, 1, mode)) == -0.75
-
-    assert float(APyFixed.from_float(-2.25, 5, 3).cast(3, 3, mode)) == -3.0
-    assert float(APyFixed.from_float(-2.00, 5, 3).cast(3, 3, mode)) == -2.0
-    assert float(APyFixed.from_float(-1.75, 5, 3).cast(3, 3, mode)) == -1.0
-    assert float(APyFixed.from_float(-1.50, 5, 3).cast(3, 3, mode)) == -1.0
-    assert float(APyFixed.from_float(-1.25, 5, 3).cast(3, 3, mode)) == -1.0
-    assert float(APyFixed.from_float(-1.00, 5, 3).cast(3, 3, mode)) == -1.0
-    assert float(APyFixed.from_float(-0.75, 5, 3).cast(3, 3, mode)) == -1.0
-    assert float(APyFixed.from_float(-0.50, 5, 3).cast(3, 3, mode)) == -1.0
-    assert float(APyFixed.from_float(-0.25, 5, 3).cast(3, 3, mode)) == -1.0
-    assert float(APyFixed.from_float(0.00, 5, 3).cast(3, 3, mode)) == 0.0
-    assert float(APyFixed.from_float(0.25, 5, 3).cast(3, 3, mode)) == 1.0
-    assert float(APyFixed.from_float(0.50, 5, 3).cast(3, 3, mode)) == 1.0
-    assert float(APyFixed.from_float(0.75, 5, 3).cast(3, 3, mode)) == 1.0
-    assert float(APyFixed.from_float(1.00, 5, 3).cast(3, 3, mode)) == 1.0
-    assert float(APyFixed.from_float(1.25, 5, 3).cast(3, 3, mode)) == 1.0
-    assert float(APyFixed.from_float(1.50, 5, 3).cast(3, 3, mode)) == 1.0
-    assert float(APyFixed.from_float(1.75, 5, 3).cast(3, 3, mode)) == 1.0
-    assert float(APyFixed.from_float(2.00, 5, 3).cast(3, 3, mode)) == 2.0
-    assert float(APyFixed.from_float(2.25, 5, 3).cast(3, 3, mode)) == 3.0
-
-    assert float(APyFixed(0b10000, 5, 0).cast(5, 5, mode)) == -1.0
-    assert float(APyFixed(0b10001, 5, 0).cast(5, 5, mode)) == -1.0
-    assert float(APyFixed(0b11111, 5, 0).cast(5, 5, mode)) == -1.0
-    assert float(APyFixed(0b01001, 5, 0).cast(5, 5, mode)) == 1.0
-    assert float(APyFixed(0b01000, 5, 0).cast(5, 5, mode)) == 1.0
-    assert float(APyFixed(0b00001, 5, 0).cast(5, 5, mode)) == 1.0
-    assert float(APyFixed(0b00000, 5, 0).cast(5, 5, mode)) == 0.0
-
-    assert float(APyFixed(0b10000, 5, -1).cast(5, 5, mode)) == -1.0
-    assert float(APyFixed(0b10001, 5, -1).cast(5, 5, mode)) == -1.0
-    assert float(APyFixed(0b11111, 5, -1).cast(5, 5, mode)) == -1.0
-    assert float(APyFixed(0b01001, 5, -1).cast(5, 5, mode)) == 1.0
-    assert float(APyFixed(0b01000, 5, -1).cast(5, 5, mode)) == 1.0
-    assert float(APyFixed(0b00001, 5, -1).cast(5, 5, mode)) == 1.0
-    assert float(APyFixed(0b00000, 5, -1).cast(5, 5, mode)) == 0.0
+    assert float(APyFixed.from_float(-0.75, 1, 2).cast(1, 4, mode)) == -0.75
+
+    assert float(APyFixed.from_float(-2.25, 3, 2).cast(3, 0, mode)) == -3.0
+    assert float(APyFixed.from_float(-2.00, 3, 2).cast(3, 0, mode)) == -2.0
+    assert float(APyFixed.from_float(-1.75, 3, 2).cast(3, 0, mode)) == -1.0
+    assert float(APyFixed.from_float(-1.50, 3, 2).cast(3, 0, mode)) == -1.0
+    assert float(APyFixed.from_float(-1.25, 3, 2).cast(3, 0, mode)) == -1.0
+    assert float(APyFixed.from_float(-1.00, 3, 2).cast(3, 0, mode)) == -1.0
+    assert float(APyFixed.from_float(-0.75, 3, 2).cast(3, 0, mode)) == -1.0
+    assert float(APyFixed.from_float(-0.50, 3, 2).cast(3, 0, mode)) == -1.0
+    assert float(APyFixed.from_float(-0.25, 3, 2).cast(3, 0, mode)) == -1.0
+    assert float(APyFixed.from_float(0.00, 3, 2).cast(3, 0, mode)) == 0.0
+    assert float(APyFixed.from_float(0.25, 3, 2).cast(3, 0, mode)) == 1.0
+    assert float(APyFixed.from_float(0.50, 3, 2).cast(3, 0, mode)) == 1.0
+    assert float(APyFixed.from_float(0.75, 3, 2).cast(3, 0, mode)) == 1.0
+    assert float(APyFixed.from_float(1.00, 3, 2).cast(3, 0, mode)) == 1.0
+    assert float(APyFixed.from_float(1.25, 3, 2).cast(3, 0, mode)) == 1.0
+    assert float(APyFixed.from_float(1.50, 3, 2).cast(3, 0, mode)) == 1.0
+    assert float(APyFixed.from_float(1.75, 3, 2).cast(3, 0, mode)) == 1.0
+    assert float(APyFixed.from_float(2.00, 3, 2).cast(3, 0, mode)) == 2.0
+    assert float(APyFixed.from_float(2.25, 3, 2).cast(3, 0, mode)) == 3.0
+
+    assert float(APyFixed(0b10000, 0, 5).cast(5, 0, mode)) == -1.0
+    assert float(APyFixed(0b10001, 0, 5).cast(5, 0, mode)) == -1.0
+    assert float(APyFixed(0b11111, 0, 5).cast(5, 0, mode)) == -1.0
+    assert float(APyFixed(0b01001, 0, 5).cast(5, 0, mode)) == 1.0
+    assert float(APyFixed(0b01000, 0, 5).cast(5, 0, mode)) == 1.0
+    assert float(APyFixed(0b00001, 0, 5).cast(5, 0, mode)) == 1.0
+    assert float(APyFixed(0b00000, 0, 5).cast(5, 0, mode)) == 0.0
+
+    assert float(APyFixed(0b10000, -1, 6).cast(5, 0, mode)) == -1.0
+    assert float(APyFixed(0b10001, -1, 6).cast(5, 0, mode)) == -1.0
+    assert float(APyFixed(0b11111, -1, 6).cast(5, 0, mode)) == -1.0
+    assert float(APyFixed(0b01001, -1, 6).cast(5, 0, mode)) == 1.0
+    assert float(APyFixed(0b01000, -1, 6).cast(5, 0, mode)) == 1.0
+    assert float(APyFixed(0b00001, -1, 6).cast(5, 0, mode)) == 1.0
+    assert float(APyFixed(0b00000, -1, 6).cast(5, 0, mode)) == 0.0
 
 
 def test_stochastic_weighted():
@@ -448,7 +447,7 @@ def test_stochastic_equal():
     ],
 )
 def test_huge_narrowing_cast(mode):
-    assert float(APyFixed.from_float(-0.75, 1000, 500).cast(5, 1, mode)) == -0.75
+    assert float(APyFixed.from_float(-0.75, 1000, 500).cast(1, 4, mode)) == -0.75
 
 
 @pytest.mark.parametrize(
@@ -467,7 +466,7 @@ def test_huge_narrowing_cast(mode):
     ],
 )
 def test_huge_extending_cast(mode):
-    assert float(APyFixed.from_float(-0.75, 5, 2).cast(1000, 500, mode)) == -0.75
+    assert float(APyFixed.from_float(-0.75, 5, 2).cast(500, 500, mode)) == -0.75
 
 
 # All of the non-implemented Python quantization methods for APyFixed
@@ -485,7 +484,7 @@ def test_not_implemented(mode):
 
 def test_issue_112():
     # Smoke test to make sure that it doesn't seg-fault
-    APyFixed.from_float(123, int_bits=119, frac_bits=0).cast(4, 4)
+    APyFixed.from_float(123, int_bits=119, frac_bits=0).cast(4, 0)
 
 
 def test_issue_179():
@@ -645,3 +644,13 @@ def test_quantize_away_all_bits():
             .cast(bits=200, int_bits=400, quantization=mode)
             .is_identical(APyFixed(0, bits=200, int_bits=400))
         )
+
+
+def test_one_specifier():
+    # It is possible to specify only `int_bits` or `frac_bits`. Doing so preserves the
+    # other specifier.
+    a = APyFixed(0b0011_1100, int_bits=4, frac_bits=4)
+    assert float(a) == 3.75
+    assert float(a.cast(1)) == -0.25
+    assert float(a.cast(int_bits=1)) == -0.25
+    assert float(a.cast(frac_bits=1)) == 3.5
diff --git a/lib/test/apyfixedarray/test_arithmetic.py b/lib/test/apyfixedarray/test_arithmetic.py
index 4e61c0f0f..3b6763971 100644
--- a/lib/test/apyfixedarray/test_arithmetic.py
+++ b/lib/test/apyfixedarray/test_arithmetic.py
@@ -203,7 +203,7 @@ def test_array_sub_scalar():
     a = APyFixedArray([-5, -6, 7, 10, -11], bits=10, int_bits=5)
     b = APyFixed(3, bits=7, int_bits=2)
     assert (a - b).is_identical(APyFixedArray([-8, -9, 4, 7, -14], bits=11, int_bits=6))
-    assert (-(b - a)).is_identical((a - b).cast(12, 7))
+    assert (-(b - a)).is_identical((a - b).cast(7, 5))
 
     a = APyFixedArray([-5, -6, 7], bits=7, int_bits=4)
     b = APyFixed(3, bits=7, int_bits=4)
@@ -470,10 +470,8 @@ def test_abs():
     ],
 )
 def test_huge_narrowing_cast(mode):
-    a = APyFixedArray.from_float([-0.75, 0.5], 1000, 500)
-    assert a.cast(10, 5, mode).is_identical(
-        APyFixedArray.from_float([-0.75, 0.5], 10, 5)
-    )
+    a = APyFixedArray.from_float([-0.75, 0.5], 500, 500)
+    assert a.cast(5, 5, mode).is_identical(APyFixedArray.from_float([-0.75, 0.5], 5, 5))
 
 
 @pytest.mark.parametrize(
@@ -492,11 +490,11 @@ def test_huge_narrowing_cast(mode):
     ],
 )
 def test_huge_extending_cast(mode):
-    a = APyFixedArray.from_float([-0.75, 0.5], 10, 5)
-    print(a.cast(1000, 500, mode))
-    print(APyFixedArray.from_float([-0.75, 0.5], 1000, 500))
-    assert a.cast(1000, 500, mode).is_identical(
-        APyFixedArray.from_float([-0.75, 0.5], 1000, 500)
+    a = APyFixedArray.from_float([-0.75, 0.5], 5, 5)
+    print(a.cast(500, 500, mode))
+    print(APyFixedArray.from_float([-0.75, 0.5], 500, 500))
+    assert a.cast(500, 500, mode).is_identical(
+        APyFixedArray.from_float([-0.75, 0.5], 500, 500)
     )
 
 
@@ -510,7 +508,7 @@ def test_long_matrix_addition():
 
 
 def test_operation_with_numbers():
-    a = APyFixedArray([5, 7, -1], 6, 2)
+    a = APyFixedArray([5, 7, -1], bits=6, int_bits=2)
     # Integer
     assert (a + 0).is_identical(a)
     assert (0 + a).is_identical(a)
diff --git a/lib/test/apyfixedarray/test_matmul.py b/lib/test/apyfixedarray/test_matmul.py
index b7c54a48d..b26cc43f7 100644
--- a/lib/test/apyfixedarray/test_matmul.py
+++ b/lib/test/apyfixedarray/test_matmul.py
@@ -224,25 +224,25 @@ def test_matrix_multiplication_accumulator_context():
         int_bits=2, frac_bits=4, quantization=QuantizationMode.TRN
     ):
         assert (A @ B).is_identical(
-            APyFixedArray.from_float([[0.3125, 0.5000], [0.8125, 1.2500]], 6, 2)
+            APyFixedArray.from_float([[0.3125, 0.5000], [0.8125, 1.2500]], 2, 4)
         )
     with APyFixedAccumulatorContext(
         int_bits=2, frac_bits=3, quantization=QuantizationMode.TRN
     ):
         assert (A @ B).is_identical(
-            APyFixedArray.from_float([[0.2500, 0.5000], [0.7500, 1.2500]], 5, 2)
+            APyFixedArray.from_float([[0.2500, 0.5000], [0.7500, 1.2500]], 2, 3)
         )
     with APyFixedAccumulatorContext(
         int_bits=2, frac_bits=2, quantization=QuantizationMode.TRN
     ):
         assert (A @ B).is_identical(
-            APyFixedArray.from_float([[0.0000, 0.5000], [0.7500, 1.2500]], 4, 2)
+            APyFixedArray.from_float([[0.0000, 0.5000], [0.7500, 1.2500]], 2, 2)
         )
     with APyFixedAccumulatorContext(
         int_bits=2, frac_bits=1, quantization=QuantizationMode.TRN
     ):
         assert (A @ B).is_identical(
-            APyFixedArray.from_float([[0.0000, 0.0000], [0.5000, 1.0000]], 3, 2)
+            APyFixedArray.from_float([[0.0000, 0.0000], [0.5000, 1.0000]], 2, 1)
         )
 
     # Quantization, ties to plus infinity quantization
@@ -250,25 +250,25 @@ def test_matrix_multiplication_accumulator_context():
         int_bits=2, frac_bits=4, quantization=QuantizationMode.RND
     ):
         assert (A @ B).is_identical(
-            APyFixedArray.from_float([[0.3125, 0.5000], [0.8125, 1.2500]], 6, 2)
+            APyFixedArray.from_float([[0.3125, 0.5000], [0.8125, 1.2500]], 2, 4)
         )
     with APyFixedAccumulatorContext(
         int_bits=2, frac_bits=3, quantization=QuantizationMode.RND
     ):
         assert (A @ B).is_identical(
-            APyFixedArray.from_float([[0.3750, 0.5000], [0.875, 1.2500]], 5, 2)
+            APyFixedArray.from_float([[0.3750, 0.5000], [0.875, 1.2500]], 2, 3)
         )
     with APyFixedAccumulatorContext(
         int_bits=2, frac_bits=2, quantization=QuantizationMode.RND
     ):
         assert (A @ B).is_identical(
-            APyFixedArray.from_float([[0.5000, 0.5000], [0.7500, 1.2500]], 4, 2)
+            APyFixedArray.from_float([[0.5000, 0.5000], [0.7500, 1.2500]], 2, 2)
         )
     with APyFixedAccumulatorContext(
         int_bits=2, frac_bits=1, quantization=QuantizationMode.RND
     ):
         assert (A @ B).is_identical(
-            APyFixedArray.from_float([[0.0000, 1.0000], [1.0000, 1.5000]], 3, 2)
+            APyFixedArray.from_float([[0.0000, 1.0000], [1.0000, 1.5000]], 2, 1)
         )
 
 
diff --git a/lib/test/apyfixedarray/test_methods.py b/lib/test/apyfixedarray/test_methods.py
index b96e49ab4..3ffbffc9e 100644
--- a/lib/test/apyfixedarray/test_methods.py
+++ b/lib/test/apyfixedarray/test_methods.py
@@ -23,7 +23,7 @@ def test_to_numpy():
     np = pytest.importorskip("numpy")
 
     assert np.array_equal(APyFixedArray([], 1, 0).to_numpy(), np.array([]))
-    assert np.array_equal(APyFixedArray([1], 2, 2).to_numpy(), np.array([1.0]))
+    assert np.array_equal(APyFixedArray([1], 2, 0).to_numpy(), np.array([1.0]))
 
     float_seq = [
         [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]],
@@ -75,6 +75,6 @@ def test_len():
 
 
 def test_round_trip_conversion():
-    for bits in range(256):
-        a = APyFixedArray([bits], 8, 4)
-        assert (APyFixedArray.from_float(a.to_numpy(), 8, 4)).is_identical(a)
+    for bit_pattern in range(256):
+        a = APyFixedArray([bit_pattern], int_bits=4, frac_bits=4)
+        assert (APyFixedArray.from_float(a.to_numpy(), 4, 4)).is_identical(a)