acme
Foundational cross-platform layer of the ca2 framework
Toggle main menu visibility
Loading...
Searching...
No Matches
uint64_muldiv.h
1
// Through https://github.com/nordlow/justcxx/blob/master/muldiv64.h
7
8
#pragma once
9
10
#ifdef __cplusplus
11
extern
"C"
{
12
#endif
13
18
static
inline ::u32 uint64_msb(uint64_t value)
19
{
20
const ::i32 MAX_LOGLOG = 6;
21
const
uint64_t BIT_LL[MAX_LOGLOG] = { 0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000, 0xFFFFFFFF00000000LL };
22
const ::u32 EXP_LL[MAX_LOGLOG] = { 1, 2, 4, 8, 16, 32 };
23
::u32 r = 0;
24
for
(::i32 i = MAX_LOGLOG - 1; i >= 0; i--) {
25
if
(value & BIT_LL[i]) {
26
value >>= EXP_LL[i];
27
r |= EXP_LL[i];
28
}
29
}
30
return
r;
31
}
32
45
static
inline
uint64_t uint64_muldiv(uint64_t a, uint32_t b, uint64_t c)
46
{
47
const
uint32_t aH = ((uint32_t*)&a)[1];
48
const
uint32_t aL = ((uint32_t*)&a)[0];
49
50
// lower 32-bit portions yield 64-bit product that can be divided
51
// directly giving 64-bits of result,
52
uint64_t res = (aL * b) / c;
53
54
// upper 32-bit have to be shifted, so calculate modulus 2^32
55
const
uint64_t prod_h = aH * b;
56
const
uint64_t div_h = prod_h / c;
// division main
57
const
uint64_t mod_h = prod_h - c * div_h;
// modulus
58
59
// upper bits
60
res += div_h << 32;
61
if
(mod_h == 0) {
62
return
res;
63
}
64
65
// remainder of division. if msb modulus < 32 we can be quick about
66
// it
67
if
((mod_h >> 32) == 0) {
68
res += (mod_h << 32) / c;
69
return
res;
70
}
71
72
// if we reach this point we have full 64-bit values, i.e. a 96-bit
73
// dividend. calculate an approximate result by shifting according
74
// to msb set
75
::i32 msb_nominator = uint64_msb(mod_h) + 32;
76
::i32 msb_c = uint64_msb(c);
77
::i32 msb = maximum(msb_nominator, msb_c);
78
::i32 shift = msb - 63;
79
res += (mod_h << (32 - shift)) / (c >> shift);
80
81
return
res;
82
}
83
84
#ifdef __cplusplus
85
}
86
#endif
platform
uint64_muldiv.h
Generated by
1.17.0