2011-01-09 00:40:27 +01:00
|
|
|
|
/*
|
|
|
|
|
|
UtilFloordiv(Test) - verify integer rounding function
|
|
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
Copyright (C)
|
|
|
|
|
|
2011, Hermann Vosseler <Ichthyostega@web.de>
|
2011-01-09 00:40:27 +01:00
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
**Lumiera** is free software; you can redistribute it and/or modify it
|
|
|
|
|
|
under the terms of the GNU General Public License as published by the
|
|
|
|
|
|
Free Software Foundation; either version 2 of the License, or (at your
|
|
|
|
|
|
option) any later version. See the file COPYING for further details.
|
2011-01-09 00:40:27 +01:00
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
* *****************************************************************/
|
2011-01-09 00:40:27 +01:00
|
|
|
|
|
2017-02-22 01:54:20 +01:00
|
|
|
|
/** @file util-floordiv-test.cpp
|
2017-02-22 03:17:18 +01:00
|
|
|
|
** unit test \ref UtilFloordiv_test
|
2016-11-03 18:20:10 +01:00
|
|
|
|
*/
|
|
|
|
|
|
|
2011-01-09 00:40:27 +01:00
|
|
|
|
|
|
|
|
|
|
#include "lib/test/run.hpp"
|
2012-03-04 01:34:18 +01:00
|
|
|
|
#include "lib/util-quant.hpp"
|
2011-01-09 00:40:27 +01:00
|
|
|
|
#include "lib/util.hpp"
|
|
|
|
|
|
|
2016-01-07 03:58:29 +01:00
|
|
|
|
#include "lib/format-cout.hpp"
|
|
|
|
|
|
#include "lib/format-string.hpp"
|
|
|
|
|
|
|
2011-01-09 00:40:27 +01:00
|
|
|
|
#include <cmath>
|
2011-10-23 22:06:32 +02:00
|
|
|
|
#include <time.h>
|
2011-01-09 00:40:27 +01:00
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
|
|
|
|
using ::Test;
|
2011-01-22 18:44:03 +01:00
|
|
|
|
using util::isnil;
|
2016-01-07 03:58:29 +01:00
|
|
|
|
using util::_Fmt;
|
2011-01-09 00:40:27 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace util {
|
|
|
|
|
|
namespace test {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace{ // Test data and operations
|
|
|
|
|
|
|
|
|
|
|
|
const uint NUM_ELMS_PERFORMANCE_TEST = 50000000;
|
|
|
|
|
|
const uint NUMBER_LIMIT = 1 << 30;
|
|
|
|
|
|
|
|
|
|
|
|
typedef std::vector<int> VecI;
|
|
|
|
|
|
|
|
|
|
|
|
VecI
|
|
|
|
|
|
buildTestNumberz (uint cnt)
|
|
|
|
|
|
{
|
|
|
|
|
|
VecI data;
|
|
|
|
|
|
for (uint i=0; i<cnt; ++i)
|
|
|
|
|
|
{
|
2024-11-13 17:56:50 +01:00
|
|
|
|
int someNumber = -int(NUMBER_LIMIT)+rani(2*NUMBER_LIMIT);
|
|
|
|
|
|
if (!someNumber) someNumber -= 1 + rani(NUMBER_LIMIT);
|
2011-01-09 00:40:27 +01:00
|
|
|
|
|
|
|
|
|
|
data.push_back (someNumber);
|
|
|
|
|
|
}
|
|
|
|
|
|
return data;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** the built-in integer division operator,
|
|
|
|
|
|
* packaged as inline function for timing comparison
|
|
|
|
|
|
*/
|
|
|
|
|
|
inline long
|
|
|
|
|
|
integerDiv (long num, long den)
|
|
|
|
|
|
{
|
|
|
|
|
|
return num / den;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** an alternate formulation,
|
|
|
|
|
|
* which turned out to perform slightly worse
|
|
|
|
|
|
*/
|
|
|
|
|
|
inline long
|
|
|
|
|
|
floordiv_alternate (long num, long den)
|
|
|
|
|
|
{
|
|
|
|
|
|
ldiv_t res = ldiv(num,den);
|
2025-06-07 23:59:57 +02:00
|
|
|
|
return (0 >= res.quot and res.rem)? res.quot-1
|
|
|
|
|
|
: res.quot;
|
2011-01-09 00:40:27 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} // (End) test data and operations
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-10-24 23:06:36 +02:00
|
|
|
|
/******************************************************************//**
|
2011-01-09 00:40:27 +01:00
|
|
|
|
* @test Evaluate a custom built integer floor function.
|
2011-03-31 18:43:50 +02:00
|
|
|
|
* Also known as Knuth's floor division.
|
2011-01-09 00:40:27 +01:00
|
|
|
|
* 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.
|
2017-04-02 04:22:51 +02:00
|
|
|
|
* @see lib/util.hpp
|
2011-01-09 00:40:27 +01:00
|
|
|
|
* @see QuantiserBasics_test
|
|
|
|
|
|
*/
|
|
|
|
|
|
class UtilFloordiv_test : public Test
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
virtual void
|
|
|
|
|
|
run (Arg arg)
|
|
|
|
|
|
{
|
2024-11-13 02:23:23 +01:00
|
|
|
|
seedRand();
|
|
|
|
|
|
|
2011-01-09 00:40:27 +01:00
|
|
|
|
verifyBehaviour ();
|
|
|
|
|
|
|
2011-03-31 18:43:50 +02:00
|
|
|
|
verifyIntegerTypes<int>();
|
|
|
|
|
|
verifyIntegerTypes<long>();
|
|
|
|
|
|
verifyIntegerTypes<short>();
|
|
|
|
|
|
verifyIntegerTypes<int64_t>();
|
2024-11-21 18:07:30 +01:00
|
|
|
|
verifyIntegerTypes<llong>();
|
2011-03-31 18:43:50 +02:00
|
|
|
|
|
2025-06-07 23:59:57 +02:00
|
|
|
|
if (not isnil (arg))
|
2011-01-09 00:40:27 +01:00
|
|
|
|
runPerformanceTest();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
verifyBehaviour ()
|
|
|
|
|
|
{
|
|
|
|
|
|
CHECK ( 3 == floordiv ( 12,4));
|
|
|
|
|
|
CHECK ( 2 == floordiv ( 11,4));
|
|
|
|
|
|
CHECK ( 2 == floordiv ( 10,4));
|
|
|
|
|
|
CHECK ( 2 == floordiv ( 9,4));
|
|
|
|
|
|
CHECK ( 2 == floordiv ( 8,4));
|
|
|
|
|
|
CHECK ( 1 == floordiv ( 7,4));
|
|
|
|
|
|
CHECK ( 1 == floordiv ( 6,4));
|
|
|
|
|
|
CHECK ( 1 == floordiv ( 5,4));
|
|
|
|
|
|
CHECK ( 1 == floordiv ( 4,4));
|
|
|
|
|
|
CHECK ( 0 == floordiv ( 3,4));
|
|
|
|
|
|
CHECK ( 0 == floordiv ( 2,4));
|
|
|
|
|
|
CHECK ( 0 == floordiv ( 1,4));
|
|
|
|
|
|
CHECK ( 0 == floordiv ( 0,4));
|
|
|
|
|
|
CHECK (-1 == floordiv (- 1,4));
|
|
|
|
|
|
CHECK (-1 == floordiv (- 2,4));
|
|
|
|
|
|
CHECK (-1 == floordiv (- 3,4));
|
|
|
|
|
|
CHECK (-1 == floordiv (- 4,4));
|
|
|
|
|
|
CHECK (-2 == floordiv (- 5,4));
|
|
|
|
|
|
CHECK (-2 == floordiv (- 6,4));
|
|
|
|
|
|
CHECK (-2 == floordiv (- 7,4));
|
|
|
|
|
|
CHECK (-2 == floordiv (- 8,4));
|
|
|
|
|
|
CHECK (-3 == floordiv (- 9,4));
|
|
|
|
|
|
CHECK (-3 == floordiv (-10,4));
|
|
|
|
|
|
CHECK (-3 == floordiv (-11,4));
|
|
|
|
|
|
CHECK (-3 == floordiv (-12,4));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-03-31 18:43:50 +02:00
|
|
|
|
template<typename I>
|
|
|
|
|
|
void
|
|
|
|
|
|
verifyIntegerTypes ()
|
|
|
|
|
|
{
|
|
|
|
|
|
I n,d,expectedRes;
|
|
|
|
|
|
|
|
|
|
|
|
for (int i=-12; i <= 12; ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
n = i;
|
|
|
|
|
|
d = 4;
|
|
|
|
|
|
expectedRes = floordiv (i,4);
|
|
|
|
|
|
CHECK (floordiv(n,d) == expectedRes);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-01-09 00:40:27 +01:00
|
|
|
|
|
|
|
|
|
|
/** @test timing measurements to compare implementation details.
|
|
|
|
|
|
* This test uses a sequence of random integers, where the values
|
|
|
|
|
|
* used as denominator are ensured not to be zero.
|
|
|
|
|
|
*
|
|
|
|
|
|
* \par measurement results
|
|
|
|
|
|
* My experiments (AMD Athlon-64 4200 X2) gave me
|
|
|
|
|
|
* the following timing measurements in nanoseconds:
|
|
|
|
|
|
*
|
|
|
|
|
|
* Verification.......... 127.7
|
|
|
|
|
|
* Integer_div........... 111.7
|
|
|
|
|
|
* double_floor.......... 74.8
|
|
|
|
|
|
* floordiv_int.......... 112.7
|
|
|
|
|
|
* floordiv_long......... 119.8
|
|
|
|
|
|
* floordiv_int64_t...... 121.4
|
|
|
|
|
|
* floordiv_long_alt..... 122.7
|
|
|
|
|
|
*
|
|
|
|
|
|
* These figures are the average of 6 runs with 50 million
|
|
|
|
|
|
* iterations each (as produced by this function)
|
|
|
|
|
|
*
|
|
|
|
|
|
* \par conclusions
|
|
|
|
|
|
* The most significant result is the striking performance of the
|
|
|
|
|
|
* fpu based calculation. Consequently, integer arithmetics should
|
|
|
|
|
|
* only be used when necessary due to resolution requirements, as
|
|
|
|
|
|
* is the case for int64_t based Lumiera Time values, which require
|
|
|
|
|
|
* 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
|
2011-01-20 21:30:48 +01:00
|
|
|
|
* 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
|
2025-06-07 23:59:57 +02:00
|
|
|
|
* intent more clearly in code.
|
2011-01-09 00:40:27 +01:00
|
|
|
|
*/
|
|
|
|
|
|
void
|
|
|
|
|
|
runPerformanceTest ()
|
|
|
|
|
|
{
|
|
|
|
|
|
VecI testdata = buildTestNumberz (2*NUM_ELMS_PERFORMANCE_TEST);
|
|
|
|
|
|
typedef VecI::const_iterator I;
|
|
|
|
|
|
|
|
|
|
|
|
clock_t start(0), stop(0);
|
2016-01-07 03:58:29 +01:00
|
|
|
|
_Fmt resultDisplay{"timings(%s)%|30T.|%5.3fsec\n"};
|
2011-01-09 00:40:27 +01:00
|
|
|
|
|
2025-06-07 23:59:57 +02:00
|
|
|
|
#define START_TIMINGS start=clock();
|
2011-01-09 00:40:27 +01:00
|
|
|
|
#define DISPLAY_TIMINGS(ID) \
|
|
|
|
|
|
stop = clock(); \
|
|
|
|
|
|
cout << resultDisplay % STRINGIFY (ID) % (double(stop-start)/CLOCKS_PER_SEC) ;
|
|
|
|
|
|
|
|
|
|
|
|
START_TIMINGS
|
|
|
|
|
|
for (I ii =testdata.begin(); ii!=testdata.end(); )
|
|
|
|
|
|
{
|
|
|
|
|
|
int num = *ii;
|
|
|
|
|
|
++ii;
|
|
|
|
|
|
int den = *ii;
|
|
|
|
|
|
++ii;
|
|
|
|
|
|
CHECK (floor(double(num)/den) == floordiv(num,den));
|
|
|
|
|
|
}
|
|
|
|
|
|
DISPLAY_TIMINGS (Verification)
|
|
|
|
|
|
|
|
|
|
|
|
START_TIMINGS
|
|
|
|
|
|
for (I ii =testdata.begin(); ii!=testdata.end(); )
|
|
|
|
|
|
{
|
|
|
|
|
|
integerDiv (*ii++, *ii++);
|
|
|
|
|
|
}
|
|
|
|
|
|
DISPLAY_TIMINGS (Integer_div)
|
|
|
|
|
|
|
|
|
|
|
|
START_TIMINGS
|
|
|
|
|
|
for (I ii =testdata.begin(); ii!=testdata.end(); )
|
|
|
|
|
|
{
|
|
|
|
|
|
floor (double(*ii++) / *ii++);
|
|
|
|
|
|
}
|
|
|
|
|
|
DISPLAY_TIMINGS (double_floor)
|
|
|
|
|
|
|
|
|
|
|
|
START_TIMINGS
|
|
|
|
|
|
for (I ii =testdata.begin(); ii!=testdata.end(); )
|
|
|
|
|
|
{
|
|
|
|
|
|
floordiv (*ii++, *ii++);
|
|
|
|
|
|
}
|
|
|
|
|
|
DISPLAY_TIMINGS (floordiv_int)
|
|
|
|
|
|
|
|
|
|
|
|
START_TIMINGS
|
|
|
|
|
|
for (I ii =testdata.begin(); ii!=testdata.end(); )
|
|
|
|
|
|
{
|
|
|
|
|
|
floordiv (long(*ii++), long(*ii++));
|
|
|
|
|
|
}
|
|
|
|
|
|
DISPLAY_TIMINGS (floordiv_long)
|
|
|
|
|
|
|
|
|
|
|
|
START_TIMINGS
|
|
|
|
|
|
for (I ii =testdata.begin(); ii!=testdata.end(); )
|
|
|
|
|
|
{
|
|
|
|
|
|
floordiv (int64_t(*ii++), int64_t(*ii++));
|
|
|
|
|
|
}
|
|
|
|
|
|
DISPLAY_TIMINGS (floordiv_int64_t)
|
|
|
|
|
|
|
|
|
|
|
|
START_TIMINGS
|
|
|
|
|
|
for (I ii =testdata.begin(); ii!=testdata.end(); )
|
|
|
|
|
|
{
|
|
|
|
|
|
floordiv_alternate (*ii++, *ii++);
|
|
|
|
|
|
}
|
|
|
|
|
|
DISPLAY_TIMINGS (floordiv_long_alt)
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LAUNCHER (UtilFloordiv_test, "unit common");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}} // namespace util::test
|