diff --git a/Makefile.in b/Makefile.in
index 89d52a08e..07cc1505e 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -25,7 +25,7 @@ export
 SOURCES = 
 LIB_SOURCES = $(wildcard $(patsubst %, %/*.c, $(BUILD_DIRS)))  $(patsubst %, %/*.c, $(TEMPLATE_DIRS))
 
-HEADERS = $(patsubst %, %.h, $(BUILD_DIRS))
+HEADERS = $(patsubst %, %.h, $(BUILD_DIRS)) arb-defs.h
 
 OBJS = $(patsubst %.c, build/%.o, $(SOURCES))
 LIB_OBJS = $(patsubst %, build/%/*.o, $(BUILD_DIRS))
diff --git a/arb-defs.h b/arb-defs.h
new file mode 100644
index 000000000..8748d8c4b
--- /dev/null
+++ b/arb-defs.h
@@ -0,0 +1,138 @@
+/*
+    Copyright (C) 2022 Albin Ahlbäck
+    Copyright (C) 2022 Fredrik Johansson
+
+    This file is part of Arb.
+
+    Arb is free software: you can redistribute it and/or modify it under
+    the terms of the GNU Lesser General Public License (LGPL) as published
+    by the Free Software Foundation; either version 2.1 of the License, or
+    (at your option) any later version.  See <http://www.gnu.org/licenses/>.
+*/
+
+#include "flint/flint.h"
+
+#ifndef ARB_DEFS_H
+#define ARB_DEFS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define __ARB_VERSION 2
+#define __ARB_VERSION_MINOR 22
+#define __ARB_VERSION_PATCHLEVEL 1
+
+#define ARB_VERSION "2.22.1"
+
+#define __ARB_RELEASE (__ARB_VERSION            * 10000 +   \
+                       __ARB_VERSION_MINOR      * 100   +   \
+                       __ARB_VERSION_PATCHLEVEL)
+
+
+#define TLS_PREFIX FLINT_TLS_PREFIX
+
+#if defined(_MSC_VER) && defined(ARB_BUILD_DLL)
+#define ARB_DLL __declspec(dllexport)
+#else
+#define ARB_DLL FLINT_DLL
+#endif
+
+
+#ifndef flint_abort
+#if __FLINT_RELEASE <= 20502
+#define flint_abort abort
+#endif
+#endif
+
+#if __FLINT_RELEASE < 20600
+#define flint_bitcnt_t ulong
+#endif
+
+
+#define LIMB_ONE ((mp_limb_t) 1)
+#define LIMB_ONES (-(mp_limb_t) 1)
+#define LIMB_TOP (((mp_limb_t) 1) << (FLINT_BITS - 1))
+#define MASK_LIMB(n, c) ((n) & (LIMB_ONES << (c)))
+
+
+/* FLINT_ABS is unsafe for x = WORD_MIN */
+#define UI_ABS_SI(x) (((slong)(x) < 0) ? (-(ulong)(x)) : ((ulong)(x)))
+
+
+#define nn_mul_2x1(r2, r1, r0, a1, a0, b0)                  \
+    do {                                                    \
+        mp_limb_t t1;                                       \
+        umul_ppmm(r1, r0, a0, b0);                          \
+        umul_ppmm(r2, t1, a1, b0);                          \
+        add_ssaaaa(r2, r1, r2, r1, 0, t1);                  \
+    } while (0)
+
+#define nn_mul_2x2(r3, r2, r1, r0, a1, a0, b1, b0)          \
+    do {                                                    \
+        mp_limb_t t1, t2, t3;                               \
+        umul_ppmm(r1, r0, a0, b0);                          \
+        umul_ppmm(r2, t1, a1, b0);                          \
+        add_ssaaaa(r2, r1, r2, r1, 0, t1);                  \
+        umul_ppmm(t1, t2, a0, b1);                          \
+        umul_ppmm(r3, t3, a1, b1);                          \
+        add_ssaaaa(r3, t1, r3, t1, 0, t3);                  \
+        add_ssaaaa(r2, r1, r2, r1, t1, t2);                 \
+        r3 += r2 < t1;                                      \
+    } while (0)
+
+
+#ifndef NEWTON_INIT
+
+#define NEWTON_INIT(from, to)                           \
+    {                                                   \
+        slong __steps[FLINT_BITS], __i, __from, __to;   \
+        __steps[__i = 0] = __to = (to);                 \
+        __from = (from);                                \
+        while (__to > __from)                           \
+            __steps[++__i] = (__to = (__to + 1) / 2);   \
+
+#define NEWTON_BASECASE(bc_to) { slong bc_to = __to;
+
+#define NEWTON_END_BASECASE }
+
+#define NEWTON_LOOP(step_from, step_to)                 \
+        {                                               \
+            for (__i--; __i >= 0; __i--)                \
+            {                                           \
+                slong step_from = __steps[__i+1];       \
+                slong step_to = __steps[__i];           \
+
+#define NEWTON_END_LOOP }}
+
+#define NEWTON_END }
+
+#endif
+
+
+ARB_DLL extern const char * arb_version;
+
+double arb_test_multiplier(void);
+
+/* counts zero bits in the binary representation of e */
+static __inline__
+int
+n_zerobits(mp_limb_t e)
+{
+#ifdef __GMP_SHORT_LIMB
+    return FLINT_BITS - __builtin_popcount(e) - __builtin_clz(e);
+#else
+# ifdef _LONG_LONG_LIMB
+    return FLINT_BITS - __builtin_popcountll(e) - __builtin_clzll(e);
+# else
+    return FLINT_BITS - __builtin_popcountl(e) - __builtin_clzl(e);
+# endif
+#endif
+}
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/arb.h b/arb.h
index be5bf85ff..903c239bd 100644
--- a/arb.h
+++ b/arb.h
@@ -26,17 +26,6 @@
 extern "C" {
 #endif
 
-#define __ARB_VERSION 2
-#define __ARB_VERSION_MINOR 22
-#define __ARB_VERSION_PATCHLEVEL 1
-#define ARB_VERSION "2.22.1"
-#define __ARB_RELEASE (__ARB_VERSION * 10000 + \
-                         __ARB_VERSION_MINOR * 100 + \
-                         __ARB_VERSION_PATCHLEVEL)
-
-ARB_DLL extern const char * arb_version;
-double arb_test_multiplier(void);
-
 typedef struct
 {
     arf_struct mid;
diff --git a/arb_poly.h b/arb_poly.h
index 1fa2940b2..3d00dae92 100644
--- a/arb_poly.h
+++ b/arb_poly.h
@@ -730,22 +730,6 @@ arb_poly_allocated_bytes(const arb_poly_t x)
 
 /* Macros */
 
-
-/* counts zero bits in the binary representation of e */
-ARB_POLY_INLINE int
-n_zerobits(mp_limb_t e)
-{
-    int zeros = 0;
-
-    while (e > 1)
-    {
-        zeros += !(e & 1);
-        e >>= 1;
-    }
-
-    return zeros;
-}
-
 /* Computes the length of the result when raising a polynomial of
    length *len* to the power *exp* and truncating to length *trunc*,
    without overflow. Assumes poly_len >= 1. */
@@ -760,33 +744,6 @@ poly_pow_length(slong poly_len, ulong exp, slong trunc)
     return FLINT_MIN((slong) lo, trunc);
 }
 
-#ifndef NEWTON_INIT
-
-#define NEWTON_INIT(from, to) \
-    { \
-        slong __steps[FLINT_BITS], __i, __from, __to; \
-        __steps[__i = 0] = __to = (to); \
-        __from = (from); \
-        while (__to > __from) \
-            __steps[++__i] = (__to = (__to + 1) / 2); \
-
-#define NEWTON_BASECASE(bc_to) { slong bc_to = __to;
-
-#define NEWTON_END_BASECASE }
-
-#define NEWTON_LOOP(step_from, step_to) \
-        { \
-            for (__i--; __i >= 0; __i--) \
-            { \
-                slong step_from = __steps[__i+1]; \
-                slong step_to = __steps[__i]; \
-
-#define NEWTON_END_LOOP }}
-
-#define NEWTON_END }
-
-#endif
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/arf.h b/arf.h
index 2c193f520..3ab1f74b4 100644
--- a/arf.h
+++ b/arf.h
@@ -27,12 +27,6 @@
 #include "fmpr.h"
 #include "mag.h"
 
-#ifndef flint_abort
-#if __FLINT_RELEASE <= 20502
-#define flint_abort abort
-#endif
-#endif
-
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -439,9 +433,6 @@ arf_init_set_ui(arf_t x, ulong v)
     }
 }
 
-/* FLINT_ABS is unsafe for x = WORD_MIN */
-#define UI_ABS_SI(x) (((slong)(x) < 0) ? (-(ulong)(x)) : ((ulong)(x)))
-
 ARF_INLINE void
 arf_init_set_si(arf_t x, slong v)
 {
@@ -805,27 +796,6 @@ void arf_urandom(arf_t x, flint_rand_t state, slong bits, arf_rnd_t rnd);
 #define MUL_MPFR_MIN_LIMBS 25
 #define MUL_MPFR_MAX_LIMBS 10000
 
-#define nn_mul_2x1(r2, r1, r0, a1, a0, b0)                  \
-    do {                                                    \
-        mp_limb_t t1;                                       \
-        umul_ppmm(r1, r0, a0, b0);                          \
-        umul_ppmm(r2, t1, a1, b0);                          \
-        add_ssaaaa(r2, r1, r2, r1, 0, t1);                  \
-    } while (0)
-
-#define nn_mul_2x2(r3, r2, r1, r0, a1, a0, b1, b0)          \
-    do {                                                    \
-        mp_limb_t t1, t2, t3;                               \
-        umul_ppmm(r1, r0, a0, b0);                          \
-        umul_ppmm(r2, t1, a1, b0);                          \
-        add_ssaaaa(r2, r1, r2, r1, 0, t1);                  \
-        umul_ppmm(t1, t2, a0, b1);                          \
-        umul_ppmm(r3, t3, a1, b1);                          \
-        add_ssaaaa(r3, t1, r3, t1, 0, t3);                  \
-        add_ssaaaa(r2, r1, r2, r1, t1, t2);                 \
-        r3 += r2 < t1;                                      \
-    } while (0)
-
 #define ARF_MPN_MUL(_z, _x, _xn, _y, _yn) \
     if ((_xn) == (_yn)) \
     { \
diff --git a/bool_mat.h b/bool_mat.h
index e35940b6c..3b45fa1e4 100644
--- a/bool_mat.h
+++ b/bool_mat.h
@@ -21,20 +21,12 @@
 #include <stdio.h>
 #include "flint/flint.h"
 #include "flint/fmpz_mat.h"
-
-#ifndef flint_abort
-#if __FLINT_RELEASE <= 20502
-#define flint_abort abort
-#endif
-#endif
+#include "arb-defs.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-/* currently defined in the arb module, but global to the library */
-double arb_test_multiplier(void);
-
 typedef struct
 {
     int *entries;
diff --git a/dlog.h b/dlog.h
index a00f017e0..0d580d1a7 100644
--- a/dlog.h
+++ b/dlog.h
@@ -19,15 +19,9 @@
 #endif
 
 #include "flint/flint.h"
-
-#ifndef flint_abort
-#if __FLINT_RELEASE <= 20502
-#define flint_abort abort
-#endif
-#endif
-
 #include "flint/ulong_extras.h"
 #include "flint/nmod_vec.h"
+#include "arb-defs.h"
 
 #ifdef __cplusplus
 extern "C" {
diff --git a/doc/source/arb-defs.rst b/doc/source/arb-defs.rst
new file mode 100644
index 000000000..36d1272d4
--- /dev/null
+++ b/doc/source/arb-defs.rst
@@ -0,0 +1,91 @@
+.. _arb-defs:
+
+**arb-defs.h** -- global definitions for the Arb library
+================================================================================
+
+The header ``arb-defs.h`` provides macros and functions used throughout the
+Arb-library that are not specific for any Arb-types.
+
+
+Types, macros and constants
+--------------------------------------------------------------------------------
+
+.. macro:: __ARB_VERSION
+
+.. macro:: __ARB_VERSION_MINOR
+
+.. macro:: __ARB_VERSION_PATCHLEVEL
+
+   A macro for the major, minor and patch version of Arb, respectively,
+   represented as an integer. In other words, it gives you the first, second or
+   third number in the version number.
+
+.. macro:: ARB_VERSION
+
+   A macro for the version of Arb, represented as a string.
+
+.. var:: const char * arb_version
+
+   A constant variable equivalence to :macro:`ARB_VERSION`.
+
+.. macro:: __ARB_RELEASE
+
+   A macro aimed for easily parsing the version number of Arb. It is represented
+   as an integer defined by
+
+   .. math ::
+      \mathtt{\_\_ARB\_RELEASE}
+   =
+      10000 \cdot \mathtt{\_\_ARB\_VERSION}
+      +
+      100 \cdot \mathtt{\_\_ARB\_VERSION\_MINOR}
+      +
+      \mathtt{\_\_ARB\_VERSION\_PATCHLEVEL}
+
+.. macro:: LIMB_ONE
+
+   The limb with binary representation `(0 0 \cdots 0 1)_{2}`.
+
+.. macro:: LIMB_ONES
+
+   The limb with binary representation `(1 1 \cdots 1 1)_{2}`.
+
+.. macro:: LIMB_TOP
+
+   The limb with binary representation `(1 0 \cdots 0 0)_{2}`.
+
+.. macro:: MASK_LIMB(n, c)
+
+   A macro for removing the `c` lower ones in the bit representation of `n`.
+
+.. macro:: UI_ABS_SI(x)
+
+   Returns the absolute value of `x`.
+
+.. macro:: nn_mul_2x1(r2, r1, r0, a1, a0, b0)
+
+   Given `a = \{a_0, a_1\}` and `b = \{b_0\}`, it sets `r = \{r_0, r_1, r_2\}`
+   to the product `a \cdot b`.
+
+.. macro:: nn_mul_2x2(r3, r2, r1, r0, a1, a0, b1, b0)
+
+   Given `a = \{a_0, a_1\}` and `b = \{b_0, b_1\}`, it sets
+   `r = \{r_0, r_1, r_2, r_3\}` to the product `a \cdot b`.
+
+
+Functions
+--------------------------------------------------------------------------------
+
+.. function:: double arb_test_multiplier(void)
+
+   Returns the test multiplier. This function is used to determine how many
+   tests are going to be performed during ``make check``.
+
+.. function:: int n_zerobits(mp_limb_t e)
+
+   Returns the number of zero bits in the binary representation of `e` *up to
+   its most significant bit*.
+
+
+..
+    vim:spell spelllang=en_us:ts=3:sw=3:tw=80:expandtab:
diff --git a/doc/source/index.rst b/doc/source/index.rst
index 3b94791ac..a37d6743f 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -100,6 +100,14 @@ Example programs
 
    examples.rst
 
+General utilities
+::::::::::::::::::::::::::::::::::::
+
+.. toctree::
+   :maxdepth: 2
+
+   arb-defs.rst
+
 Floating-point numbers
 ::::::::::::::::::::::::::::::::::::
 
@@ -248,3 +256,5 @@ Version history
 
    history.rst
 
+..
+    vim:spell spelllang=en_us:ts=3:sw=3:tw=80:expandtab:
diff --git a/fmpr.h b/fmpr.h
index c6a8c3425..c03edf50a 100644
--- a/fmpr.h
+++ b/fmpr.h
@@ -22,26 +22,8 @@
 #include "flint/flint.h"
 #include "flint/fmpz.h"
 #include "flint/fmpq.h"
-#if __FLINT_RELEASE < 20600
-#include "flint/config.h"
-#else
-#include "flint/flint-config.h"
-#endif
 #include "fmpz_extras.h"
-
-#ifndef flint_abort
-#if __FLINT_RELEASE <= 20502
-#define flint_abort abort
-#endif
-#endif
-
-#define TLS_PREFIX FLINT_TLS_PREFIX
-
-#if defined(_MSC_VER) && defined(ARB_BUILD_DLL)
-#define ARB_DLL __declspec(dllexport)
-#else
-#define ARB_DLL FLINT_DLL
-#endif
+#include "arb-defs.h"
 
 #define fmpr_rnd_t int
 #define FMPR_RND_DOWN 0
@@ -54,9 +36,6 @@
 extern "C" {
 #endif
 
-/* currently defined in the arb module, but global to the library */
-double arb_test_multiplier(void);
-
 static __inline__ int
 rounds_up(fmpr_rnd_t rnd, int negative)
 {
diff --git a/fmpz_extras.h b/fmpz_extras.h
index 0c55f7f6a..168752840 100644
--- a/fmpz_extras.h
+++ b/fmpz_extras.h
@@ -15,24 +15,12 @@
 #include <limits.h>
 #include "flint/flint.h"
 #include "flint/fmpz.h"
+#include "arb-defs.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-#ifndef flint_abort
-#if __FLINT_RELEASE <= 20502
-#define flint_abort abort
-#endif
-#endif
-
-#if __FLINT_RELEASE < 20600
-#define flint_bitcnt_t ulong
-#endif
-
-/* currently defined in the arb module, but global to the library */
-double arb_test_multiplier(void);
-
 static __inline__ void
 fmpz_add_inline(fmpz_t z, const fmpz_t x, const fmpz_t y)
 {
diff --git a/mag.h b/mag.h
index 00eb44fa9..3e2991125 100644
--- a/mag.h
+++ b/mag.h
@@ -24,21 +24,10 @@
 #include "flint/fmpz.h"
 #include "fmpz_extras.h"
 
-#ifndef flint_abort
-#if __FLINT_RELEASE <= 20502
-#define flint_abort abort
-#endif
-#endif
-
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-#define LIMB_ONE ((mp_limb_t) 1)
-#define LIMB_ONES (-(mp_limb_t) 1)
-#define LIMB_TOP (((mp_limb_t) 1) << (FLINT_BITS - 1))
-#define MASK_LIMB(n, c) ((n) & (LIMB_ONES << (c)))
-
 #define MAG_MAX_LAGOM_EXP (COEFF_MAX / 4)
 #define MAG_MIN_LAGOM_EXP (-MAG_MAX_LAGOM_EXP)