Compare commits
2 commits
b11abb2d15
...
0320c31eb5
| Author | SHA1 | Date | |
|---|---|---|---|
| 0320c31eb5 | |||
| 4f8a8e8042 |
14 changed files with 181 additions and 548 deletions
|
|
@ -363,11 +363,11 @@ namespace util {
|
|||
|
||||
string showDecimal (double val) noexcept { return showFloatingPoint (val, PRECISION_DECIMAL<double>); }
|
||||
string showDecimal (float val) noexcept { return showFloatingPoint (val, PRECISION_DECIMAL<float>); }
|
||||
string showDecimal (lflp val) noexcept { return showFloatingPoint (val, PRECISION_DECIMAL<lflp>); }
|
||||
string showDecimal (lflo val) noexcept { return showFloatingPoint (val, PRECISION_DECIMAL<lflo>); }
|
||||
|
||||
string showComplete (double val) noexcept { return showFloatingPoint (val, PRECISION_COMPLETE<double>); }
|
||||
string showComplete (float val) noexcept { return showFloatingPoint (val, PRECISION_COMPLETE<float>); }
|
||||
string showComplete (lflp val) noexcept { return showFloatingPoint (val, PRECISION_COMPLETE<lflp>); }
|
||||
string showComplete (lflo val) noexcept { return showFloatingPoint (val, PRECISION_COMPLETE<lflo>); }
|
||||
|
||||
|
||||
string
|
||||
|
|
|
|||
|
|
@ -93,10 +93,10 @@ namespace util {
|
|||
|
||||
std::string showDecimal (double) noexcept;
|
||||
std::string showDecimal (float) noexcept;
|
||||
std::string showDecimal (lflp) noexcept;
|
||||
std::string showDecimal (lflo) noexcept;
|
||||
std::string showComplete (double)noexcept;
|
||||
std::string showComplete (float) noexcept;
|
||||
std::string showComplete (lflp) noexcept;
|
||||
std::string showComplete (lflo) noexcept;
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@ using llong = long long int;
|
|||
using ullong = unsigned long long int;
|
||||
using ushort = unsigned short int;
|
||||
|
||||
using lflp = long double;
|
||||
static_assert(10 <= sizeof(lflp));
|
||||
using lflo = long double;
|
||||
static_assert(10 <= sizeof(lflo));
|
||||
|
||||
const uint LIFE_AND_UNIVERSE_4EVER = 42;
|
||||
|
||||
|
|
|
|||
|
|
@ -456,12 +456,12 @@ namespace util {
|
|||
/** show maximum reproducible decimal representation */
|
||||
std::string showDecimal (double) noexcept;
|
||||
std::string showDecimal (float) noexcept;
|
||||
std::string showDecimal (lflp) noexcept;
|
||||
std::string showDecimal (lflo) noexcept;
|
||||
|
||||
/** show enough decimal digits to represent every distinct value */
|
||||
std::string showComplete (double) noexcept;
|
||||
std::string showComplete (float) noexcept;
|
||||
std::string showComplete (lflp) noexcept;
|
||||
std::string showComplete (lflo) noexcept;
|
||||
|
||||
std::string showSize (size_t) noexcept;
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ namespace lib {
|
|||
namespace par {
|
||||
namespace err = lumiera::error;
|
||||
|
||||
using std::abs;
|
||||
using util::_Fmt;
|
||||
using std::optional;
|
||||
|
||||
|
|
@ -80,7 +79,6 @@ namespace par {
|
|||
bool isValid() const;
|
||||
bool isFactor() const;
|
||||
bool isCyclic() const;
|
||||
bool isLimited() const;
|
||||
bool isLogarithmic() const;
|
||||
|
||||
/* ===== conforming operations ===== */
|
||||
|
|
@ -92,6 +90,16 @@ namespace par {
|
|||
VAL join (VAL const&, SRC const&, Scale<SRC> const&) const;
|
||||
VAL join (VAL const&, VAL const&) const;
|
||||
|
||||
/* ===== conversion helpers ===== */
|
||||
|
||||
template<typename TAR>
|
||||
auto asFactor (VAL const&) const;
|
||||
|
||||
template<typename TAR>
|
||||
auto baseScale (Metric targetMetric) const;
|
||||
|
||||
template<typename TAR>
|
||||
auto asLogarithm (Metric targetMetric, VAL const&) const;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -127,8 +135,7 @@ namespace par {
|
|||
and (not isCyclic()
|
||||
or (minVal and maxVal
|
||||
and *minVal < *maxVal
|
||||
and VAL(0) < cyclicLim
|
||||
and abs (*maxVal) <= cyclicLim)
|
||||
and VAL(0) < cyclicLim)
|
||||
)
|
||||
;
|
||||
}
|
||||
|
|
@ -149,14 +156,6 @@ namespace par {
|
|||
return VAL(0) != cyclicLim;
|
||||
}
|
||||
|
||||
template<typename VAL>
|
||||
inline bool
|
||||
Scale<VAL>::isLimited() const
|
||||
{
|
||||
return (maxVal or minVal)
|
||||
and not isCyclic();
|
||||
}
|
||||
|
||||
template<typename VAL>
|
||||
inline bool
|
||||
Scale<VAL>::isLogarithmic() const
|
||||
|
|
@ -192,7 +191,7 @@ namespace par {
|
|||
{
|
||||
REQUIRE (minVal and maxVal);
|
||||
REQUIRE (*minVal < *maxVal);
|
||||
if constexpr (std::is_floating_point_v<VAL>)
|
||||
if (std::is_floating_point_v<VAL>)
|
||||
if (not (std::abs (rawVal) < cyclicLim))
|
||||
throw err::Invalid {_Fmt{"Parameter value %4.2g beyond supported numeric precision "
|
||||
"for cyclic wrapping into [%1.2g...%1.2g[ "}
|
||||
|
|
@ -209,80 +208,6 @@ namespace par {
|
|||
}
|
||||
|
||||
|
||||
namespace { // logarithmic scale conversions...
|
||||
|
||||
/** transform a logarithmic value into an exponential factor */
|
||||
template<typename TAR, typename VAL>
|
||||
inline auto
|
||||
expFactor (Metric metric, VAL const& value)
|
||||
{
|
||||
using WorkType = CommonComputeType<VAL,TAR>;
|
||||
switch (metric)
|
||||
{
|
||||
case NAT: return std::exp (WorkType(value));
|
||||
case BIN: return std::exp2 (WorkType(value));
|
||||
case DEC: return std::pow (WorkType(10), WorkType(value/10.0));
|
||||
default:
|
||||
throw err::Logic{_Fmt{"Attempt to compute exponential "
|
||||
"from a non-logarithmic value with metric %d"}
|
||||
% metric};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** transform this value into a suitable logarithm for the target scale */
|
||||
template<typename TAR, typename VAL>
|
||||
inline auto
|
||||
asLogarithm (Metric targetMetric, VAL const& value)
|
||||
{
|
||||
if (isNeg (value))
|
||||
throw err::Invalid{_Fmt{"Attempt to take logarithm from %f < 0"}
|
||||
% value};
|
||||
using WorkType = CommonComputeType<VAL,TAR>;
|
||||
switch (targetMetric)
|
||||
{
|
||||
case NAT: return std::log (WorkType(value));
|
||||
case BIN: return std::log2 (WorkType(value));
|
||||
case DEC: return std::log10 (WorkType(value)) * 10;
|
||||
default:
|
||||
throw err::Logic{_Fmt{"Attempt to compute logarithm "
|
||||
"for a non-logarithmic metric %d"}
|
||||
% targetMetric};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** provide the adaptation factor from this logarithmic scale
|
||||
* to the given other logarithmic scale and target type \a VAL
|
||||
* @remarks
|
||||
* - use the logarithm conversion formula logb(x) ≡ logb(k)·logk(x)
|
||||
* - if target is in decibel, have to apply factor 10; asLogarithm() does that already
|
||||
* - if we are in decibel, log10 = dB /10; fold that factor in the logarithm of the base,
|
||||
* by using log(b)·x ≡ log(b^x) and rewrite that as b^x = exp(ln(b)·x)
|
||||
*/
|
||||
|
||||
template<typename TAR, typename VAL>
|
||||
inline auto
|
||||
baseScale (Metric targetMetric, Metric srcMetric)
|
||||
{
|
||||
using WorkType = CommonComputeType<VAL,TAR>;
|
||||
if (srcMetric == targetMetric)
|
||||
return WorkType(1);
|
||||
|
||||
auto srcBase = [&]{switch (srcMetric)
|
||||
{
|
||||
case BIN: return WorkType(2);
|
||||
case NAT: return std::exp (WorkType(1));
|
||||
case DEC: return std::exp (std::log (WorkType(10)) / 10);
|
||||
default:
|
||||
throw err::Logic{"Attempt to treat non-logarithmic scales as logarithms"};
|
||||
break;
|
||||
}};
|
||||
return asLogarithm<WorkType> (targetMetric, srcBase());
|
||||
}
|
||||
}//(End) log helpers
|
||||
|
||||
|
||||
/**
|
||||
* Join and combine an additional feed value with an anchor value.
|
||||
* @note actual joining operation is picked based on both scales and types involved.
|
||||
|
|
@ -301,7 +226,7 @@ namespace par {
|
|||
if (LIN == metric)
|
||||
{
|
||||
if (feedScale.isLogarithmic())
|
||||
assignConverted (res, value * expFactor<VAL> (feedScale.metric, srcFeed));
|
||||
assignConverted (res, value * feedScale.template asFactor<VAL> (srcFeed));
|
||||
else
|
||||
if (feedScale.isFactor())
|
||||
assignConverted (res, JoinT(value) * JoinT(srcFeed));
|
||||
|
|
@ -312,10 +237,10 @@ namespace par {
|
|||
if (this->isLogarithmic())
|
||||
{
|
||||
if (feedScale.isLogarithmic())
|
||||
assignConverted (res, value + baseScale<VAL,SRC> (metric,feedScale.metric) * srcFeed);
|
||||
assignConverted (res, value + feedScale.template baseScale<VAL>(metric) * srcFeed);
|
||||
else
|
||||
if (feedScale.isFactor())
|
||||
assignConverted (res, value + asLogarithm<VAL> (metric, srcFeed));
|
||||
assignConverted (res, value + feedScale.template asLogarithm<VAL> (metric, srcFeed));
|
||||
else
|
||||
throw err::Invalid {"adding a non-logarithmic data feed on top of a logarithmic base value is pointless."};
|
||||
}
|
||||
|
|
@ -339,5 +264,81 @@ namespace par {
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** transform a logarithmic value into an exponential factor */
|
||||
template<typename VAL>
|
||||
template<typename TAR>
|
||||
inline auto
|
||||
Scale<VAL>::asFactor (VAL const& value) const
|
||||
{
|
||||
using WorkType = CommonComputeType<VAL,TAR>;
|
||||
switch (metric)
|
||||
{
|
||||
case NAT: return std::exp (WorkType(value));
|
||||
case BIN: return std::exp2 (WorkType(value));
|
||||
case DEC: return std::pow (WorkType(10), WorkType(value/10.0));
|
||||
default:
|
||||
throw err::Logic{_Fmt{"Attempt to compute exponential "
|
||||
"from a non-logarithmic value with metric %d"}
|
||||
% metric};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** transform this value into a suitable logarithm for the target scale */
|
||||
template<typename VAL>
|
||||
template<typename TAR>
|
||||
inline auto
|
||||
Scale<VAL>::asLogarithm (Metric targetMetric, VAL const& value) const
|
||||
{
|
||||
if (isNeg (value))
|
||||
throw err::Invalid{_Fmt{"Attempt to take logarithm from %f < 0"}
|
||||
% value};
|
||||
using WorkType = CommonComputeType<VAL,TAR>;
|
||||
switch (targetMetric)
|
||||
{
|
||||
case NAT: return std::log (WorkType(value));
|
||||
case BIN: return std::logb (WorkType(value));
|
||||
case DEC: return std::log10 (WorkType(value)) * 10;
|
||||
default:
|
||||
throw err::Logic{_Fmt{"Attempt to compute logarithm "
|
||||
"for a non-logarithmic metric %d"}
|
||||
% targetMetric};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** provide the adaptation factor from this logarithmic scale
|
||||
* to the given other logarithmic scale and target type \a VAL
|
||||
* @remarks
|
||||
* - use the logarithm conversion formula logb(x) ≡ logb(k)·logk(x)
|
||||
* - if target is in decibel, have to apply factor 10; asLogarithm() does that already
|
||||
* - if we are in decibel, log10 = dB /10; fold that factor in the logarithm of the base,
|
||||
* by using log(b)·x ≡ log(b^x) and rewrite that as b^x = exp(ln(b)·x)
|
||||
*/
|
||||
|
||||
template<typename VAL>
|
||||
template<typename TAR>
|
||||
inline auto
|
||||
Scale<VAL>::baseScale (Metric targetMetric) const
|
||||
{
|
||||
using WorkType = CommonComputeType<VAL,TAR>;
|
||||
if (metric == targetMetric)
|
||||
return WorkType(1);
|
||||
|
||||
auto myBase = [&]{switch (metric)
|
||||
{
|
||||
case NAT: return std::exp(WorkType(1));
|
||||
case BIN: return WorkType(2);
|
||||
case DEC: return std::exp(std::log(WorkType(10)) / 10);
|
||||
default:
|
||||
throw err::Logic{"Attempt to treat non-logarithmic scales as logarithms"};
|
||||
break;
|
||||
}};
|
||||
return asLogarithm<WorkType> (targetMetric, myBase());
|
||||
}
|
||||
|
||||
|
||||
}} // namespace lib::par
|
||||
#endif /*LIB_PAR_SCALE_H*/
|
||||
|
|
|
|||
|
|
@ -154,13 +154,16 @@ _Pragma("GCC diagnostic pop")
|
|||
|
||||
template<typename T>
|
||||
concept number = integral<T> or floating_point<T>;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* the best-precision floating point type to carry out
|
||||
* a numeric operation to combine two values
|
||||
*/
|
||||
template<number V, number W>
|
||||
using CommonComputeType = std::conditional_t<integral<V> and integral<W>, double
|
||||
, common_type_t<V, W>>;
|
||||
|
||||
namespace {
|
||||
static_assert (64 <= std::numeric_limits<lflp>::digits
|
||||
,"long double type can not represent uint64_t exactly");
|
||||
|
||||
|
||||
/** @internal decision logic for combining numeric parameters */
|
||||
template<typename V, typename W>
|
||||
auto
|
||||
|
|
@ -177,27 +180,14 @@ _Pragma("GCC diagnostic pop")
|
|||
if constexpr (8 > sizeof(U))
|
||||
return std::type_identity<int64_t>{};
|
||||
else
|
||||
return std::type_identity<lflp>{};
|
||||
return std::type_identity<lflo>{};
|
||||
// no standard integral type can hold uint64_t's full range signed.
|
||||
// Expand to long double, which can hold 64bit without precision loss
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal logic to pick a suitable floating-point for intermediary computations */
|
||||
template<typename V, typename W>
|
||||
auto
|
||||
selectCommonComputeType()
|
||||
{
|
||||
if constexpr (is_integral_v<V> and is_integral_v<W>)
|
||||
{ // ensure integral precision is retained to the degree possible...
|
||||
if constexpr (8 > sizeof(V) and 8 > sizeof(W))
|
||||
return std::type_identity<double>{};
|
||||
else
|
||||
return std::type_identity<lflp>{};
|
||||
}
|
||||
else
|
||||
return std::type_identity<common_type_t<V,W>>{};
|
||||
}
|
||||
static_assert (64 <= std::numeric_limits<lflo>::digits
|
||||
,"long double type can not represent uint64_t exactly");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -208,17 +198,8 @@ _Pragma("GCC diagnostic pop")
|
|||
* - in the remaining problematic case(s), long double is used, as it can accommodate
|
||||
* the full 64bit value range without loss on platforms relevant for Lumiera.
|
||||
*/
|
||||
template<number V, number W>
|
||||
using NumberJoinType = typename decltype(selectNumberJoinType<V,W>())::type;
|
||||
|
||||
/**
|
||||
* best-precision floating point type to carry out
|
||||
* a numeric operation to transform and adapt value scales.
|
||||
* @note the result type is always some floating point,
|
||||
* since the goal is to use the exponential / logarithm family.
|
||||
*/
|
||||
template<number V, number W>
|
||||
using CommonComputeType = typename decltype(selectCommonComputeType<V,W>())::type;
|
||||
template<typename A, typename B>
|
||||
using NumberJoinType = typename decltype(selectNumberJoinType<A,B>())::type;
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -122,12 +122,12 @@ namespace util {
|
|||
u = 0!=u? u:1;
|
||||
auto [d,r] = util::iDiv (num, den);
|
||||
// round to smallest integer fraction, to shake off "number dust"
|
||||
lflp const ROUND_ULP = 1 + 1/(lflp(std::numeric_limits<int64_t>::max()) * 2);
|
||||
lflo const ROUND_ULP = 1 + 1/(lflo(std::numeric_limits<int64_t>::max()) * 2);
|
||||
|
||||
// construct approximation quantised to 1/u
|
||||
lflp frac = lflp(r) / den;
|
||||
lflo frac = lflo(r) / den;
|
||||
int64_t res = d*u + int64_t(frac*u * ROUND_ULP);
|
||||
ENSURE (abs (lflp(res)/u - rational_cast<lflp>(Rat{num,den})) <= 1.0/abs(u)
|
||||
ENSURE (abs (lflo(res)/u - rational_cast<lflo>(Rat{num,den})) <= 1.0/abs(u)
|
||||
,"Requantisation error exceeded num=%li / den=%li -> res=%li / quant=%li"
|
||||
, num, den, res, u);
|
||||
return res;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ return: 0
|
|||
END
|
||||
|
||||
|
||||
TEST "Parameter value scales" ParameterScale_test << END
|
||||
PLANNED "Parameter value scales" ParameterScale_test << END
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ namespace test {
|
|||
|
||||
verifyFloatTypes<float>();
|
||||
verifyFloatTypes<double>();
|
||||
verifyFloatTypes<lflp>();
|
||||
verifyFloatTypes<lflo>();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ namespace test{
|
|||
// using lumiera::error::LUMIERA_ERROR_LOGIC;
|
||||
using std::floating_point;
|
||||
|
||||
namespace {//Test helpers....
|
||||
namespace {//Test fixture....
|
||||
|
||||
template<typename NUM>
|
||||
constexpr NUM _MAX = std::numeric_limits<NUM>::max();
|
||||
|
|
@ -50,7 +50,7 @@ namespace test{
|
|||
template<floating_point FLO>
|
||||
constexpr FLO _EPSILON = std::numeric_limits<FLO>::epsilon();
|
||||
|
||||
}//(End)Test helpers
|
||||
}//(End)Test fixture
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,13 @@
|
|||
#include "lib/par/scale.hpp"
|
||||
#include "test/diagnostic-output.hpp"/////////////TODO
|
||||
|
||||
//#include <utility>
|
||||
//#include <string>
|
||||
//#include <vector>
|
||||
|
||||
//using std::string;
|
||||
//using std::vector;
|
||||
//using std::swap;
|
||||
using test::roughEQ;
|
||||
|
||||
|
||||
|
|
@ -28,18 +35,11 @@ namespace lib {
|
|||
namespace par {
|
||||
namespace test{
|
||||
|
||||
namespace {//Test helpers....
|
||||
// using lumiera::error::LUMIERA_ERROR_LOGIC;
|
||||
|
||||
namespace {//Test fixture....
|
||||
|
||||
template<typename NUM>
|
||||
constexpr NUM _MAX = std::numeric_limits<NUM>::max();
|
||||
|
||||
template<typename NUM>
|
||||
constexpr NUM _MIN = std::numeric_limits<NUM>::lowest();
|
||||
|
||||
template<floating_point FLO>
|
||||
constexpr FLO _EPSILON = std::numeric_limits<FLO>::epsilon();
|
||||
|
||||
}//(End)Test helpers
|
||||
}//(End)Test fixture
|
||||
|
||||
|
||||
|
||||
|
|
@ -50,13 +50,7 @@ namespace test{
|
|||
|
||||
|
||||
/**************************************************************************//**
|
||||
* @test demonstrate features and verify behaviour of value Scale definitions.
|
||||
* - a par::Scale is a descriptor record with some feature configuration settings
|
||||
* - some combination of setting marks specific scale features to be present
|
||||
* - values can be _conformed_ to comply with the scale constraints
|
||||
* - a Scale can be configured to maintain cyclic wrapping values
|
||||
* - values defined on different scales can be _joined_ (numerically combined)
|
||||
* - scales can be defined to be logarithmic, and work together with linear scales.
|
||||
* @test cover properties of generic parameter containers.
|
||||
*/
|
||||
class ParameterScale_test : public Test
|
||||
{
|
||||
|
|
@ -65,7 +59,6 @@ namespace test{
|
|||
run (Arg)
|
||||
{
|
||||
simpleUsage();
|
||||
verify_Predicate();
|
||||
verify_Conforming();
|
||||
verify_cyclicScale();
|
||||
verify_valueJoining();
|
||||
|
|
@ -86,51 +79,6 @@ namespace test{
|
|||
}
|
||||
|
||||
|
||||
/** @test verify the feature detection and descriptor predicates */
|
||||
void
|
||||
verify_Predicate()
|
||||
{
|
||||
Scale<double> scale;
|
||||
|
||||
CHECK (scale.isValid());
|
||||
CHECK (not scale.isCyclic());
|
||||
CHECK (not scale.isLimited());
|
||||
CHECK (not scale.isLogarithmic());
|
||||
|
||||
scale.minVal = -5;
|
||||
CHECK (scale.isValid());
|
||||
CHECK (not scale.isCyclic());
|
||||
CHECK ( scale.isLimited());
|
||||
|
||||
scale.cyclicLim = 10;
|
||||
CHECK (not scale.isValid());
|
||||
CHECK ( scale.isCyclic());
|
||||
CHECK (not scale.isLimited());
|
||||
|
||||
scale.maxVal = +5;
|
||||
CHECK ( scale.isValid());
|
||||
CHECK ( scale.isCyclic());
|
||||
CHECK (not scale.isLimited());
|
||||
|
||||
CHECK (not scale.isFactor());
|
||||
scale.neutral = 2;
|
||||
CHECK (not scale.isFactor());
|
||||
scale.neutral = 1;
|
||||
CHECK ( scale.isFactor());
|
||||
|
||||
CHECK (scale.metric == LIN);
|
||||
CHECK (not scale.isLogarithmic());
|
||||
scale.metric = NOM;
|
||||
CHECK (not scale.isLogarithmic());
|
||||
scale.metric = DEC;
|
||||
CHECK ( scale.isLogarithmic());
|
||||
scale.metric = BIN;
|
||||
CHECK ( scale.isLogarithmic());
|
||||
scale.metric = NAT;
|
||||
CHECK ( scale.isLogarithmic());
|
||||
}
|
||||
|
||||
|
||||
/** @test accommodate values to comply with the scale
|
||||
* - optionally a maximum and minimum can be enforced
|
||||
* - optionally the value can be cyclically wrapped
|
||||
|
|
@ -186,7 +134,7 @@ namespace test{
|
|||
CHECK ( 15 == angleScale.conform(65535));
|
||||
|
||||
|
||||
Scale<lflp> tinyScale = {.minVal=-lflp(1)/100, .maxVal=lflp(1)/100};
|
||||
Scale<lflo> tinyScale = {.minVal=-lflo(1)/100, .maxVal=lflo(1)/100};
|
||||
tinyScale.cyclicLim = util::limit_cyclicWrap(*tinyScale.maxVal - *tinyScale.minVal);
|
||||
CHECK (1e16 < tinyScale.cyclicLim);
|
||||
CHECK (tinyScale.isValid());
|
||||
|
|
@ -224,26 +172,24 @@ namespace test{
|
|||
* - applying a linear factor to a logarithmic scale is
|
||||
* transformed into an addition in the logarithmic domain
|
||||
* - adding a linear offset to a logarithmic scale is rejected
|
||||
* - extended precision scales handled using `lflp` (≙`long double`)
|
||||
* - this allows to retain full precision of 64bit integrals
|
||||
* @todo WIP 9/26 ✔ define ⟶ ✔ implement
|
||||
* @todo WIP 9/26 🔁 define ⟶ ✔ implement
|
||||
*/
|
||||
void
|
||||
verify_valueJoining()
|
||||
{
|
||||
Scale<ushort> scale = {.minVal = 2, .maxVal = 10};
|
||||
Scale<int64_t> lscale;
|
||||
Scale<int64_t> feedScale;
|
||||
|
||||
CHECK ( 5 == scale.join (2, int64_t(3), lscale)); // 2+3 ≡ 5 (all computations done as double)
|
||||
CHECK (10 == scale.join (5, int64_t(8), lscale)); // 5+8 ≡ 13 ⟼ capped to 10
|
||||
CHECK ( 5 == scale.join (2, int64_t(3), feedScale)); // 2+3 ≡ 5 (all computations done as double)
|
||||
CHECK (10 == scale.join (5, int64_t(8), feedScale)); // 5+8 ≡ 13 ⟼ capped to 10
|
||||
|
||||
lscale.neutral = 1;
|
||||
CHECK (lscale.isFactor());
|
||||
CHECK ( 6 == scale.join (2, int64_t(3), lscale)); // 2*3 ≡ 6
|
||||
CHECK ( 2 == scale.join (2, int64_t(-3),lscale)); // 2*-3 ≡ -6 ⟼ first conditioned to ushort domain, then capped to 2
|
||||
feedScale.neutral = 1;
|
||||
CHECK (feedScale.isFactor());
|
||||
CHECK ( 6 == scale.join (2, int64_t(3), feedScale)); // 2*3 ≡ 6
|
||||
CHECK ( 2 == scale.join (2, int64_t(-3),feedScale)); // 2*-3 ≡ -6 ⟼ first conditioned to ushort domain, then capped to 2
|
||||
|
||||
lscale.metric = DEC; // in dB
|
||||
CHECK ( 7 == scale.join (4, int64_t(3), lscale)); // 4 + 3dB ⟼ 4 * 1.995 ≡ 7.98 ⟼ truncated to 7
|
||||
feedScale.metric = DEC; // in dB
|
||||
CHECK ( 7 == scale.join (4, int64_t(3), feedScale)); // 4 + 3dB ⟼ 4 * 1.995 ≡ 7.98 ⟼ truncated to 7
|
||||
|
||||
Scale<short> sscale;
|
||||
Scale<uint64_t> uscale = {.neutral = 1};
|
||||
|
|
@ -256,94 +202,28 @@ namespace test{
|
|||
//
|
||||
Scale<float> fscale = {.metric = NAT};
|
||||
Scale<float> feed_dB = {.metric = DEC};
|
||||
CHECK (roughEQ (fscale.join (0, float(20), feed_dB) , log(100.0f) )); // dB ⟼ natural logarithm; note 20dB ≙ factor 10 * lg(100); input 20 divided by 10
|
||||
fscale.metric = BIN;
|
||||
CHECK (roughEQ (fscale.join (0, float(20), feed_dB) , log2(100.0f))); // dB ⟼ binary logarithm; (factor 1/10 on input is folded into the log factor)
|
||||
fscale.metric = DEC;
|
||||
CHECK (roughEQ (fscale.join (0, float(20), feed_dB) , 20.0f )); // dB ⟼ dB just passed-through and then added to value ≔ 0.0
|
||||
CHECK (roughEQ (fscale.join (0, float(20), feed_dB) , log(100.0f) )); // dB ⟼ natural logarithm; note 10dB ≙ factor 10 * lg(10) value divided / 10
|
||||
|
||||
fscale.metric = DEC;
|
||||
lscale.metric = BIN;
|
||||
CHECK (roughEQ (fscale.join (0, int64_t(-3), lscale), log10(1.0f/8) *10)); // binary log (given as int value) ⟼ dB
|
||||
lscale.metric = NAT;
|
||||
CHECK (roughEQ (fscale.join (0, int64_t(-3), lscale), log10(exp(-3))*10)); // natural log (input as int) ⟼ dB
|
||||
lscale.metric = DEC;
|
||||
CHECK (roughEQ (fscale.join (0, int64_t(-3), lscale), -3 )); // dB ⟼ dB just passed-through
|
||||
CHECK (roughEQ (fscale.join (0, float(20), feed_dB) , 20.0f )); // dB ⟼ dB just passed-through and then added to value ≔ 0.0
|
||||
|
||||
fscale.metric = BIN;
|
||||
lscale.metric = BIN;
|
||||
CHECK (roughEQ (fscale.join (0, int64_t(-3), lscale), -3 )); // lb ⟼ lb just passed-through
|
||||
lscale.metric = NAT;
|
||||
CHECK (roughEQ (fscale.join (0, int64_t(-3), lscale), log2 (exp(-3)) )); // natural log ⟼ binary log
|
||||
lscale.metric = DEC;
|
||||
CHECK (roughEQ (fscale.join (0, int64_t(-30),lscale), log2 (1.0/1000) )); // conversion factor: dB/10 ⟼ binary log
|
||||
feedScale.metric = BIN;
|
||||
CHECK (roughEQ (fscale.join (0, int64_t(-3), feedScale), log10(1.0f/8)*10)); // binary log (given as int value) ⟼ dB
|
||||
|
||||
fscale.metric = LIN;
|
||||
lscale.metric = BIN;
|
||||
CHECK (roughEQ (fscale.join (1, int64_t(-3), lscale), 1.0f/8 )); // binary log applied as factor to a linear scale
|
||||
lscale.metric = NAT;
|
||||
CHECK (roughEQ (fscale.join (1, int64_t(-1), lscale), 1.0f/exp(1))); // natural log applied as factor 1/e
|
||||
lscale.metric = DEC;
|
||||
CHECK (roughEQ (fscale.join (1, int64_t(-30),lscale), 1.0f/1000 )); // decibels applied as factor : -30 dB ≙ 10^-3
|
||||
CHECK (roughEQ (fscale.join (1, int64_t(-3), feedScale), 1.0f/8 )); // binary log applied as factor to a linear scale
|
||||
|
||||
fscale.metric = BIN;
|
||||
lscale.metric = LIN;
|
||||
lscale.neutral = 1;
|
||||
CHECK (lscale.isFactor());
|
||||
feedScale.metric = LIN;
|
||||
feedScale.neutral = 1;
|
||||
CHECK (feedScale.isFactor());
|
||||
CHECK (fscale.isLogarithmic());
|
||||
CHECK ( fscale.join (1, int64_t(8), lscale) == 1 + 3); // feed factor 8 ⟼ to binary logarithmic fscale (8 ≡ 2^3) and added there (exact)
|
||||
fscale.metric = NAT;
|
||||
CHECK (roughEQ (fscale.join (1, int64_t(8), lscale), 1 + logf(8))); // feed factor 8 ⟼ now applied to a natural log scale (and added to one, in float)
|
||||
fscale.metric = DEC;
|
||||
CHECK (roughEQ (fscale.join (1, int64_t(100),lscale), 1 + 20)); // feed factor 8 ⟼ now applied as offset in decibels
|
||||
CHECK (1 + 3 == fscale.join (1, int64_t(8), feedScale)); // feed factor 8 ⟼ to binary logarithmic fscale (8 ≡ 2^3) and added there
|
||||
|
||||
lscale.neutral = 0;
|
||||
CHECK (not lscale.isFactor());
|
||||
feedScale.neutral = 0;
|
||||
CHECK (not feedScale.isFactor());
|
||||
VERIFY_FAIL ("adding a non-logarithmic data feed on top of a logarithmic base value"
|
||||
, fscale.join (1, int64_t(8), lscale));
|
||||
|
||||
|
||||
//---verify a long-double target scale
|
||||
//
|
||||
Scale<lflp> megaScale = {.minVal = -10, .maxVal = +10}; // setup a cyclic scale using the long double domain
|
||||
megaScale.cyclicLim = util::limit_cyclicWrap<lflp>(20); // (cyclic wrap is handled by conform(); just another little twist)
|
||||
CHECK (megaScale.isCyclic());
|
||||
megaScale.metric = DEC;
|
||||
fscale.metric = LIN;
|
||||
fscale.neutral = 1;
|
||||
CHECK (fscale.isFactor());
|
||||
CHECK ( 5 == megaScale.join ( 5, 100.0f, fscale)); // input ⟼ decibels, then added to the base value, and finally wrapped ∈ [-10 ... 10[
|
||||
CHECK (-5 == megaScale.join (-5, 100.0f, fscale));
|
||||
CHECK ( 5 == megaScale.join (-5, 1000.0f, fscale)); // ...so here we get -5dB + 30dB
|
||||
|
||||
// now push that to the limits....
|
||||
CHECK (logb (1e18) < logb (_MAX<int64_t>)); // use the largest power of 10 representable in int64_t
|
||||
CHECK (logb (_MAX<int64_t>) < logb (megaScale.cyclicLim)); // ...which the (cyclic) target scale can still handle precisely!
|
||||
|
||||
lflp res1 = megaScale.join (-5, 1e18f, fscale); // log10 ⟼ 18, so we add -5dB + 180dB;
|
||||
CHECK (roughEQ (res1, -5)); // the cyclicWrap then computes 175 - (-10) ≡ 185 % 20 (≙5) + (minVal ≙ -10)
|
||||
|
||||
// but the computation is not exact...
|
||||
CHECK (0 != std::fmod (res1, 1));
|
||||
// yet the cause lies in the input already:
|
||||
lflp srcErr = lflp(1e18f) - pow (lflp(10), 18);
|
||||
CHECK (1e10 < fabs (srcErr)); // ... so the float input incurs a gigantic error margin
|
||||
|
||||
// however: use an exact input, and the result will be exact
|
||||
lscale.neutral = 1;
|
||||
CHECK (lscale.isFactor());
|
||||
CHECK (-5 == megaScale.join (-5, int64_t(1e18), lscale));
|
||||
lflp res2 = megaScale.join (-5, int64_t(1e18)+1, lscale);
|
||||
CHECK (-5 != res2); // even a tiny offset makes it through the computation
|
||||
CHECK (-16 > log10 (res2 -(-5))); // error is below the 16. decimal place (plausible, since log10 is computed)
|
||||
|
||||
// compare to target scale with lesser precision...
|
||||
Scale<double> doubleTargetScale = {.metric = DEC};
|
||||
Scale<uint64_t> longTargetScale = {.metric = DEC};
|
||||
CHECK (180 == doubleTargetScale.join (0, int64_t(1e18), lscale)); // uses double for internal log10 computation
|
||||
CHECK (180 == doubleTargetScale.join (0, int64_t(1e18)-10, lscale)); // offset chosen large enough to prevail in int64_t but not in double
|
||||
CHECK (180 == longTargetScale.join (0, int64_t(1e18), lscale)); // 64bit integral scales use long-double for log10 computation internally
|
||||
CHECK (179 == longTargetScale.join (0, int64_t(1e18)-10, lscale)); // ...and thus the offset survives the log10 and is truncated down on conversion
|
||||
, fscale.join (1, int64_t(8), feedScale));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -224,7 +224,7 @@ namespace test{
|
|||
|
||||
CHECK (format4Csv(double(1) / 3) == "0.333333333333333"_expect );
|
||||
CHECK (format4Csv(float(1) / 3) == "0.333333"_expect );
|
||||
CHECK (format4Csv(lflp(1) / 3) == "0.333333333333333333"_expect);
|
||||
CHECK (format4Csv(lflo(1) / 3) == "0.333333333333333333"_expect);
|
||||
CHECK (format4Csv(bool(1)) == "true"_expect );
|
||||
CHECK (format4Csv(bool(0)) == "false"_expect);
|
||||
CHECK (format4Csv("Starship-3") == "\"Starship-3\""_expect ); // 3rd test today ;-)
|
||||
|
|
|
|||
|
|
@ -92,9 +92,9 @@ namespace test {
|
|||
CHECK (a2.siz > 555);
|
||||
|
||||
// can use that memory without blowing up....
|
||||
auto doooh = new(a1.mem) lflp{std::numeric_limits<lflp>::max()};
|
||||
auto doooh = new(a1.mem) lflo{std::numeric_limits<lflo>::max()};
|
||||
*doooh /= 2;
|
||||
CHECK (2 == std::numeric_limits<lflp>::max() / *doooh);
|
||||
CHECK (2 == std::numeric_limits<lflo>::max() / *doooh);
|
||||
|
||||
allo.deallocate (a1);
|
||||
allo.deallocate (a2);
|
||||
|
|
|
|||
|
|
@ -85973,7 +85973,7 @@
|
|||
<linktarget COLOR="#c50711" DESTINATION="ID_621869035" ENDARROW="Default" ENDINCLINATION="108;0;" ID="Arrow_ID_191032855" SOURCE="ID_1491788669" STARTARROW="None" STARTINCLINATION="34;-37;"/>
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
<node CREATED="1789003479184" ID="ID_833220665" MODIFIED="1789003479184" TEXT="The two doors that actually close">
|
||||
<node CREATED="1789003479184" ID="ID_833220665" MODIFIED="1789003552060" TEXT="The two doors that actually close">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
|
|
@ -85985,7 +85985,7 @@
|
|||
<b>The persisted form</b>. The moment a session file records a parameter with a scale, the meaning of its qualifiers is frozen or needs migration. It's worth spending more thought on what a Scale looks like when written out than on what it looks like in memory.
|
||||
</li>
|
||||
<li>
|
||||
<b>Keeping Scale reducible to data</b>. You mention a possible connection to rules later. A rules system can only reason about a Scale if the Scale <em>is</em> a small tuple of facts (metric, bounds, cyclic flag, domain-set id, default) with a fixed interpreter, rather than a polymorphic object whose behaviour exists only as C++. That constraint costs you nothing today, since your qualifier-based design already satisfies it. It's just worth adopting as a deliberate rule so that a future <code><font color="#673a3a">conform()</font></code> override doing something clever doesn't quietly break it.
|
||||
<b>Keeping Scale reducible to data</b>. You mention a possible connection to rules later. A rules system can only reason about a Scale if the Scale <em>is</em>  a small tuple of facts (metric, bounds, cyclic flag, domain-set id, default) with a fixed interpreter, rather than a polymorphic object whose behaviour exists only as C++. That constraint costs you nothing today, since your qualifier-based design already satisfies it. It's just worth adopting as a deliberate rule so that a future <code>conform()</code>  override doing something clever doesn't quietly break it.
|
||||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
|
|
@ -86269,17 +86269,16 @@ class ScaleRegistry
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1789159365103" ID="ID_435108847" MODIFIED="1790094564624" TEXT="sollte dann wohl gleich eine generische Registry sein...">
|
||||
<node CREATED="1789159365103" ID="ID_435108847" MODIFIED="1789159397705" TEXT="sollte dann wohl gleich eine generische Registry sein...">
|
||||
<linktarget COLOR="#426aa5" DESTINATION="ID_435108847" ENDARROW="Default" ENDINCLINATION="28;-70;" ID="Arrow_ID_1818399541" SOURCE="ID_735608493" STARTARROW="None" STARTINCLINATION="-393;12;"/>
|
||||
<linktarget COLOR="#365ac0" DESTINATION="ID_435108847" ENDARROW="Default" ENDINCLINATION="-11;82;" ID="Arrow_ID_246372510" SOURCE="ID_438812693" STARTARROW="None" STARTINCLINATION="14;-8;"/>
|
||||
<node CREATED="1789159448086" ID="ID_1755995276" MODIFIED="1789159547368" TEXT="Feste Index-Tabelle + heap-allozierte Extents"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1789170321059" ID="ID_533778146" MODIFIED="1790094388582" TEXT="einfache / vorläufige Implementierung">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1789170321059" ID="ID_533778146" MODIFIED="1789170328666" TEXT="einfache / vorläufige Implementierung">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node CREATED="1789170329999" ID="ID_247689608" MODIFIED="1789170375860" TEXT="»vorläufig« insofern ich komplexe Themen ignorieren sollte (Nominal-Skalen, Quantisierung)">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
|
|
@ -87236,9 +87235,9 @@ Prop.1: dist%3 1 2 0 1 2 0
|
|||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1789171911830" ID="ID_944344547" MODIFIED="1790094358125" TEXT="join">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#338800" CREATED="1789171916490" FOLDED="true" ID="ID_920699877" MODIFIED="1790094384518" TEXT="einfacher Fall: gemeinsame Scale">
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1789171911830" ID="ID_944344547" MODIFIED="1789171915156" TEXT="join">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node COLOR="#338800" CREATED="1789171916490" ID="ID_920699877" MODIFIED="1789172001819" TEXT="einfacher Fall: gemeinsame Scale">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#338800" CREATED="1789171933617" ID="ID_284757000" MODIFIED="1789171970154" TEXT="isFactor definieren">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
|
|
@ -87252,7 +87251,7 @@ Prop.1: dist%3 1 2 0 1 2 0
|
|||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1789172002831" FOLDED="true" ID="ID_939833813" MODIFIED="1790094383113" TEXT="gemische Scales handhaben">
|
||||
<node COLOR="#338800" CREATED="1789172002831" ID="ID_939833813" MODIFIED="1789961933370" TEXT="gemische Scales handhaben">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#338800" CREATED="1789949153983" ID="ID_781783423" MODIFIED="1789949195612" TEXT="ushort-Scale mit Limits ⟵ kombiniert mit int64_t">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
|
|
@ -87264,49 +87263,16 @@ Prop.1: dist%3 1 2 0 1 2 0
|
|||
<arrowlink COLOR="#28b55c" DESTINATION="ID_1223578931" ENDARROW="Default" ENDINCLINATION="-139;1297;" ID="Arrow_ID_225645373" STARTARROW="None" STARTINCLINATION="111;6;"/>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1789961742643" FOLDED="true" ID="ID_949990390" MODIFIED="1790094370986" TEXT="Verbindung verschiedener log-Scales">
|
||||
<node COLOR="#338800" CREATED="1789961742643" ID="ID_949990390" MODIFIED="1789961760832" TEXT="Verbindung verschiedener log-Scales">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#435e98" CREATED="1789961765581" ID="ID_1536983378" MODIFIED="1789961783683" TEXT="Umwandlung linear ⟷ log">
|
||||
<node CREATED="1790021597423" ID="ID_5025438" MODIFIED="1790021610941" TEXT="die Konvertierungs-Funktionen sind strukturell eigenartig">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1790021612645" ID="ID_1614531537" MODIFIED="1790021624855" TEXT="sie hängen eigentlich zwischen zwei Scales"/>
|
||||
<node CREATED="1790021853785" ID="ID_1972131978" LINK="https://math.stackexchange.com/questions/14133/clarify-why-all-logarithms-differ-by-a-constant" MODIFIED="1790022525577" TEXT="sie reflektieren die (verwirrende) Struktur der Logarithmen-Konvertierung">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...ich muß die Formeln jedes mal wieder nachschlagen, bzw mir herleiten, weil diese Formeln so eigenartig <i>über Kreuz</i> aufgebaut sind:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
<font color="#79320b" face="Monospaced">log</font><font color="#79320b" face="Monospaced" size="2"><i>b</i></font><font color="#79320b" face="Monospaced">(x) ≡ log</font><font color="#79320b" face="Monospaced" size="2"><i>k</i></font><font color="#79320b" face="Monospaced">(x)/log</font><font color="#79320b" face="Monospaced" size="2"><i>k</i></font><font color="#79320b" face="Monospaced">(b)</font>
|
||||
</li>
|
||||
<li>
|
||||
<font color="#79320b" face="Monospaced">log</font><font color="#79320b" face="Monospaced" size="2"><i>b</i></font><font color="#79320b" face="Monospaced">(x) ≡ log</font><font color="#79320b" face="Monospaced" size="2"><i>b</i></font><font color="#79320b" face="Monospaced">(k)·log</font><font color="#79320b" face="Monospaced" size="2"><i>k</i></font><font color="#79320b" face="Monospaced">(x)</font>
|
||||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1790021537463" ID="ID_1193038289" MODIFIED="1790022831555" TEXT="Funktion Scale<VAL>::asLogarithm ist zudem gar nicht von der Quell-Skala abhängig"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1790022911017" ID="ID_761833274" MODIFIED="1790024210457" TEXT="Code-Struktur / Design-Frage : als freie Funktionen?">
|
||||
<node CREATED="1790022936425" ID="ID_1681792313" MODIFIED="1790023005221" TEXT="als Member-Funktionen spart man sich 2 Parameter in zwei Fällen">
|
||||
<icon BUILTIN="smiley-oh"/>
|
||||
</node>
|
||||
<node CREATED="1790022966402" ID="ID_1905759427" MODIFIED="1790022996702" TEXT="allerdings müssen sie dann auf das Scale-API, und man ruft sie mit "template"-Qualifier auf">
|
||||
<icon BUILTIN="smiley-neutral"/>
|
||||
</node>
|
||||
<node COLOR="#135457" CREATED="1790023008316" ID="ID_1604048781" MODIFIED="1790024202124" TEXT="also: in den sauren Apfel beißen — isbesserso">
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1789961765581" ID="ID_1536983378" MODIFIED="1789961783683" TEXT="Umwandlung linear ⟷ log"/>
|
||||
<node COLOR="#435e98" CREATED="1789961784810" ID="ID_245445484" MODIFIED="1789961910375" TEXT="Basis-Konvertierung logarithmischer werte"/>
|
||||
<node COLOR="#435e98" CREATED="1789961796062" ID="ID_1145409092" MODIFIED="1789961910354" TEXT="spezieller Twist: in Decibels steckt ein Faktor 10">
|
||||
<node CREATED="1789961817086" ID="ID_909916918" MODIFIED="1789961906542" TEXT="wenn als Input verwendet, muß der rausdividiert werden">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
...und dieses Herausdividieren falte ich trickreich in den log-Basis-Konvertierungsfaktor.
|
||||
|
|
@ -87315,80 +87281,13 @@ Prop.1: dist%3 1 2 0 1 2 0
|
|||
Überraschung: die Logarithmen-Matematik funktioniert ... aber das dumme Mensch braucht endlos um zu kapieren daß die Beispielwerte stimmen
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1789961831540" ID="ID_104579195" MODIFIED="1789961843094" TEXT="aber auf der Ergebnis-Seite muß er aufgeschlagen werden"/>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1789961912393" ID="ID_1778190029" MODIFIED="1789961925432" TEXT="linearer Offset auf Logarithmus wird verweigert"/>
|
||||
<node CREATED="1790029014421" ID="ID_1208653097" MODIFIED="1790036739810" TEXT="Logarithmus-Berechnung in eine long-double-Scale">
|
||||
<node CREATED="1790036139410" ID="ID_790857236" MODIFIED="1790036256247" TEXT="hier geht es darum, die möglichst präzise Berechnung zu prüfen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
die Berechnungen <i>sind</i> ungenau, mit floating-point und transzendentalen Funktionen. Aber die vorhandene Daten-Genauigkeit sollte ausgeschöpft werden, ohne jetzt gleich alles mit long double rechnen zu müssen
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1790036164854" ID="ID_229924653" MODIFIED="1790094127028" TEXT="im Besonderen die Bestimmung des Arbeits-Datentyps">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#400f69" CREATED="1790037266068" ID="ID_1040329780" MODIFIED="1790094099158" TEXT="tatsächlich: die Wahl des Rechen-Datentyps ist zu einfach implementiert">
|
||||
<linktarget COLOR="#5425ca" DESTINATION="ID_1040329780" ENDARROW="Default" ENDINCLINATION="805;29;" ID="Arrow_ID_1796905346" SOURCE="ID_31887994" STARTARROW="None" STARTINCLINATION="478;26;"/>
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1790037396226" HGAP="28" ID="ID_341439483" MODIFIED="1790094090617" TEXT="wir gehen von integral ⟶ double" VSHIFT="-7">
|
||||
<icon BUILTIN="broken-line"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1790090085802" ID="ID_222503371" MODIFIED="1790094103279" TEXT="auch hier umstellen auf eine explizit ausformulierte Fall-Logik">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
nicht mehr versuchen, alles in einen Typ-Ausdruck zu packen; stattdessen hier auch die Technik mit einer Constexpr-Funktion, die einen type_identity-Record liefert
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#5928b5" CREATED="1789961961491" ID="ID_219252546" MODIFIED="1790036535745" TEXT="und ja: wer testet, der findet">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<ul>
|
||||
<li>
|
||||
Type-promotion-Bug in der Anwendung der pow()-Funktion
|
||||
</li>
|
||||
<li>
|
||||
weiterer Type-promotion-Error in der baseScale-Funktion
|
||||
</li>
|
||||
<li>
|
||||
logb() liefert nur den exponenten, log2() den 2-er-Logarithmus
|
||||
</li>
|
||||
<li>
|
||||
in conform steckt auch noch ein statischer Fehler: std::abs funktioniert nicht auf <i>unsigned</i>
|
||||
</li>
|
||||
<li>
|
||||
das <i>Wiederverwenden</i> der asLogarithm()-Funktion macht deutlich, daß diese einen unnötigen Typ-Constraint auf den VAL-Parameter der Ausgangs-Scale erzwingt
|
||||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<arrowlink COLOR="#3f3ba8" DESTINATION="ID_1207373600" ENDARROW="Default" ENDINCLINATION="534;0;" ID="Arrow_ID_625720992" STARTARROW="None" STARTINCLINATION="16;533;"/>
|
||||
<font ITALIC="true" NAME="SansSerif" SIZE="12"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1790094428926" ID="ID_1432141408" MODIFIED="1790094455904" TEXT="muß nun die Scale (Descriptor) sinnvoll in die Parameter-Implementierung integrieren">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1790094459596" ID="ID_184861465" MODIFIED="1790094482634" TEXT="brauche dazu eine Registrierung und Scale-IDs">
|
||||
<icon BUILTIN="forward"/>
|
||||
<node CREATED="1790094501963" ID="ID_438812693" MODIFIED="1790094572153" TEXT="und diese Registry sollte generisch angelegt sein">
|
||||
<arrowlink COLOR="#365ac0" DESTINATION="ID_435108847" ENDARROW="Default" ENDINCLINATION="-11;82;" ID="Arrow_ID_246372510" STARTARROW="None" STARTINCLINATION="14;-8;"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
@ -87461,8 +87360,8 @@ Prop.1: dist%3 1 2 0 1 2 0
|
|||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1788896830329" ID="ID_355463973" MODIFIED="1790094404823" TEXT="Scale-Konfiguration ermöglichen">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1788896830329" ID="ID_355463973" MODIFIED="1788896840672" TEXT="Scale-Konfiguration ermöglichen">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1788654131472" ID="ID_1807734347" MODIFIED="1788654185033" TEXT="Prototyp-Builder">
|
||||
|
|
@ -87539,7 +87438,7 @@ Prop.1: dist%3 1 2 0 1 2 0
|
|||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1788203400185" ID="ID_900611719" MODIFIED="1788307794257" TEXT="Builder-Notation schaffen">
|
||||
<icon BUILTIN="full-2"/>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1788203422590" ID="ID_1249325546" MODIFIED="1788570267353" TEXT="Value-Konversionen einbinden">
|
||||
<node COLOR="#435e98" CREATED="1788203422590" ID="ID_1249325546" MODIFIED="1788570267353" TEXT="Valure-Konversionen einbinden">
|
||||
<icon BUILTIN="full-3"/>
|
||||
<node COLOR="#338800" CREATED="1788313016806" ID="ID_1966722816" MODIFIED="1788403892705" TEXT="generisch per Indirektion">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
|
|
@ -87595,8 +87494,8 @@ Prop.1: dist%3 1 2 0 1 2 0
|
|||
<icon BUILTIN="hourglass"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1789159639409" ID="ID_654373559" MODIFIED="1790094342453" TEXT="Scale-Eigenschaften abstecken per ParameterScale_test">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1789159639409" ID="ID_654373559" MODIFIED="1789607860036" TEXT="Scale-Eigenschaften abstecken per ParameterScale_test">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node CREATED="1789159687318" ID="ID_1480074646" MODIFIED="1789160197623" TEXT="Hier nur rein die Scale-Descriptoren und das intendierte Verhalten">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
|
|
@ -87624,11 +87523,6 @@ Prop.1: dist%3 1 2 0 1 2 0
|
|||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1790094258921" ID="ID_1942061887" MODIFIED="1790094261651" TEXT="verify_Predicate">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1790094263246" ID="ID_1388987426" MODIFIED="1790094274333" TEXT="demonstriert die wichtigsten Informations-Funktionen"/>
|
||||
<node COLOR="#310088" CREATED="1790094276841" ID="ID_783774183" MODIFIED="1790094312786" TEXT="(isValid() wird i.d.R. mit dem jeweilgen Feature zusammen abgedeckt)"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1789607293094" ID="ID_734632281" MODIFIED="1789607296849" TEXT="verify_Conforming">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1789607298013" ID="ID_452068382" MODIFIED="1789607555871" TEXT="im Grunde offensichtlich und redundant">
|
||||
|
|
@ -87664,131 +87558,8 @@ Prop.1: dist%3 1 2 0 1 2 0
|
|||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1789675604211" ID="ID_201071963" MODIFIED="1790094240877" TEXT="verify_valueJoining">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#338800" CREATED="1790015115678" ID="ID_1510723485" MODIFIED="1790015142255" TEXT="Schritt-1 : teste Typ-Konvertierung und Zusammenspiel mit conform()">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1790015143816" ID="ID_1173177816" MODIFIED="1790015164942" TEXT="Schritt-2 : kläre und repariere das noch bestehende signed/unsigned-Problem">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1790015165677" ID="ID_1207373600" MODIFIED="1790094237018" TEXT="Schritt-2 : Pfadabdeckung der Logarithmus-Skalen-Behandlung">
|
||||
<linktarget COLOR="#3f3ba8" DESTINATION="ID_1207373600" ENDARROW="Default" ENDINCLINATION="534;0;" ID="Arrow_ID_625720992" SOURCE="ID_219252546" STARTARROW="None" STARTINCLINATION="16;533;"/>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#8c0157" CREATED="1790024320509" HGAP="56" ID="ID_1433168831" MODIFIED="1790028991933" TEXT="lästig aber sinnvoll..." VSHIFT="21">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
jaja ... oft weiß man nicht ob es um "overengieering" geht, oder man selber einfach <i>faul</i> ist
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="smiley-oh"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1790028975682" FOLDED="true" HGAP="66" ID="ID_228688702" LINK="#ID_1208653097" MODIFIED="1790094232863" TEXT="auch noch einen log-double-Fall" VSHIFT="-1">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#435e98" CREATED="1790036164854" ID="ID_585649034" MODIFIED="1790094228089" TEXT="Augenmerk auf Arbeits-Datentyp legen">
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
<node CREATED="1790036260115" ID="ID_1393622284" MODIFIED="1790036281875" TEXT="führe hier als »gimmick« einen zyklische long-double-Skala ein">
|
||||
<node CREATED="1790036283183" ID="ID_181132589" MODIFIED="1790036293637" TEXT="damit könnte ich exakte kleine Werte bekommen"/>
|
||||
<node CREATED="1790036295430" ID="ID_803016212" MODIFIED="1790036306537" TEXT="und somit Rechenfehler dramatisch sichtbar machen"/>
|
||||
<node CREATED="1790036308659" ID="ID_1027526075" MODIFIED="1790036324753" TEXT="(und außerdem bestätigt das nochmal die Integration von conform())">
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1790036331633" ID="ID_926231651" MODIFIED="1790036487239" TEXT="Ha! Compile-Fehler">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
woot?  kann keinen std::abs berechnen von .... uint64_t  ??!
|
||||
</p>
|
||||
<p>
|
||||
"der mutt dat doch checken!"
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="broken-line"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#5e0f69" CREATED="1790036344862" ID="ID_1357077453" MODIFIED="1790037322238" TEXT="in conform() muß der Genauigkeits-Test zur compile-Zeit geguarded werden">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Tatsächlich ist der ganze Zweig mit dem Genauigkeits-Limit nur für floating-point-Typen notwendig; und diesen Branch-Guard kann man tatsächlich schon zur compile-time machen!
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#b7d8bb" COLOR="#338800" CREATED="1790036598900" ID="ID_246190994" MODIFIED="1790094211855" TEXT="ein echter Logarithmus ist am »intereessantesten«">
|
||||
<icon BUILTIN="idea"/>
|
||||
<node CREATED="1790036619370" ID="ID_913914685" MODIFIED="1790036638956">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
also nehme ich einen <b>linearen </b>Input
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1790036640983" ID="ID_1799300764" MODIFIED="1790036674383" TEXT="und wende den als Faktor auf eine Decibel-Skala an">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
damit's raucht!
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1790036690621" ID="ID_296790938" MODIFIED="1790036696747" TEXT="teste erst mal mit float-Input">
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1790036837717" ID="ID_918464928" MODIFIED="1790036869516" TEXT="verblüffend: mit kleinem Input, zB. 1000 ist das Ergebnis exakt">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
<node CREATED="1790036877098" ID="ID_1895824050" MODIFIED="1790036888026" TEXT="im Debugger sieht man aber ganz hinten schon die Rundungsfehler"/>
|
||||
<node CREATED="1790036889038" ID="ID_1642131477" MODIFIED="1790036914456" TEXT="nur das fmod in der Cyclic-Scale schluckt wohl die Subnormals">
|
||||
<icon BUILTIN="help"/>
|
||||
</node>
|
||||
<node CREATED="1790036918375" ID="ID_873113976" MODIFIED="1790036933655" TEXT="mit einem sehr großen Input wird der Fehler sehr deutlich">
|
||||
<node CREATED="1790036950358" ID="ID_1610030443" MODIFIED="1790036982693" TEXT="verwende einen Input von 10^18">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
das ist die größtmögliche 10-er-Potenz, die noch in 63bit reinpaßt
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1790037016669" ID="ID_1010388251" MODIFIED="1790037055912" TEXT="dann ist der Rechenfehler am Ende ≈ 10^10"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1790037065135" ID="ID_719693034" MODIFIED="1790037072092" TEXT="nehme dann int64_t-Input">
|
||||
<node COLOR="#338800" CREATED="1790037078616" ID="ID_1172597143" MODIFIED="1790037090915" TEXT="nun läuft selbst diese extreme Berechnung exakt">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node CREATED="1790037118015" ID="ID_886617373" MODIFIED="1790037148321" TEXT="bekomme nun 10^18 + 1 noch als abweichendes Signal durch die Berechnung"/>
|
||||
<node CREATED="1790037158306" ID="ID_819609666" MODIFIED="1790037170188" TEXT="und der Fehler ist < 10^16"/>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1790037172872" ID="ID_1473906602" MODIFIED="1790037181400" TEXT="klingt plausibel">
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1790037201845" ID="ID_1001721326" MODIFIED="1790037216271" TEXT="Gegencheck: ungenauere Target-Scale">
|
||||
<node CREATED="1790037220688" ID="ID_1408762592" MODIFIED="1790037236453" TEXT="double ⟹ kann diesen Fehler wie erwartet nicht »fangen«"/>
|
||||
<node COLOR="#435e98" CREATED="1790037238039" ID="ID_31887994" MODIFIED="1790094163676" TEXT="uint64_t ⟹ auch nicht ⟵ das ist nicht plausibel">
|
||||
<arrowlink COLOR="#5425ca" DESTINATION="ID_1040329780" ENDARROW="Default" ENDINCLINATION="805;29;" ID="Arrow_ID_1796905346" STARTARROW="None" STARTINCLINATION="478;26;"/>
|
||||
<icon BUILTIN="broken-line"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1790094336075" ID="ID_814063222" MODIFIED="1790094337810" TEXT="verify_NominalScale">
|
||||
<icon BUILTIN="hourglass"/>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1789675604211" ID="ID_201071963" MODIFIED="1789676070358" TEXT="verify_valueJoining">
|
||||
<icon BUILTIN="pencil"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
|
|||
Loading…
Reference in a new issue