generalise to long and int; improve test coverage
This commit is contained in:
parent
05383ea44a
commit
c55260d4e4
4 changed files with 205 additions and 108 deletions
|
|
@ -56,6 +56,30 @@ namespace util {
|
|||
return n1 < n2? N1(n2) : n1;
|
||||
}
|
||||
|
||||
|
||||
/** helper to treat int or long division uniformly */
|
||||
template<typename I>
|
||||
struct IDiv;
|
||||
|
||||
template<>
|
||||
struct IDiv<int>
|
||||
: div_t
|
||||
{
|
||||
IDiv<int> (int num, int den)
|
||||
: div_t(div (num,den))
|
||||
{ }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct IDiv<long>
|
||||
: ldiv_t
|
||||
{
|
||||
IDiv<long> (long num, long den)
|
||||
: ldiv_t(ldiv (num,den))
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
/** floor function for integer arithmetics.
|
||||
* Unlike the built-in integer division, this function
|
||||
* always rounds towards the next \em smaller integer,
|
||||
|
|
@ -63,20 +87,44 @@ namespace util {
|
|||
* @warning floor on doubles performs way better
|
||||
* @see UtilFloordiv_test
|
||||
*/
|
||||
template<typename LI>
|
||||
inline LI
|
||||
floordiv (LI num, LI den)
|
||||
template<typename I>
|
||||
inline I
|
||||
floordiv (I num, I den)
|
||||
{
|
||||
if (0 < (num^den))
|
||||
return num/den;
|
||||
else
|
||||
{ // truncate similar to floor()
|
||||
ldiv_t res = ldiv(num,den);
|
||||
IDiv<I> res(num,den);
|
||||
return (res.rem)? res.quot-1 // negative results truncated towards next smaller int
|
||||
: res.quot; //..unless the division result not truncated at all
|
||||
}
|
||||
}
|
||||
|
||||
/** scale wrapping operation.
|
||||
* Quantises the numerator value into the scale given by the denominator.
|
||||
* Unlike the built-in integer division, this function always rounds towards
|
||||
* the next \em smaller integer and also relates the remainder (=modulo) to
|
||||
* this next lower scale grid point.
|
||||
* @return quotient and remainder packed into a struct
|
||||
* @see UtilFloorwarp_test
|
||||
*/
|
||||
template<typename I>
|
||||
inline IDiv<I>
|
||||
floorwrap (I num, I den)
|
||||
{
|
||||
IDiv<I> res(num,den);
|
||||
if (0 > (num^den) && res.rem)
|
||||
{ // negative results
|
||||
// wrapped similar to floor()
|
||||
--res.quot;
|
||||
res.rem = den - (-res.rem);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* ======== generic empty check ========= */
|
||||
|
||||
/** a family of util functions providing a "no value whatsoever" test.
|
||||
Works on strings and all STL containers, includes NULL test for pointers */
|
||||
|
|
|
|||
|
|
@ -1094,32 +1094,111 @@ return: 0
|
|||
END
|
||||
|
||||
|
||||
PLANNED "integer scale wrapping utility" UtilFloorwrap_test <<END
|
||||
out-lit: 12 / 4 = 3 % = 0 floor= 3.0 wrap = ( 3, 0)
|
||||
out-lit: 11 / 4 = 2 % = 3 floor= 2.0 wrap = ( 2, 3)
|
||||
out-lit: 10 / 4 = 2 % = 2 floor= 2.0 wrap = ( 2, 2)
|
||||
out-lit: 9 / 4 = 2 % = 1 floor= 2.0 wrap = ( 2, 1)
|
||||
out-lit: 8 / 4 = 2 % = 0 floor= 2.0 wrap = ( 2, 0)
|
||||
out-lit: 7 / 4 = 1 % = 3 floor= 1.0 wrap = ( 1, 3)
|
||||
out-lit: 6 / 4 = 1 % = 2 floor= 1.0 wrap = ( 1, 2)
|
||||
out-lit: 5 / 4 = 1 % = 1 floor= 1.0 wrap = ( 1, 1)
|
||||
out-lit: 4 / 4 = 1 % = 0 floor= 1.0 wrap = ( 1, 0)
|
||||
out-lit: 3 / 4 = 0 % = 3 floor= 0.0 wrap = ( 0, 3)
|
||||
out-lit: 2 / 4 = 0 % = 2 floor= 0.0 wrap = ( 0, 2)
|
||||
out-lit: 1 / 4 = 0 % = 1 floor= 0.0 wrap = ( 0, 1)
|
||||
out-lit: 0 / 4 = 0 % = 0 floor= 0.0 wrap = ( 0, 0)
|
||||
out-lit: -1 / 4 = 0 % =-1 floor=-1.0 wrap = (-1, 3)
|
||||
out-lit: -2 / 4 = 0 % =-2 floor=-1.0 wrap = (-1, 2)
|
||||
out-lit: -3 / 4 = 0 % =-3 floor=-1.0 wrap = (-1, 1)
|
||||
out-lit: -4 / 4 =-1 % = 0 floor=-1.0 wrap = (-1, 0)
|
||||
out-lit: -5 / 4 =-1 % =-1 floor=-2.0 wrap = (-2, 3)
|
||||
out-lit: -6 / 4 =-1 % =-2 floor=-2.0 wrap = (-2, 2)
|
||||
out-lit: -7 / 4 =-1 % =-3 floor=-2.0 wrap = (-2, 1)
|
||||
out-lit: -8 / 4 =-2 % = 0 floor=-2.0 wrap = (-2, 0)
|
||||
out-lit: -9 / 4 =-2 % =-1 floor=-3.0 wrap = (-3, 3)
|
||||
out-lit:-10 / 4 =-2 % =-2 floor=-3.0 wrap = (-3, 2)
|
||||
out-lit:-11 / 4 =-2 % =-3 floor=-3.0 wrap = (-3, 1)
|
||||
out-lit:-12 / 4 =-3 % = 0 floor=-3.0 wrap = (-3, 0)
|
||||
TEST "integer scale wrapping utility" UtilFloorwrap_test <<END
|
||||
out-lit: --------i--------12/4
|
||||
out-lit: 12 / 4 = 3 % = 0 floor= 3.0 wrap = ( 3, 0)
|
||||
out-lit: 11 / 4 = 2 % = 3 floor= 2.0 wrap = ( 2, 3)
|
||||
out-lit: 10 / 4 = 2 % = 2 floor= 2.0 wrap = ( 2, 2)
|
||||
out-lit: 9 / 4 = 2 % = 1 floor= 2.0 wrap = ( 2, 1)
|
||||
out-lit: 8 / 4 = 2 % = 0 floor= 2.0 wrap = ( 2, 0)
|
||||
out-lit: 7 / 4 = 1 % = 3 floor= 1.0 wrap = ( 1, 3)
|
||||
out-lit: 6 / 4 = 1 % = 2 floor= 1.0 wrap = ( 1, 2)
|
||||
out-lit: 5 / 4 = 1 % = 1 floor= 1.0 wrap = ( 1, 1)
|
||||
out-lit: 4 / 4 = 1 % = 0 floor= 1.0 wrap = ( 1, 0)
|
||||
out-lit: 3 / 4 = 0 % = 3 floor= 0.0 wrap = ( 0, 3)
|
||||
out-lit: 2 / 4 = 0 % = 2 floor= 0.0 wrap = ( 0, 2)
|
||||
out-lit: 1 / 4 = 0 % = 1 floor= 0.0 wrap = ( 0, 1)
|
||||
out-lit: 0 / 4 = 0 % = 0 floor= 0.0 wrap = ( 0, 0)
|
||||
out-lit: -1 / 4 = 0 % =-1 floor=-1.0 wrap = (-1, 3)
|
||||
out-lit: -2 / 4 = 0 % =-2 floor=-1.0 wrap = (-1, 2)
|
||||
out-lit: -3 / 4 = 0 % =-3 floor=-1.0 wrap = (-1, 1)
|
||||
out-lit: -4 / 4 =-1 % = 0 floor=-1.0 wrap = (-1, 0)
|
||||
out-lit: -5 / 4 =-1 % =-1 floor=-2.0 wrap = (-2, 3)
|
||||
out-lit: -6 / 4 =-1 % =-2 floor=-2.0 wrap = (-2, 2)
|
||||
out-lit: -7 / 4 =-1 % =-3 floor=-2.0 wrap = (-2, 1)
|
||||
out-lit: -8 / 4 =-2 % = 0 floor=-2.0 wrap = (-2, 0)
|
||||
out-lit: -9 / 4 =-2 % =-1 floor=-3.0 wrap = (-3, 3)
|
||||
out-lit: -10 / 4 =-2 % =-2 floor=-3.0 wrap = (-3, 2)
|
||||
out-lit: -11 / 4 =-2 % =-3 floor=-3.0 wrap = (-3, 1)
|
||||
out-lit: -12 / 4 =-3 % = 0 floor=-3.0 wrap = (-3, 0)
|
||||
out-lit: --------i--------12/-4
|
||||
out-lit: 12 /-4 =-3 % = 0 floor=-3.0 wrap = (-3, 0)
|
||||
out-lit: 11 /-4 =-2 % = 3 floor=-3.0 wrap = (-3,-1)
|
||||
out-lit: 10 /-4 =-2 % = 2 floor=-3.0 wrap = (-3,-2)
|
||||
out-lit: 9 /-4 =-2 % = 1 floor=-3.0 wrap = (-3,-3)
|
||||
out-lit: 8 /-4 =-2 % = 0 floor=-2.0 wrap = (-2, 0)
|
||||
out-lit: 7 /-4 =-1 % = 3 floor=-2.0 wrap = (-2,-1)
|
||||
out-lit: 6 /-4 =-1 % = 2 floor=-2.0 wrap = (-2,-2)
|
||||
out-lit: 5 /-4 =-1 % = 1 floor=-2.0 wrap = (-2,-3)
|
||||
out-lit: 4 /-4 =-1 % = 0 floor=-1.0 wrap = (-1, 0)
|
||||
out-lit: 3 /-4 = 0 % = 3 floor=-1.0 wrap = (-1,-1)
|
||||
out-lit: 2 /-4 = 0 % = 2 floor=-1.0 wrap = (-1,-2)
|
||||
out-lit: 1 /-4 = 0 % = 1 floor=-1.0 wrap = (-1,-3)
|
||||
out-lit: 0 /-4 = 0 % = 0 floor=-0.0 wrap = ( 0, 0)
|
||||
out-lit: -1 /-4 = 0 % =-1 floor= 0.0 wrap = ( 0,-1)
|
||||
out-lit: -2 /-4 = 0 % =-2 floor= 0.0 wrap = ( 0,-2)
|
||||
out-lit: -3 /-4 = 0 % =-3 floor= 0.0 wrap = ( 0,-3)
|
||||
out-lit: -4 /-4 = 1 % = 0 floor= 1.0 wrap = ( 1, 0)
|
||||
out-lit: -5 /-4 = 1 % =-1 floor= 1.0 wrap = ( 1,-1)
|
||||
out-lit: -6 /-4 = 1 % =-2 floor= 1.0 wrap = ( 1,-2)
|
||||
out-lit: -7 /-4 = 1 % =-3 floor= 1.0 wrap = ( 1,-3)
|
||||
out-lit: -8 /-4 = 2 % = 0 floor= 2.0 wrap = ( 2, 0)
|
||||
out-lit: -9 /-4 = 2 % =-1 floor= 2.0 wrap = ( 2,-1)
|
||||
out-lit: -10 /-4 = 2 % =-2 floor= 2.0 wrap = ( 2,-2)
|
||||
out-lit: -11 /-4 = 2 % =-3 floor= 2.0 wrap = ( 2,-3)
|
||||
out-lit: -12 /-4 = 3 % = 0 floor= 3.0 wrap = ( 3, 0)
|
||||
out-lit: --------l--------12/4
|
||||
out-lit: 12 / 4 = 3 % = 0 floor= 3.0 wrap = ( 3, 0)
|
||||
out-lit: 11 / 4 = 2 % = 3 floor= 2.0 wrap = ( 2, 3)
|
||||
out-lit: 10 / 4 = 2 % = 2 floor= 2.0 wrap = ( 2, 2)
|
||||
out-lit: 9 / 4 = 2 % = 1 floor= 2.0 wrap = ( 2, 1)
|
||||
out-lit: 8 / 4 = 2 % = 0 floor= 2.0 wrap = ( 2, 0)
|
||||
out-lit: 7 / 4 = 1 % = 3 floor= 1.0 wrap = ( 1, 3)
|
||||
out-lit: 6 / 4 = 1 % = 2 floor= 1.0 wrap = ( 1, 2)
|
||||
out-lit: 5 / 4 = 1 % = 1 floor= 1.0 wrap = ( 1, 1)
|
||||
out-lit: 4 / 4 = 1 % = 0 floor= 1.0 wrap = ( 1, 0)
|
||||
out-lit: 3 / 4 = 0 % = 3 floor= 0.0 wrap = ( 0, 3)
|
||||
out-lit: 2 / 4 = 0 % = 2 floor= 0.0 wrap = ( 0, 2)
|
||||
out-lit: 1 / 4 = 0 % = 1 floor= 0.0 wrap = ( 0, 1)
|
||||
out-lit: 0 / 4 = 0 % = 0 floor= 0.0 wrap = ( 0, 0)
|
||||
out-lit: -1 / 4 = 0 % =-1 floor=-1.0 wrap = (-1, 3)
|
||||
out-lit: -2 / 4 = 0 % =-2 floor=-1.0 wrap = (-1, 2)
|
||||
out-lit: -3 / 4 = 0 % =-3 floor=-1.0 wrap = (-1, 1)
|
||||
out-lit: -4 / 4 =-1 % = 0 floor=-1.0 wrap = (-1, 0)
|
||||
out-lit: -5 / 4 =-1 % =-1 floor=-2.0 wrap = (-2, 3)
|
||||
out-lit: -6 / 4 =-1 % =-2 floor=-2.0 wrap = (-2, 2)
|
||||
out-lit: -7 / 4 =-1 % =-3 floor=-2.0 wrap = (-2, 1)
|
||||
out-lit: -8 / 4 =-2 % = 0 floor=-2.0 wrap = (-2, 0)
|
||||
out-lit: -9 / 4 =-2 % =-1 floor=-3.0 wrap = (-3, 3)
|
||||
out-lit: -10 / 4 =-2 % =-2 floor=-3.0 wrap = (-3, 2)
|
||||
out-lit: -11 / 4 =-2 % =-3 floor=-3.0 wrap = (-3, 1)
|
||||
out-lit: -12 / 4 =-3 % = 0 floor=-3.0 wrap = (-3, 0)
|
||||
out-lit: --------l--------12/-4
|
||||
out-lit: 12 /-4 =-3 % = 0 floor=-3.0 wrap = (-3, 0)
|
||||
out-lit: 11 /-4 =-2 % = 3 floor=-3.0 wrap = (-3,-1)
|
||||
out-lit: 10 /-4 =-2 % = 2 floor=-3.0 wrap = (-3,-2)
|
||||
out-lit: 9 /-4 =-2 % = 1 floor=-3.0 wrap = (-3,-3)
|
||||
out-lit: 8 /-4 =-2 % = 0 floor=-2.0 wrap = (-2, 0)
|
||||
out-lit: 7 /-4 =-1 % = 3 floor=-2.0 wrap = (-2,-1)
|
||||
out-lit: 6 /-4 =-1 % = 2 floor=-2.0 wrap = (-2,-2)
|
||||
out-lit: 5 /-4 =-1 % = 1 floor=-2.0 wrap = (-2,-3)
|
||||
out-lit: 4 /-4 =-1 % = 0 floor=-1.0 wrap = (-1, 0)
|
||||
out-lit: 3 /-4 = 0 % = 3 floor=-1.0 wrap = (-1,-1)
|
||||
out-lit: 2 /-4 = 0 % = 2 floor=-1.0 wrap = (-1,-2)
|
||||
out-lit: 1 /-4 = 0 % = 1 floor=-1.0 wrap = (-1,-3)
|
||||
out-lit: 0 /-4 = 0 % = 0 floor=-0.0 wrap = ( 0, 0)
|
||||
out-lit: -1 /-4 = 0 % =-1 floor= 0.0 wrap = ( 0,-1)
|
||||
out-lit: -2 /-4 = 0 % =-2 floor= 0.0 wrap = ( 0,-2)
|
||||
out-lit: -3 /-4 = 0 % =-3 floor= 0.0 wrap = ( 0,-3)
|
||||
out-lit: -4 /-4 = 1 % = 0 floor= 1.0 wrap = ( 1, 0)
|
||||
out-lit: -5 /-4 = 1 % =-1 floor= 1.0 wrap = ( 1,-1)
|
||||
out-lit: -6 /-4 = 1 % =-2 floor= 1.0 wrap = ( 1,-2)
|
||||
out-lit: -7 /-4 = 1 % =-3 floor= 1.0 wrap = ( 1,-3)
|
||||
out-lit: -8 /-4 = 2 % = 0 floor= 2.0 wrap = ( 2, 0)
|
||||
out-lit: -9 /-4 = 2 % =-1 floor= 2.0 wrap = ( 2,-1)
|
||||
out-lit: -10 /-4 = 2 % =-2 floor= 2.0 wrap = ( 2,-2)
|
||||
out-lit: -11 /-4 = 2 % =-3 floor= 2.0 wrap = ( 2,-3)
|
||||
out-lit: -12 /-4 = 3 % = 0 floor= 3.0 wrap = ( 3, 0)
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
|
|
|||
|
|
@ -174,15 +174,13 @@ namespace test {
|
|||
* a precision beyond the 16 digits provided by double.
|
||||
* Besides that, we can conclude that the additional tests and
|
||||
* adjustment of the custom floordiv only creates a slight overhead
|
||||
* compared to the built-in integer div function. The comparison
|
||||
* with the \c floordiv<int> instantiation is largely moot, because
|
||||
* this internally calls \c fdiv on values promoted to long. Another
|
||||
* oddity in the same category is the slightly better performance
|
||||
* of long over int64_t. Also, the alternative formulation of
|
||||
* the function, which uses the \c fdiv() function also to divide
|
||||
* the positive results, performs only slightly worse. So this
|
||||
* actual implementation was chosen mainly because it seems
|
||||
* to state its intent more clearly in code.
|
||||
* compared to the built-in integer div function. An oddity to note
|
||||
* is the slightly better performance of long over int64_t. Also,
|
||||
* the alternative formulation of the function, which uses the
|
||||
* \c fdiv() function also to divide the positive results,
|
||||
* performs only slightly worse. So this implementation
|
||||
* was chosen mainly because it seems to state its
|
||||
* intent more clearly in code.
|
||||
*/
|
||||
void
|
||||
runPerformanceTest ()
|
||||
|
|
|
|||
|
|
@ -22,17 +22,20 @@
|
|||
|
||||
|
||||
#include "lib/test/run.hpp"
|
||||
#include "lib/test/test-helper.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
#include <cmath>
|
||||
//#include <vector>
|
||||
#include <iostream>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
using ::Test;
|
||||
using std::cout;
|
||||
//using std::rand;
|
||||
using std::endl;
|
||||
using boost::format;
|
||||
using boost::lexical_cast;
|
||||
using lib::test::showType;
|
||||
|
||||
|
||||
namespace util {
|
||||
|
|
@ -40,51 +43,18 @@ namespace test {
|
|||
|
||||
|
||||
|
||||
namespace{ // Test data and operations
|
||||
|
||||
div_t
|
||||
floorwrap (int num, int den)
|
||||
{
|
||||
div_t res = div (num,den);
|
||||
if (0 > (num^den) && res.rem)
|
||||
{ // wrap similar to floor()
|
||||
--res.quot;
|
||||
res.rem = den - (-res.rem);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
showWrap (int val, int scale)
|
||||
{
|
||||
div_t wrap = floorwrap(val,scale);
|
||||
cout << format ("% 3d /% 1d =% 1d %% =% d floor=% 4.1f wrap = (%2d,%2d) \n")
|
||||
% val % scale % (val/scale)
|
||||
% (val%scale) % floor(double(val)/scale)
|
||||
% wrap.quot % wrap.rem;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // (End) test data and operations
|
||||
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* @test Evaluate a custom built integer floor function.
|
||||
* This function is crucial for Lumiera's rule of quantisation
|
||||
* of time values into frame intervals. This rule requires time
|
||||
* points to be rounded towards the next lower frame border always,
|
||||
* irrespective of the relation to the actual time origin.
|
||||
* Contrast this to the built-in integer division operator, which
|
||||
* truncates towards zero.
|
||||
*
|
||||
* @note if invoked with an non empty parameter, this test performs
|
||||
* some interesting timing comparisons, which initially were
|
||||
* used to tweak the implementation a bit.
|
||||
/***************************************************************************
|
||||
* @test Verify a custom built integer scale division and wrapping function.
|
||||
* This function is relevant for decimating values into a given scale,
|
||||
* like splitting time measurements in hours, minutes, seconds etc.
|
||||
* Basically, in Lumiera the quantisation into a scale is always
|
||||
* done with the same orientation, irrespective of the zero point
|
||||
* on the given scale. Contrast this to the built-in integer
|
||||
* division and modulo operators working symmetrical to zero.
|
||||
* @see util.hpp
|
||||
* @see QuantiserBasics_test
|
||||
* @see TimeFormats_test
|
||||
*/
|
||||
class UtilFloorwrap_test : public Test
|
||||
{
|
||||
|
|
@ -92,34 +62,36 @@ namespace test {
|
|||
virtual void
|
||||
run (Arg arg)
|
||||
{
|
||||
showWrap ( 12,4);
|
||||
showWrap ( 11,4);
|
||||
showWrap ( 10,4);
|
||||
showWrap ( 9,4);
|
||||
showWrap ( 8,4);
|
||||
showWrap ( 7,4);
|
||||
showWrap ( 6,4);
|
||||
showWrap ( 5,4);
|
||||
showWrap ( 4,4);
|
||||
showWrap ( 3,4);
|
||||
showWrap ( 2,4);
|
||||
showWrap ( 1,4);
|
||||
showWrap ( 0,4);
|
||||
showWrap (- 1,4);
|
||||
showWrap (- 2,4);
|
||||
showWrap (- 3,4);
|
||||
showWrap (- 4,4);
|
||||
showWrap (- 5,4);
|
||||
showWrap (- 6,4);
|
||||
showWrap (- 7,4);
|
||||
showWrap (- 8,4);
|
||||
showWrap (- 9,4);
|
||||
showWrap (-10,4);
|
||||
showWrap (-11,4);
|
||||
showWrap (-12,4);
|
||||
int range = 0 < arg.size()? lexical_cast<int> (arg[0]) : 12;
|
||||
int scale = 1 < arg.size()? lexical_cast<int> (arg[1]) : 4;
|
||||
|
||||
checkWrap (range, scale);
|
||||
checkWrap (range, -scale);
|
||||
checkWrap<long> (range, scale);
|
||||
checkWrap<long> (range, -scale);
|
||||
}
|
||||
|
||||
|
||||
template<typename I>
|
||||
void
|
||||
checkWrap (I range, I scale)
|
||||
{
|
||||
cout << "--------"<< showType<I>()
|
||||
<< "--------"<< range<<"/"<<scale<<endl;
|
||||
for (I i=range; i >=-range; --i)
|
||||
showWrap (i, scale);
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
void
|
||||
showWrap (I val, I scale)
|
||||
{
|
||||
IDiv<I> wrap = floorwrap(val,scale);
|
||||
cout << format ("% 3d /% 1d =% 1d %% =% d floor=% 4.1f wrap = (%2d,%2d)\n")
|
||||
% val % scale % (val/scale)
|
||||
% (val%scale) % floor(double(val)/scale)
|
||||
% wrap.quot % wrap.rem;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue