acme
Foundational cross-platform layer of the ca2 framework
Loading...
Searching...
No Matches
muldiv64.h
Go to the documentation of this file.
1// From https://github.com/nordlow/justcxx/blob/master/muldiv64.h by camilo on 2022-05-09
7
8#pragma once
9
10#ifdef __cplusplus
11extern "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