KallistiOS git master
Independent SDK for the Sega Dreamcast
Loading...
Searching...
No Matches
udiv.h
Go to the documentation of this file.
1/* KallistiOS ##version##
2
3 kos/udiv.h
4 Copyright (C) 2024, 2026 Paul Cercueil
5*/
6
7/** \file kos/udiv.h
8 \brief Fast unsigned integer division
9 \ingroup intmath
10
11 This file contains an API that can be used to pre-process an unsigned value
12 into an udiv_t struct. This struct can later be used to divide another
13 unsigned value much faster than by doing an actual division.
14
15 This API is very useful when a rarely-changing divider is used often.
16
17 \author Paul Cercueil
18*/
19
20#ifndef __KOS_UDIV_H
21#define __KOS_UDIV_H
22
23#include <kos/cdefs.h>
24
25__BEGIN_DECLS
26
27#include <kos/intmath.h>
28#include <kos/regfield.h>
29
30/** \struct udiv_t
31 \brief Pre-processed unsigned integer divider value.
32*/
33typedef struct {
34 unsigned int p;
35 unsigned int m;
36} udiv_t;
37
38/** \brief Create a udiv_t from an unsigned int divider.
39
40 Use this function to create the preleminary udiv_t object, that can then
41 be passed to udiv_divide() or udiv_divide_fast().
42
43 \param div The unsigned integer divider value
44 \return A pre-processed divider as a udiv_t
45*/
46static inline udiv_t udiv_set_divider(unsigned int div)
47{
48 unsigned int p = 31 - __builtin_clz(div) + !is_power_of_two(div);
49 unsigned int m = (BITLL(32 + p) + div - 1) / (unsigned long long)div;
50
51 return (udiv_t){ .p = p, .m = m, };
52}
53
54/** \brief Perform a division using the udiv_t, without bound checking
55
56 This function is similar to udiv_divide(), except that it only works for
57 values 1 < div < 0x80000001.
58
59 \param val The dividend
60 \param udiv The divider, as a udiv_t
61 \return The result of the division operation
62*/
63static inline unsigned int udiv_divide_fast(unsigned int val, udiv_t udiv) {
64 unsigned int q = ((unsigned long long)udiv.m * val) >> 32;
65 unsigned int t = ((val - q) >> 1) + q;
66
67 return t >> (udiv.p - 1);
68}
69
70/** \brief Perform a division using the udiv_t, with bound checking
71
72 This function will perform a division using the provided udiv_t.
73 The pre-processed divider can correspond to any non-zero integer value.
74
75 \param val The dividend
76 \param udiv The divider, as a udiv_t
77 \return The result of the division operation
78*/
79static inline unsigned int udiv_divide(unsigned int val, udiv_t udiv)
80{
81 /* Divide by 0x80000001 or higher: the algorithm does not work, so
82 * udiv.m contains the full divider value, and we just need to check
83 * if the dividend is >= the divider. */
84 if (__predict_false(udiv.p == 0x20))
85 return val >= udiv.m;
86
87 /* Divide by 1: the algorithm does not work, so handle this special case. */
88 if (__predict_false(udiv.m == 0 && udiv.p == 0))
89 return val;
90
91 return udiv_divide_fast(val, udiv);
92}
93
94__END_DECLS
95
96#endif /* __KOS_UDIV_H */
Various common macros used throughout the codebase.
Functions to help with integer math.
static bool is_power_of_two(unsigned int val)
Definition intmath.h:24
Macros to help dealing with register fields.
#define BITLL(bit)
Create a 64-bit mask with a bit set.
Definition regfield.h:34
Pre-processed unsigned integer divider value.
Definition udiv.h:33
unsigned int p
Definition udiv.h:34
unsigned int m
Definition udiv.h:35
static udiv_t udiv_set_divider(unsigned int div)
Create a udiv_t from an unsigned int divider.
Definition udiv.h:46
static unsigned int udiv_divide(unsigned int val, udiv_t udiv)
Perform a division using the udiv_t, with bound checking.
Definition udiv.h:79
static unsigned int udiv_divide_fast(unsigned int val, udiv_t udiv)
Perform a division using the udiv_t, without bound checking.
Definition udiv.h:63