31 #include "lib/integral.hpp" 81 CHECK (Rat(10,3) == 10_r/3);
82 CHECK (Rat(10,3) == boost::rational<int64_t>(10,3));
83 CHECK (rational_cast<float> (10_r/3) == 3.3333333f);
85 CHECK (2_r/3 + 3_r/4 == 17_r/12);
86 CHECK (2_r/3 * 3_r/4 == 1_r/2);
87 CHECK (2_r/3 /(3_r/4)== 8_r/9);
88 CHECK (2_r/3 / 3 /4 == 1_r/18);
94 CHECK (Rat(10,3).numerator() == int64_t(10));
95 CHECK (Rat(10,3).denominator() == int64_t(3));
96 CHECK (boost::rational<uint>(10,3).numerator() == uint(10));
97 CHECK (boost::rational<uint>(10,3).denominator() == uint(3));
98 CHECK (boost::rational<uint>(10,3) == rational_cast<boost::rational<uint>> (Rat(10,3)));
99 CHECK (boost::rational<uint>(11,3) != rational_cast<boost::rational<uint>> (Rat(10,3)));
112 const Rat MAXI = Rat{std::numeric_limits<int64_t>::max()};
113 const Rat MINI = Rat{1, std::numeric_limits<int64_t>::max()};
115 CHECK (rational_cast<int64_t>(MAXI) == std::numeric_limits<int64_t>::max());
116 CHECK (rational_cast<double> (MAXI) == 9.2233720368547758e+18);
120 CHECK (MAXI+1 < -MAXI);
131 CHECK (
util::toString(1-MINI) ==
"9223372036854775806/9223372036854775807sec");
132 CHECK (
util::toString(1+MINI) ==
"-9223372036854775808/9223372036854775807sec");
134 CHECK ((MAXI-1)/MAXI == 1-MINI);
135 CHECK (MAXI/(MAXI-1) > 1);
136 CHECK (MAXI/(MAXI-1) - 1 > MINI);
137 CHECK (1 - MAXI/(MAXI-1) < -MINI);
138 CHECK (
util::toString(MAXI/(MAXI-1)) ==
"9223372036854775807/9223372036854775806sec");
139 CHECK (
util::toString(MAXI/(MAXI-1) - 1) ==
"1/9223372036854775806sec");
140 CHECK (
util::toString(1 - MAXI/(MAXI-1)) ==
"-1/9223372036854775806sec");
143 const Rat MIMI = -MAXI-1;
150 NOTREACHED(
"expected boost::rational to flounder");
152 catch (std::exception& tilt)
154 CHECK (tilt.what() ==
string{
"bad rational: non-zero singular denominator"});
159 Rat poison = MAXI/49 / (MAXI/49-1);
160 Rat decoy = poison + 5;
163 CHECK (rational_cast<double>(decoy) == 6);
164 CHECK (rational_cast<double>(decoy+5) == 11);
165 CHECK (rational_cast<double>(decoy+50) == -42);
166 CHECK (rational_cast<double>(decoy+500) == 15.999999999999996);
169 CHECK ( can_represent_Sum(decoy,5));
170 CHECK (not can_represent_Sum(decoy,50));
173 CHECK ( can_represent_Sum(decoy,15));
174 CHECK (not can_represent_Sum(decoy,16));
175 CHECK (decoy+16 > 0);
176 CHECK (decoy+43 > 0);
177 CHECK (decoy+44 < 0);
180 CHECK (poison + 1_r/10 > 0);
181 CHECK (poison + 1_r/90 > 0);
182 CHECK (poison + 1_r/98 < 0);
183 CHECK ( can_represent_Sum(poison,1_r/10));
184 CHECK ( can_represent_Sum(poison,1_r/15));
185 CHECK (not can_represent_Sum(poison,1_r/16));
186 CHECK (not can_represent_Sum(poison,1_r/91));
187 CHECK (not can_represent_Sum(poison,1_r/100));
201 CHECK ( 5 ==
ilog2( int64_t(0b101010)));
202 CHECK ( 5 ==
ilog2(uint64_t(0b101010)));
203 CHECK ( 5 ==
ilog2( int32_t(0b101010)));
204 CHECK ( 5 ==
ilog2(uint32_t(0b101010)));
205 CHECK ( 5 ==
ilog2( int16_t(0b101010)));
206 CHECK ( 5 ==
ilog2(uint16_t(0b101010)));
207 CHECK ( 5 ==
ilog2( int8_t(0b101010)));
208 CHECK ( 5 ==
ilog2( uint8_t(0b101010)));
209 CHECK ( 5 ==
ilog2(
int (0b101010)));
210 CHECK ( 5 ==
ilog2( uint (0b101010)));
211 CHECK ( 5 ==
ilog2(
char (0b101010)));
212 CHECK ( 5 ==
ilog2( uchar (0b101010)));
213 CHECK ( 5 ==
ilog2(
long (0b101010)));
214 CHECK ( 5 ==
ilog2( ulong (0b101010)));
215 CHECK ( 5 ==
ilog2(
short (0b101010)));
216 CHECK ( 5 ==
ilog2( ushort (0b101010)));
218 CHECK (63 ==
ilog2(std::numeric_limits<uint64_t>::max()));
219 CHECK (62 ==
ilog2(std::numeric_limits< int64_t>::max()));
220 CHECK (31 ==
ilog2(std::numeric_limits<uint32_t>::max()));
221 CHECK (30 ==
ilog2(std::numeric_limits< int32_t>::max()));
222 CHECK (15 ==
ilog2(std::numeric_limits<uint16_t>::max()));
223 CHECK (14 ==
ilog2(std::numeric_limits< int16_t>::max()));
224 CHECK ( 7 ==
ilog2(std::numeric_limits< uint8_t>::max()));
225 CHECK ( 6 ==
ilog2(std::numeric_limits< int8_t>::max()));
227 CHECK ( 5 ==
ilog2(0b111111));
228 CHECK ( 5 ==
ilog2(0b101110));
229 CHECK ( 5 ==
ilog2(0b100100));
230 CHECK ( 5 ==
ilog2(0b100000));
232 CHECK ( 2 ==
ilog2(4));
233 CHECK ( 1 ==
ilog2(2));
234 CHECK ( 0 ==
ilog2(1));
235 CHECK (-1 ==
ilog2(0));
236 CHECK (-1 ==
ilog2(-1));
238 CHECK (-1 ==
ilog2(std::numeric_limits<uint64_t>::min()));
239 CHECK (-1 ==
ilog2(std::numeric_limits< int64_t>::min()));
240 CHECK (-1 ==
ilog2(std::numeric_limits<uint32_t>::min()));
241 CHECK (-1 ==
ilog2(std::numeric_limits< int32_t>::min()));
242 CHECK (-1 ==
ilog2(std::numeric_limits<uint16_t>::min()));
243 CHECK (-1 ==
ilog2(std::numeric_limits< int16_t>::min()));
244 CHECK (-1 ==
ilog2(std::numeric_limits< uint8_t>::min()));
245 CHECK (-1 ==
ilog2(std::numeric_limits< int8_t>::min()));
250 auto floatLog = [](
auto n)
252 return n <=0? -1 : ilogb(n);
254 auto bitshift = [](
auto n)
256 if (n <= 0)
return -1;
262 auto do_nothing = [](
auto n){
return n; };
264 array<uint64_t, 1000> numz;
267 n = rand() * uint64_t(1 << 31);
268 CHECK (
ilog2(n) == floatLog(n));
269 CHECK (
ilog2(n) == bitshift(n));
273 auto microbenchmark = [&numz,&dump](
auto algo)
275 using std::chrono::system_clock;
276 using Dur = std::chrono::duration<double>;
277 const double SCALE = 1e9;
279 auto start = system_clock::now();
280 for (uint i=0; i<1000; ++i)
281 for (
auto const& n : numz)
283 Dur duration = system_clock::now () - start;
284 return duration.count()/(1000*1000) * SCALE;
289 auto time_ilog2 = microbenchmark(ilog2<int64_t>);
290 auto time_float = microbenchmark(floatLog);
291 auto time_shift = microbenchmark(bitshift);
292 auto time_ident = microbenchmark(do_nothing);
294 cout <<
"Microbenchmark integer-log2" <<endl
295 <<
"util::ilog2 :"<<time_ilog2<<
"ns"<<endl
296 <<
"std::ilogb :"<<time_float<<
"ns"<<endl
297 <<
"bit-shift :"<<time_shift<<
"ns"<<endl
298 <<
"identity :"<<time_ident<<
"ns"<<endl
299 <<
"(checksum="<<dump<<
")" <<endl;
302 CHECK (time_ilog2 < time_shift);
303 CHECK (time_ident < time_ilog2);
333 const int64_t
MAX{std::numeric_limits<int64_t>::max()};
334 const Rat MAXI = Rat{
MAX};
336 Rat poison = (MAXI-88)/(MAXI/7);
338 auto approx = [](Rat rat){
return rational_cast<
float> (rat); };
340 CHECK (poison+1 < 0);
341 CHECK (approx (poison ) == 6.99999952f);
342 CHECK (approx (poison+1) == -6);
343 CHECK (approx (poison+7) == -6.83047369e-17f);
344 CHECK (approx (poison+9_r/5) == 0.400000006f);
346 Rat sleazy =
reQuant (poison, 1 << 24);
347 CHECK (sleazy.denominator() == 1 << 24);
350 CHECK (sleazy+1 > 0);
351 CHECK (sleazy+7 > 0);
352 CHECK (approx (sleazy) == 7);
353 CHECK (approx (sleazy+1) == 8);
354 CHECK (approx (sleazy+7) == 14);
355 CHECK (approx (sleazy+9_r/5) == 8.80000019f);
357 CHECK (
util::toString (poison) ==
"9223372036854775719/1317624576693539401sec");
358 CHECK (
util::toString (poison+1) ==
"-7905747460161236496/1317624576693539401sec");
363 CHECK (
reQuant (1/poison,
MAX) == 1317624576693539413_r/9223372036854775807);
364 CHECK (
reQuant (-poison, 7777) == -54438_r/ 7777);
365 CHECK (
reQuant (poison, -7777) == -54438_r/-7777);
367 CHECK (approx ( 1/poison ) == 0.142857149f);
368 CHECK (approx (
reQuant (1/poison,
MAX)) == 0.142857149f);
369 CHECK (approx (
reQuant (poison, 7777)) == 6.99987125f);
int64_t reQuant(int64_t num, int64_t den, int64_t u)
Re-Quantise a number into a new grid, truncating to the next lower grid point.
Rational number support, based on boost::rational.
#define MAX(A, B)
the inevitable MAX macro, sometimes still necessary in template code
void demonstrate_basics()
Simple test class runner.
Lumiera error handling (C++ interface).
constexpr int ilog2(I num)
Integral binary logarithm (disregarding fractional part)