/*
 * opt_int_div.h
 *
 * "Optimized integer division": A header-only library
 *
 * NOTE: This code will work only on a computer that uses bits.
 *
 * Author: Intel A80486DX2-66
 * License: Unlicense
 */

#ifndef _OPT_INT_DIV_H
#define _OPT_INT_DIV_H

#include <math.h>
#include <stdint.h>

// helper functions
#define INT_BIN_DIV(a, b) ((a) >> (uintmax_t) log2l((b))) /* NOTE: log2l may
                                                             slow things down */
#define INT_DIV_NEG_RESULT_SIGN(a, b)                                         \
    /* the sign is negative only if one of the numbers is negative */         \
    (((a) < 0) != ((b) < 0)) /* 1 if sign is negative else 0 */
#define INT_ABS(x) ((x) < 0 ? -(x) : (x))
#define OPT_INT_DIV_TEST(b)                                                   \
    /* check if b is a power of 2 */                                          \
    /* */                                                                     \
    /* condition: ( X & (X - 1) ) == 0 */                                     \
    ((b) & ((b) - 1)) == 0

// the main macro
#define OPT_INT_DIV(a, b)                                                     \
    ( /* beginning */                                                         \
        /* check for equality of abs(a) and abs(b) */                         \
        INT_ABS((a)) == INT_ABS((b)) ?                                        \
            /* the result is +/-1 */                                          \
            (INT_DIV_NEG_RESULT_SIGN(a, b) ? -1 : 1) : (                      \
                                                                              \
        /* check if abs(a) < abs(b) */                                        \
        INT_ABS((a)) < INT_ABS((b)) ?                                         \
            /* if abs(a) < abs(b), then the result is less than 1 (i.e., 0) */\
            0 : (                                                             \
                                                                              \
        OPT_INT_DIV_TEST((b)) ?                                               \
            (INT_DIV_NEG_RESULT_SIGN(a, b) ?                                  \
                -INT_BIN_DIV(INT_ABS((a)), INT_ABS((b)))                      \
            :                                                                 \
                INT_BIN_DIV(INT_ABS((a)), INT_ABS((b))))                      \
        :                                                                     \
            ((a) / (b)) ))                                                    \
    ) /* end */

#endif /* _OPT_INT_DIV_H */