FastLED 3.10.6
Loading...
Searching...
No Matches
wide_divide.h
Go to the documentation of this file.
1#pragma once
2
25
26#include "fl/stl/int.h"
28#include "fl/stl/noexcept.h"
29
55#ifndef FL_FIXED_POINT_NARROW_DIVIDE
56#if __cplusplus < 201402L
57#define FL_FIXED_POINT_NARROW_DIVIDE 0
58#elif defined(__arm__) && defined(__ARM_FEATURE_IDIV) && \
59 (__ARM_FEATURE_IDIV + 0) == 1
60#define FL_FIXED_POINT_NARROW_DIVIDE 1
61#elif defined(__riscv_div) && defined(__riscv_xlen) && (__riscv_xlen + 0) == 32
62#define FL_FIXED_POINT_NARROW_DIVIDE 1
63#else
64#define FL_FIXED_POINT_NARROW_DIVIDE 0
65#endif
66#endif
67
75#if __cplusplus >= 201402L
76#define FL_FIXED_POINT_DIVIDE_INLINE constexpr FASTLED_FORCE_INLINE
77#else
78#define FL_FIXED_POINT_DIVIDE_INLINE FASTLED_FORCE_INLINE
79#endif
80
81namespace fl {
82
83namespace detail {
84
87#if defined(__GNUC__) || defined(__clang__)
88 // One CLZ instruction on every core this file's fast path is enabled for.
89 return value == 0 ? 32 : __builtin_clz(value);
90#else
91 int count = 0;
92 while (count < 32 && (value & 0x80000000u) == 0u) {
93 value <<= 1;
94 ++count;
95 }
96 return count;
97#endif
98}
99
100} // namespace detail
101
121 u32 divisor) FL_NO_EXCEPT {
122 constexpr u32 kBase = 65536u;
123 if (divisor == 0u || hi >= divisor) {
124 return 0xFFFFFFFFu;
125 }
126
127 // Normalising the divisor is what makes the digit estimate below good to
128 // within one, which is the whole reason two corrections suffice.
129 const int shift = detail::fixedPointLeadingZeros(divisor);
130 const u32 d = divisor << shift;
131 const u32 d_high = d >> 16;
132 const u32 d_low = d & 0xFFFFu;
133
134 // A shift of 32 is undefined, so the unshifted case is spelled out rather
135 // than folded in with a mask.
136 const u32 n_high = shift == 0 ? hi : ((hi << shift) | (lo >> (32 - shift)));
137 const u32 n_low = lo << shift;
138 const u32 n_low_high = n_low >> 16;
139 const u32 n_low_low = n_low & 0xFFFFu;
140
141 u32 quotient_high = n_high / d_high;
142 u32 remainder = n_high - quotient_high * d_high;
143 while (quotient_high >= kBase ||
144 static_cast<u64>(quotient_high) * d_low >
145 static_cast<u64>(kBase) * remainder + n_low_high) {
146 --quotient_high;
147 remainder += d_high;
148 if (remainder >= kBase) {
149 break;
150 }
151 }
152
153 // Deliberate 32-bit wraparound: the true value needs 33 bits and the
154 // low 32 are the ones the next digit is taken from.
155 const u32 partial =
156 static_cast<u32>(n_high * kBase + n_low_high - quotient_high * d);
157
158 u32 quotient_low = partial / d_high;
159 remainder = partial - quotient_low * d_high;
160 while (quotient_low >= kBase ||
161 static_cast<u64>(quotient_low) * d_low >
162 static_cast<u64>(kBase) * remainder + n_low_low) {
163 --quotient_low;
164 remainder += d_high;
165 if (remainder >= kBase) {
166 break;
167 }
168 }
169
170 return quotient_high * kBase + quotient_low;
171}
172
173} // namespace fl
FL_FIXED_POINT_DIVIDE_INLINE int fixedPointLeadingZeros(u32 value) FL_NO_EXCEPT
Leading zeros of a non-zero 32-bit value; 32 for zero.
Definition wide_divide.h:86
FL_FIXED_POINT_DIVIDE_INLINE u32 divide64By32(u32 hi, u32 lo, u32 divisor) FL_NO_EXCEPT
(hi:lo) / divisor, for a quotient that fits 32 bits.
constexpr int type_rank< T >::value
InputGamut g FL_NO_EXCEPT
Definition rgbw.h:121
Base definition for an LED controller.
Definition crgb.hpp:179
fl::u64 u64
Definition stdint.h:220
#define FL_FIXED_POINT_DIVIDE_INLINE
constexpr where the language allows it, always force-inlined.
Definition wide_divide.h:78