Compare commits
No commits in common. "0320c31eb56aad60bf6768a1e2bc6fd22fd0ab00" and "620ca918c36319e52b1fb9b040a1c737ac206363" have entirely different histories.
0320c31eb5
...
620ca918c3
16 changed files with 154 additions and 881 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 (lflo val) noexcept { return showFloatingPoint (val, PRECISION_DECIMAL<lflo>); }
|
||||
string showDecimal (f128 val) noexcept { return showFloatingPoint (val, PRECISION_DECIMAL<f128>); }
|
||||
|
||||
string showComplete (double val) noexcept { return showFloatingPoint (val, PRECISION_COMPLETE<double>); }
|
||||
string showComplete (float val) noexcept { return showFloatingPoint (val, PRECISION_COMPLETE<float>); }
|
||||
string showComplete (lflo val) noexcept { return showFloatingPoint (val, PRECISION_COMPLETE<lflo>); }
|
||||
string showComplete (f128 val) noexcept { return showFloatingPoint (val, PRECISION_COMPLETE<f128>); }
|
||||
|
||||
|
||||
string
|
||||
|
|
|
|||
|
|
@ -93,10 +93,10 @@ namespace util {
|
|||
|
||||
std::string showDecimal (double) noexcept;
|
||||
std::string showDecimal (float) noexcept;
|
||||
std::string showDecimal (lflo) noexcept;
|
||||
std::string showDecimal (f128) noexcept;
|
||||
std::string showComplete (double)noexcept;
|
||||
std::string showComplete (float) noexcept;
|
||||
std::string showComplete (lflo) noexcept;
|
||||
std::string showComplete (f128) noexcept;
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@ using llong = long long int;
|
|||
using ullong = unsigned long long int;
|
||||
using ushort = unsigned short int;
|
||||
|
||||
using lflo = long double;
|
||||
static_assert(10 <= sizeof(lflo));
|
||||
using f128 = long double;
|
||||
static_assert(10 <= sizeof(f128));
|
||||
|
||||
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 (lflo) noexcept;
|
||||
std::string showDecimal (f128) noexcept;
|
||||
|
||||
/** show enough decimal digits to represent every distinct value */
|
||||
std::string showComplete (double) noexcept;
|
||||
std::string showComplete (float) noexcept;
|
||||
std::string showComplete (lflo) noexcept;
|
||||
std::string showComplete (f128) noexcept;
|
||||
|
||||
std::string showSize (size_t) noexcept;
|
||||
|
||||
|
|
|
|||
|
|
@ -35,14 +35,24 @@
|
|||
|
||||
|
||||
#include "lib/par/spec.hpp"
|
||||
#include "lib/par/provision.hpp"
|
||||
#include "lib/meta/typelist.hpp"
|
||||
#include "lib/meta/generator.hpp"
|
||||
#include "lib/par/provision.hpp"
|
||||
#include "lib/meta/trait.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
#include <concepts>
|
||||
#include <limits>
|
||||
|
||||
|
||||
namespace lib {
|
||||
namespace par {
|
||||
|
||||
using util::isNeg;
|
||||
using std::same_as;
|
||||
using std::floating_point;
|
||||
using std::numeric_limits;
|
||||
|
||||
|
||||
/* ===== Type Handler Interface for generic parameter value access ===== */
|
||||
|
||||
|
|
|
|||
|
|
@ -36,13 +36,13 @@
|
|||
|
||||
|
||||
#include "lib/par/domain.hpp"
|
||||
#include "lib/par/type-handler.hpp"
|
||||
#include "lib/meta/generator.hpp"
|
||||
|
||||
|
||||
namespace lib {
|
||||
namespace par {
|
||||
|
||||
|
||||
// GCC > 13 warns at class definition when a new overload shadows an inherited virtual function.
|
||||
// While theoretically correct, in practice any call will be dispatched through the base interface,
|
||||
// which in turn is also generated by metaprogramming from a type list.
|
||||
|
|
@ -78,10 +78,103 @@ _Pragma("GCC diagnostic ignored \"-Woverloaded-virtual\"")
|
|||
};
|
||||
|
||||
|
||||
/* ===== type conversion details ===== */
|
||||
|
||||
/** Constraint: type \a SUB can not represent the full domain of type \a BAS
|
||||
* @todo implicitly also implements a limitation to »numeric« types,
|
||||
* due to the use of std::numeric_limits
|
||||
*/
|
||||
template<typename SUB, typename BAS>
|
||||
concept sub_domain = std::signed_integral<SUB> != std::signed_integral<BAS>
|
||||
or std::numeric_limits<SUB>::max() < std::numeric_limits<BAS>::max()
|
||||
or std::numeric_limits<SUB>::lowest() > std::numeric_limits<BAS>::lowest()
|
||||
;
|
||||
|
||||
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wsign-compare\"")
|
||||
// the following functions are specifically crafted to work around
|
||||
// the ambiguities caused by automatic signed-to-unsigned promotion;
|
||||
// furthermore, the automatic promotion allows to perform the comparison.
|
||||
|
||||
template<typename X, typename Y>
|
||||
inline constexpr bool
|
||||
isLower_safe (X const& x, Y const& y)
|
||||
{
|
||||
return isNeg(x) == isNeg(y)? x < y
|
||||
: isNeg(x);
|
||||
}
|
||||
|
||||
template<typename X, typename Y>
|
||||
inline constexpr bool
|
||||
isLarger_safe (X const& x, Y const& y)
|
||||
{
|
||||
return isNeg(x) == isNeg(y)? x > y
|
||||
: isNeg(y);
|
||||
}
|
||||
_Pragma("GCC diagnostic pop")
|
||||
|
||||
|
||||
/** generic helper to conform into a common value domain
|
||||
* @tparam SUB the implied target value domain
|
||||
* @tparam BAS source data type
|
||||
* @return a value in source data type,
|
||||
* yet conformed into the target data range
|
||||
*/
|
||||
template<typename SUB, typename BAS>
|
||||
inline constexpr BAS
|
||||
preClamp (BAS const& value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
/** special case: clamp the source value into the target value domain.
|
||||
* @remark tricky due to automatic conversions between signed/unsigned */
|
||||
template<typename SUB, typename BAS> requires (sub_domain<SUB,BAS>
|
||||
and not same_as<SUB,bool>)
|
||||
inline constexpr BAS
|
||||
preClamp (BAS const& rawVal)
|
||||
{
|
||||
static_assert (std::is_constructible_v<BAS,SUB const&>
|
||||
,"Value domains must overlap at least partially "
|
||||
"and values must be cross-constructible within overlap");
|
||||
|
||||
auto upperBound = numeric_limits<SUB>::max();
|
||||
auto lowerBound = numeric_limits<SUB>::lowest();
|
||||
|
||||
return isLarger_safe(rawVal, upperBound)? BAS(upperBound)
|
||||
: isLower_safe (rawVal, lowerBound)? BAS(lowerBound)
|
||||
: rawVal;
|
||||
}
|
||||
|
||||
/** special case: trigger a bool at the 0.5 level */
|
||||
template<same_as<bool> B, floating_point F>
|
||||
inline constexpr F
|
||||
preClamp (F const& rawVal)
|
||||
{
|
||||
return 0.5 < rawVal? F{1} : F{0};
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ===== type conversion virtual dispatch ===== */
|
||||
template<typename V, typename X>
|
||||
inline void
|
||||
assignConverted (V& targetVal, X const& srcVal)
|
||||
{
|
||||
if constexpr (std::is_assignable_v<V&, X const&>)
|
||||
{
|
||||
targetVal = preClamp<V> (srcVal);
|
||||
}
|
||||
else
|
||||
if constexpr (std::is_constructible_v<V, X const&>)
|
||||
{
|
||||
targetVal.~U();
|
||||
new(&targetVal) V (preClamp<V> (srcVal));
|
||||
}
|
||||
else
|
||||
static_assert (!sizeof(X), "this type conversion is not supported");
|
||||
}
|
||||
|
||||
|
||||
template<typename VAL, class IFA>
|
||||
template<typename X, class PAR>
|
||||
|
|
|
|||
|
|
@ -28,21 +28,15 @@
|
|||
#define LIB_PAR_SCALE_H
|
||||
|
||||
|
||||
#include "lib/error.hpp"
|
||||
#include "lib/par/domain.hpp"
|
||||
#include "lib/par/type-handler.hpp"
|
||||
#include "lib/util-quant.hpp"
|
||||
#include "lib/format-string.hpp"
|
||||
//#include "lib/util.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
#include <optional>
|
||||
|
||||
|
||||
namespace lib {
|
||||
namespace par {
|
||||
namespace err = lumiera::error;
|
||||
|
||||
using util::_Fmt;
|
||||
using std::optional;
|
||||
|
||||
|
||||
|
|
@ -72,14 +66,12 @@ namespace par {
|
|||
optional<VAL> neutral{};
|
||||
optional<VAL> defVal{};
|
||||
/////////////////////////////OOO »Sentinels« and nominal scales?
|
||||
VAL cyclicLim =0;
|
||||
bool cyclic{false};
|
||||
|
||||
/* ===== information functions ===== */
|
||||
|
||||
bool isValid() const;
|
||||
bool isFactor() const;
|
||||
bool isCyclic() const;
|
||||
bool isLogarithmic() const;
|
||||
|
||||
/* ===== conforming operations ===== */
|
||||
|
||||
|
|
@ -89,17 +81,6 @@ namespace par {
|
|||
template<typename SRC>
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -132,10 +113,8 @@ namespace par {
|
|||
and (not minVal or *minVal <= *defVal)
|
||||
)
|
||||
)
|
||||
and (not isCyclic()
|
||||
or (minVal and maxVal
|
||||
and *minVal < *maxVal
|
||||
and VAL(0) < cyclicLim)
|
||||
and (not cyclic
|
||||
or (minVal and maxVal and *minVal < *maxVal)
|
||||
)
|
||||
;
|
||||
}
|
||||
|
|
@ -149,22 +128,6 @@ namespace par {
|
|||
and *neutral == VAL(1);
|
||||
}
|
||||
|
||||
template<typename VAL>
|
||||
inline bool
|
||||
Scale<VAL>::isCyclic() const
|
||||
{
|
||||
return VAL(0) != cyclicLim;
|
||||
}
|
||||
|
||||
template<typename VAL>
|
||||
inline bool
|
||||
Scale<VAL>::isLogarithmic() const
|
||||
{
|
||||
return metric == DEC
|
||||
or metric == NAT
|
||||
or metric == BIN;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ===== conforming operations ===== */
|
||||
|
|
@ -187,17 +150,13 @@ namespace par {
|
|||
inline VAL
|
||||
Scale<VAL>::conform (VAL const& rawVal) const
|
||||
{
|
||||
if (isCyclic())
|
||||
if (cyclic)
|
||||
{
|
||||
REQUIRE (minVal and maxVal);
|
||||
REQUIRE (*minVal < *maxVal);
|
||||
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[ "}
|
||||
% rawVal % *minVal % *maxVal
|
||||
};
|
||||
return util::cyclicWrap (rawVal, *minVal, *maxVal);
|
||||
const VAL PERIOD = *maxVal - *minVal;
|
||||
ENSURE (0 < PERIOD);
|
||||
return (rawVal - *minVal) % PERIOD;
|
||||
}
|
||||
if (minVal and rawVal < *minVal)
|
||||
return *minVal;
|
||||
|
|
@ -207,7 +166,6 @@ namespace par {
|
|||
return rawVal;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Join and combine an additional feed value with an anchor value.
|
||||
* @note actual joining operation is picked based on both scales and types involved.
|
||||
|
|
@ -216,40 +174,10 @@ namespace par {
|
|||
template<typename VAL>
|
||||
template<typename SRC>
|
||||
inline VAL
|
||||
Scale<VAL>::join (VAL const& value, SRC const& srcFeed, Scale<SRC> const& feedScale) const
|
||||
Scale<VAL>::join (VAL const& value, SRC const& feed, Scale<SRC> const& feedScale) const
|
||||
{
|
||||
VAL res{};
|
||||
using JoinT = NumberJoinType<VAL,SRC>;
|
||||
|
||||
if (NOM == metric)
|
||||
UNIMPLEMENTED ("nominal and ordinal scales");
|
||||
if (LIN == metric)
|
||||
{
|
||||
if (feedScale.isLogarithmic())
|
||||
assignConverted (res, value * feedScale.template asFactor<VAL> (srcFeed));
|
||||
else
|
||||
if (feedScale.isFactor())
|
||||
assignConverted (res, JoinT(value) * JoinT(srcFeed));
|
||||
else
|
||||
assignConverted (res, JoinT(value) + JoinT(srcFeed));
|
||||
}
|
||||
else
|
||||
if (this->isLogarithmic())
|
||||
{
|
||||
if (feedScale.isLogarithmic())
|
||||
assignConverted (res, value + feedScale.template baseScale<VAL>(metric) * srcFeed);
|
||||
else
|
||||
if (feedScale.isFactor())
|
||||
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."};
|
||||
}
|
||||
else
|
||||
NOTREACHED ("Unexpected metric conversion case");
|
||||
|
||||
return conform (res);
|
||||
} // last step: re-establish target scale rules
|
||||
|
||||
UNIMPLEMENTED ("join a feed with a base value, observing Scale constraints");
|
||||
}
|
||||
|
||||
/**
|
||||
* Simplified join() variant, assuming the feed is based on the same scale.
|
||||
|
|
@ -264,81 +192,5 @@ 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*/
|
||||
|
|
|
|||
|
|
@ -1,207 +0,0 @@
|
|||
/*
|
||||
TYPE-HANDLER.hpp - generic type conversion handling support
|
||||
|
||||
Copyright (C)
|
||||
2026 Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
**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.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/** @file type-handler.hpp
|
||||
** Generic building blocks to support parameter value conversions and adaptation.
|
||||
** The implementation of parameters is built such as to conceal the actual type of
|
||||
** the parameter values -- which requires a virtual dispatch at some point. Yet the
|
||||
** underlying type conversion functionality can be defined in a generic way, based
|
||||
** on the actual types involved. Simple value-like parameters are based on a fixed
|
||||
** collection of number types, both integral and floating-point. Thus the actual
|
||||
** conversion is handled by the promotion- and coercion rules of C++ in most cases.
|
||||
**
|
||||
** @todo WIP-WIP-WIP can be considered an initial draft and placeholder, as of 2026
|
||||
*/
|
||||
|
||||
|
||||
#ifndef LIB_PAR_TYPE_HANDLER_H
|
||||
#define LIB_PAR_TYPE_HANDLER_H
|
||||
|
||||
|
||||
#include "lib/par/spec.hpp"
|
||||
#include "lib/meta/trait.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
#include <concepts>
|
||||
#include <limits>
|
||||
|
||||
|
||||
namespace lib {
|
||||
namespace par {
|
||||
|
||||
using util::isNeg;
|
||||
using std::same_as;
|
||||
using std::integral;
|
||||
using std::signed_integral;
|
||||
using std::floating_point;
|
||||
using std::numeric_limits;
|
||||
using std::common_type_t;
|
||||
using std::is_signed_v;
|
||||
using std::is_unsigned_v;
|
||||
using std::is_integral_v;
|
||||
using std::is_floating_point_v;
|
||||
|
||||
|
||||
/* ===== type conversion implementation details ===== */
|
||||
|
||||
/** Constraint: type \a SUB can not represent the full domain of type \a BAS
|
||||
* @todo implicitly also implements a limitation to »numeric« types,
|
||||
* due to the use of std::numeric_limits
|
||||
*/
|
||||
template<typename SUB, typename BAS>
|
||||
concept sub_domain = signed_integral<SUB> != signed_integral<BAS>
|
||||
or numeric_limits<SUB>::max() < numeric_limits<BAS>::max()
|
||||
or numeric_limits<SUB>::lowest() > numeric_limits<BAS>::lowest()
|
||||
;
|
||||
|
||||
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wsign-compare\"")
|
||||
// the following functions are specifically crafted to work around
|
||||
// the ambiguities caused by automatic signed-to-unsigned promotion;
|
||||
// furthermore, the automatic promotion allows to perform the comparison.
|
||||
|
||||
template<typename X, typename Y>
|
||||
inline constexpr bool
|
||||
isLower_safe (X const& x, Y const& y)
|
||||
{
|
||||
return isNeg(x) == isNeg(y)? x < y
|
||||
: isNeg(x);
|
||||
}
|
||||
|
||||
template<typename X, typename Y>
|
||||
inline constexpr bool
|
||||
isLarger_safe (X const& x, Y const& y)
|
||||
{
|
||||
return isNeg(x) == isNeg(y)? x > y
|
||||
: isNeg(y);
|
||||
}
|
||||
_Pragma("GCC diagnostic pop")
|
||||
|
||||
|
||||
|
||||
/** generic helper to conform into a common value domain
|
||||
* @tparam SUB the implied target value domain
|
||||
* @tparam BAS source data type
|
||||
* @return a value in source data type,
|
||||
* yet conformed into the target data range
|
||||
*/
|
||||
template<typename SUB, typename BAS>
|
||||
inline constexpr BAS
|
||||
preClamp (BAS const& value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
/** special case: clamp the source value into the target value domain.
|
||||
* @remark tricky due to automatic conversions between signed/unsigned */
|
||||
template<typename SUB, typename BAS> requires (sub_domain<SUB,BAS>
|
||||
and not same_as<SUB,bool>)
|
||||
inline constexpr BAS
|
||||
preClamp (BAS const& rawVal)
|
||||
{
|
||||
static_assert (std::is_constructible_v<BAS,SUB const&>
|
||||
,"Value domains must overlap at least partially "
|
||||
"and values must be cross-constructible within overlap");
|
||||
|
||||
auto upperBound = numeric_limits<SUB>::max();
|
||||
auto lowerBound = numeric_limits<SUB>::lowest();
|
||||
|
||||
return isLarger_safe(rawVal, upperBound)? BAS(upperBound)
|
||||
: isLower_safe (rawVal, lowerBound)? BAS(lowerBound)
|
||||
: rawVal;
|
||||
}
|
||||
|
||||
/** special case: trigger a bool at the 0.5 level */
|
||||
template<same_as<bool> B, floating_point F>
|
||||
inline constexpr F
|
||||
preClamp (F const& rawVal)
|
||||
{
|
||||
return 0.5 < rawVal? F{1} : F{0};
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename V, typename X>
|
||||
inline void
|
||||
assignConverted (V& targetVal, X const& srcVal)
|
||||
{
|
||||
if constexpr (std::is_assignable_v<V&, X const&>)
|
||||
{
|
||||
targetVal = preClamp<V> (srcVal);
|
||||
}
|
||||
else
|
||||
if constexpr (std::is_constructible_v<V, X const&>)
|
||||
{
|
||||
targetVal.~V();
|
||||
new(&targetVal) V (preClamp<V> (srcVal));
|
||||
}
|
||||
else
|
||||
static_assert (!sizeof(X), "this type conversion is not supported");
|
||||
}
|
||||
|
||||
|
||||
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 {
|
||||
/** @internal decision logic for combining numeric parameters */
|
||||
template<typename V, typename W>
|
||||
auto
|
||||
selectNumberJoinType()
|
||||
{
|
||||
if constexpr (is_floating_point_v<V> or is_floating_point_v<W>)
|
||||
return std::type_identity<common_type_t<V,W>>{};
|
||||
else
|
||||
if constexpr (is_signed_v<V> == is_signed_v<W>)
|
||||
return std::type_identity<common_type_t<V,W>>{};
|
||||
else
|
||||
{ // mixed signed/unsigned integral: need a type wide enough to accommodate.
|
||||
using U = std::conditional_t<is_signed_v<V>, W,V>;
|
||||
if constexpr (8 > sizeof(U))
|
||||
return std::type_identity<int64_t>{};
|
||||
else
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
static_assert (64 <= std::numeric_limits<lflo>::digits
|
||||
,"long double type can not represent uint64_t exactly");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A common type to perform simple numeric operations safely.
|
||||
* - when one of the type parameters is floating-point, computations switch over there
|
||||
* - on integral types with same signedness, std::common_type handles a sane common ground
|
||||
* - when mixed computations can be managed within signed 64bit, switch up to that
|
||||
* - 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<typename A, typename B>
|
||||
using NumberJoinType = typename decltype(selectNumberJoinType<A,B>())::type;
|
||||
|
||||
|
||||
|
||||
}} // namespace lib::par
|
||||
#endif /*LIB_PAR_TYPE_HANDLER_H*/
|
||||
|
|
@ -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"
|
||||
lflo const ROUND_ULP = 1 + 1/(lflo(std::numeric_limits<int64_t>::max()) * 2);
|
||||
f128 const ROUND_ULP = 1 + 1/(f128(std::numeric_limits<int64_t>::max()) * 2);
|
||||
|
||||
// construct approximation quantised to 1/u
|
||||
lflo frac = lflo(r) / den;
|
||||
f128 frac = f128(r) / den;
|
||||
int64_t res = d*u + int64_t(frac*u * ROUND_ULP);
|
||||
ENSURE (abs (lflo(res)/u - rational_cast<lflo>(Rat{num,den})) <= 1.0/abs(u)
|
||||
ENSURE (abs (f128(res)/u - rational_cast<f128>(Rat{num,den})) <= 1.0/abs(u)
|
||||
,"Requantisation error exceeded num=%li / den=%li -> res=%li / quant=%li"
|
||||
, num, den, res, u);
|
||||
return res;
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ namespace util {
|
|||
inline constexpr F
|
||||
limit_cyclicWrap (F period)
|
||||
{
|
||||
REQUIRE (std::isnormal (period));
|
||||
REQUIRE (std::isfinite (period));
|
||||
REQUIRE (F(0) < period);
|
||||
F limit = period / std::numeric_limits<F>::epsilon();
|
||||
if (not std::isfinite (limit))
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@
|
|||
#include "lib/random.hpp"
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <concepts>
|
||||
#include <typeinfo>
|
||||
#include <cstdlib>
|
||||
#include <utility>
|
||||
|
|
@ -62,15 +61,14 @@ namespace test{
|
|||
using util::showType;
|
||||
using util::showTypes;
|
||||
|
||||
using std::floating_point;
|
||||
|
||||
constexpr auto ROUGH_PRECISION = pow (10, -3);
|
||||
constexpr auto EPSILON_ULP = 5;
|
||||
|
||||
|
||||
template<floating_point F, typename N>
|
||||
constexpr inline
|
||||
bool
|
||||
template<typename F, typename N>
|
||||
constexpr inline enable_if< std::is_floating_point<F>,
|
||||
bool >
|
||||
roughEQ (F val, N target, F limit =ROUGH_PRECISION)
|
||||
{
|
||||
REQUIRE (0 < limit);
|
||||
|
|
@ -78,9 +76,9 @@ namespace test{
|
|||
} //////////////////////////////////////////////////////////////////////////TICKET #1360 looks like this problem was solved several times
|
||||
|
||||
|
||||
template<floating_point F>
|
||||
constexpr inline
|
||||
F
|
||||
template<typename F>
|
||||
constexpr inline enable_if< std::is_floating_point<F>,
|
||||
F >
|
||||
ulp (F val)
|
||||
{
|
||||
val = fabs (val);
|
||||
|
|
@ -92,9 +90,9 @@ namespace test{
|
|||
return scaledUlp;
|
||||
}
|
||||
|
||||
template<floating_point F, typename N>
|
||||
constexpr inline
|
||||
bool
|
||||
template<typename F, typename N>
|
||||
constexpr inline enable_if< std::is_floating_point<F>,
|
||||
bool >
|
||||
epsEQ (F val, N target, uint ulps =EPSILON_ULP)
|
||||
{
|
||||
return abs (val - target) < ulps * ulp<F> (target);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include "lib/util-quant.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
using ::Test;
|
||||
using util::isLimited;
|
||||
using std::floating_point;
|
||||
|
||||
|
|
@ -76,7 +77,7 @@ namespace test {
|
|||
|
||||
verifyFloatTypes<float>();
|
||||
verifyFloatTypes<double>();
|
||||
verifyFloatTypes<lflo>();
|
||||
verifyFloatTypes<f128>();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
|
||||
#include "test/run.hpp"
|
||||
#include "test/test-helper.hpp"
|
||||
//#include "test/test-helper.hpp"
|
||||
#include "lib/par/scale.hpp"
|
||||
#include "test/diagnostic-output.hpp"/////////////TODO
|
||||
|
||||
|
|
@ -28,7 +28,6 @@
|
|||
//using std::string;
|
||||
//using std::vector;
|
||||
//using std::swap;
|
||||
using test::roughEQ;
|
||||
|
||||
|
||||
namespace lib {
|
||||
|
|
@ -59,9 +58,7 @@ namespace test{
|
|||
run (Arg)
|
||||
{
|
||||
simpleUsage();
|
||||
verify_Conforming();
|
||||
verify_cyclicScale();
|
||||
verify_valueJoining();
|
||||
verify_Bounds();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -79,159 +76,11 @@ namespace test{
|
|||
}
|
||||
|
||||
|
||||
/** @test accommodate values to comply with the scale
|
||||
* - optionally a maximum and minimum can be enforced
|
||||
* - optionally the value can be cyclically wrapped
|
||||
* @todo WIP 9/26 ✔ define ⟶ ✔ implement
|
||||
*/
|
||||
void
|
||||
verify_Conforming()
|
||||
{
|
||||
Scale<float> scale;
|
||||
CHECK (1e5f == scale.conform (1e5f));
|
||||
|
||||
scale.maxVal = -5.0f;
|
||||
CHECK (-5.0f == scale.conform (1e5f));
|
||||
|
||||
CHECK (scale.isValid());
|
||||
scale.minVal = 5.0f;
|
||||
CHECK (not scale.isValid());
|
||||
scale.maxVal = 8.0f;
|
||||
CHECK (scale.isValid());
|
||||
CHECK (5.0f == scale.conform (-5.0f));
|
||||
|
||||
CHECK (not scale.isCyclic());
|
||||
scale.cyclicLim = 100;
|
||||
CHECK (scale.isCyclic());
|
||||
CHECK (7.0f == scale.conform (-5.0f));
|
||||
CHECK (5.0f == scale.conform (-4.0f));
|
||||
CHECK (6.0f == scale.conform (-3.0f));
|
||||
CHECK (7.0f == scale.conform (-2.0f));
|
||||
|
||||
VERIFY_FAIL ("beyond supported numeric precision"
|
||||
, scale.conform (-1e5f));
|
||||
}
|
||||
|
||||
|
||||
/** @test Scales can be configured to wrap cyclically, e.g. for angles.
|
||||
* - demonstrate an unsigned angle scale with short precision
|
||||
* - demonstrate a high-resolution scale symmetric to zero
|
||||
* @todo WIP 9/26 ✔define ⟶ ✔ implement
|
||||
*/
|
||||
void
|
||||
verify_cyclicScale()
|
||||
{
|
||||
Scale<ushort> angleScale = {.minVal=0, .maxVal=360, .cyclicLim=0xFFFF};
|
||||
CHECK (angleScale.isValid());
|
||||
CHECK (angleScale.isCyclic());
|
||||
|
||||
CHECK ( 0 == angleScale.conform(0));
|
||||
CHECK (180 == angleScale.conform(180));
|
||||
CHECK (240 == angleScale.conform(240));
|
||||
CHECK ( 0 == angleScale.conform(360));
|
||||
CHECK (359 == angleScale.conform(719));
|
||||
CHECK ( 0 == angleScale.conform(65520));
|
||||
CHECK ( 15 == angleScale.conform(65535));
|
||||
|
||||
|
||||
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());
|
||||
CHECK (tinyScale.isCyclic());
|
||||
|
||||
CHECK ( tinyScale.conform(0 ) == 0 );
|
||||
CHECK (roughEQ (tinyScale.conform(0.001) , 0.001));
|
||||
CHECK (roughEQ (tinyScale.conform(0.005) , 0.005));
|
||||
CHECK (roughEQ (tinyScale.conform(0.00999), 0.00999));
|
||||
CHECK (roughEQ (tinyScale.conform(0.01 ),-0.0099999)); // surprise: 1/100 not exactly representable in floating-point
|
||||
|
||||
// since the domain is symmetric and 2/100 long, the ten-folds will fall into the middle,
|
||||
// but they typically do not land precisely on zero due to inherent "number dust"
|
||||
CHECK (1e15 > fabs(tinyScale.conform(1)));
|
||||
CHECK (0 != tinyScale.conform(1) );
|
||||
|
||||
auto beyond_precision = -10 * tinyScale.cyclicLim;
|
||||
VERIFY_FAIL ("beyond supported numeric precision"
|
||||
, tinyScale.conform (beyond_precision));
|
||||
}
|
||||
|
||||
|
||||
/** @test Base value and data feeds from differing Scales can be joined together
|
||||
* - when the target scale defines limits (or is cyclic),
|
||||
* this conforming is applied after all conversions
|
||||
* - a feed can be marked as "factor", in which case
|
||||
* the feed is multiplied to the target rather than added
|
||||
* - even scales with integral type can carry log meaning
|
||||
* - suitable intermediary types used for good precision,
|
||||
* and especially to avoid wrapping signed into unsigned
|
||||
* - the supported logarithmic flavours are accommodated,
|
||||
* possibly converting the base of the logarithm accordingly
|
||||
* - the factor 10 inherent to decibels is applied / removed
|
||||
* before combining decibel values with other logarithms
|
||||
* - 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
|
||||
* @todo WIP 9/26 🔁 define ⟶ ✔ implement
|
||||
*/
|
||||
void
|
||||
verify_valueJoining()
|
||||
{
|
||||
Scale<ushort> scale = {.minVal = 2, .maxVal = 10};
|
||||
Scale<int64_t> feedScale;
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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};
|
||||
|
||||
// Note: number promotion rules of C++ would backfire nastily here...
|
||||
CHECK (short(-3) * uint64_t(2) > numeric_limits<int64_t>::max());
|
||||
CHECK (short(-6) == sscale.join (-3, uint64_t(2), uscale));
|
||||
|
||||
//---floating-point logarithmic scale conversions---
|
||||
//
|
||||
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 10dB ≙ factor 10 * lg(10) value divided / 10
|
||||
|
||||
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
|
||||
|
||||
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;
|
||||
CHECK (roughEQ (fscale.join (1, int64_t(-3), feedScale), 1.0f/8 )); // binary log applied as factor to a linear scale
|
||||
|
||||
fscale.metric = BIN;
|
||||
feedScale.metric = LIN;
|
||||
feedScale.neutral = 1;
|
||||
CHECK (feedScale.isFactor());
|
||||
CHECK (fscale.isLogarithmic());
|
||||
CHECK (1 + 3 == fscale.join (1, int64_t(8), feedScale)); // feed factor 8 ⟼ to binary logarithmic fscale (8 ≡ 2^3) and added there
|
||||
|
||||
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), feedScale));
|
||||
}
|
||||
|
||||
|
||||
/** @test
|
||||
/** @test
|
||||
* @todo WIP 9/26 🔁 define ⟶ implement
|
||||
*/
|
||||
void
|
||||
verify_NominalScale()
|
||||
verify_Bounds()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -224,7 +224,7 @@ namespace test{
|
|||
|
||||
CHECK (format4Csv(double(1) / 3) == "0.333333333333333"_expect );
|
||||
CHECK (format4Csv(float(1) / 3) == "0.333333"_expect );
|
||||
CHECK (format4Csv(lflo(1) / 3) == "0.333333333333333333"_expect);
|
||||
CHECK (format4Csv(f128(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) lflo{std::numeric_limits<lflo>::max()};
|
||||
auto doooh = new(a1.mem) f128{std::numeric_limits<f128>::max()};
|
||||
*doooh /= 2;
|
||||
CHECK (2 == std::numeric_limits<lflo>::max() / *doooh);
|
||||
CHECK (2 == std::numeric_limits<f128>::max() / *doooh);
|
||||
|
||||
allo.deallocate (a1);
|
||||
allo.deallocate (a2);
|
||||
|
|
|
|||
|
|
@ -85572,45 +85572,8 @@
|
|||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1789164533222" ID="ID_1017590695" MODIFIED="1789164556832" TEXT="Problem: kann auch vom Typ des Beitrags (und des Basis-Werts) abhängen">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1789164561486" ID="ID_376197998" MODIFIED="1789164593909" TEXT="bedeutet: die darauf aufbauende Provision muß ggfs. einen double-Dispatch machen"/>
|
||||
<node CREATED="1789165221192" ID="ID_388299163" MODIFIED="1789687877259" TEXT="die Basis-Implementierung muß dann generisch sein und von Scale bereitgestellt werden">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Zwar könnte man auch so argumentieren, daß zunächst der Quell-Feed so adaptiert werden sollte, daß der Basistyp gleich ist...
|
||||
</p>
|
||||
<p>
|
||||
Bei genauerer Betrachtung stellt sich jedoch heraus, daß dies keine gute Idee ist, denn...
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
zum Einen wäre das jeweils ein weiterer dynamisch hinzugefügter Dekorator (und damit zusätzlicher Overhead), obwohl doch die eigentliche Umwandlung auf Basis bekannter Typen bereits zur Compile-Zeit gemacht werden könnte
|
||||
</li>
|
||||
<li>
|
||||
und außerdem wirft man damit die detailierte Information über den Quell-Feed weg (oder reicht sie dann eben doch weiter, wodurch dieser Schritt dann redundant würde) obwohl eben diese zusätzliche Information durchaus in einen besser angepaßten Rechenweg umgesetzt werden könnte
|
||||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1789165187065" ID="ID_1109273270" MODIFIED="1789165213989" TEXT="Konsequenz ⟹ die Scale muß hier zwei Typ-Parameter nehmen">
|
||||
<node CREATED="1789679141799" ID="ID_907734481" MODIFIED="1789679174971" TEXT="die eigentliche Wert-Umwandlung ist hier vergleichsweise einfach">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...weil wir die Basis-Typen für Parameter entsprechend eingeschränkt haben
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1789679178010" ID="ID_641923682" MODIFIED="1789679196411" TEXT="dazu genügt die preClamp-Funktion (generisch, mit Varianten)"/>
|
||||
<node CREATED="1789679234347" ID="ID_562560611" MODIFIED="1789679253968" TEXT="diese hängt aber (mit diversen weiteren Funktionen) in param-type.hpp"/>
|
||||
<node COLOR="#435e98" CREATED="1789679364793" ID="ID_1241002579" MODIFIED="1789690095158" STYLE="fork" TEXT="extrahieren in type-handler.hpp">
|
||||
<arrowlink COLOR="#3f4b72" DESTINATION="ID_517472625" ENDARROW="Default" ENDINCLINATION="368;-30;" ID="Arrow_ID_914959509" STARTARROW="None" STARTINCLINATION="-199;17;"/>
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1789165221192" ID="ID_388299163" MODIFIED="1789165234448" TEXT="die Basis-Implementierung muß dann generisch sein und von Scale bereitgestellt werden"/>
|
||||
<node CREATED="1789165187065" ID="ID_1109273270" MODIFIED="1789165213989" TEXT="Konsequenz ⟹ die Scale muß hier zwei Typ-Parameter nehmen"/>
|
||||
<node CREATED="1789165444623" ID="ID_1649021234" MODIFIED="1789165459491" TEXT="vereinfachte Variante für identische Scale"/>
|
||||
</node>
|
||||
</node>
|
||||
|
|
@ -85633,197 +85596,6 @@
|
|||
</html></richcontent>
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
<node CREATED="1789681257536" ID="ID_1700836715" MODIFIED="1789681261057" TEXT="Implementierung">
|
||||
<node COLOR="#338800" CREATED="1789681263702" ID="ID_517472625" MODIFIED="1789690087703" TEXT="type-handler.hpp verwenden">
|
||||
<linktarget COLOR="#3f4b72" DESTINATION="ID_517472625" ENDARROW="Default" ENDINCLINATION="368;-30;" ID="Arrow_ID_914959509" SOURCE="ID_1241002579" STARTARROW="None" STARTINCLINATION="-199;17;"/>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node CREATED="1789690189866" ID="ID_1376240578" MODIFIED="1789690197006" TEXT="Einzelfälle...">
|
||||
<node CREATED="1789690461895" ID="ID_1698758358" MODIFIED="1789690470825" TEXT="Ziel linear">
|
||||
<node CREATED="1789690555041" ID="ID_1115887554" MODIFIED="1789690584237" TEXT="Quelle logarithmisch ⟹ in Faktor verwandeln"/>
|
||||
<node CREATED="1789690484811" ID="ID_1985479365" MODIFIED="1789690540680" TEXT="Quelle multiplikativ ⟹ Feed multiplizieren"/>
|
||||
<node CREATED="1789690518951" ID="ID_369458503" MODIFIED="1789690532408" TEXT="sonst: ⟹ Feed addieren"/>
|
||||
</node>
|
||||
<node CREATED="1789690604246" ID="ID_1698111641" MODIFIED="1789690609463" TEXT="Ziel logarithmisch">
|
||||
<node CREATED="1789690612021" ID="ID_699494084" MODIFIED="1789690620205" TEXT="Quelle logarithmisch">
|
||||
<node CREATED="1789690621353" ID="ID_369958191" MODIFIED="1789690631911" TEXT="ggfs Basis-Anpassungsfaktor"/>
|
||||
<node CREATED="1789690632759" ID="ID_169878566" MODIFIED="1789690643602" TEXT="sonst ⟹ Feed addieren"/>
|
||||
</node>
|
||||
<node CREATED="1789690650447" ID="ID_763848405" MODIFIED="1789690934324" TEXT="Quelle multiplikativ ⟹ logarithmieren und addieren"/>
|
||||
<node COLOR="#5b280f" CREATED="1789690952586" ID="ID_806764948" MODIFIED="1789864844352" TEXT="sonst delogarithmieren, Feed addieren, re-logarithmieren">
|
||||
<icon BUILTIN="button_cancel"/>
|
||||
<node CREATED="1789864846110" ID="ID_1307210282" MODIFIED="1789865000390" TEXT="dieser Fall macht inhaltlich keinen Sinn">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
man könnte hier zwar delogarithmieren / relogarithmieren, aber was ist z.B. bei negativem Ergebnis...? und, noch mehr: welchen Sinn hat es zu einem <i>multiplikativen Faktor</i> etwas hinzuzuaddieren (was aber nicht logarithmisch ist)
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1789864856488" ID="ID_1180276604" MODIFIED="1789865677798" TEXT="diese Kombination kann eigentlich nur auf einen konzeptionellen Fehler hinweisen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Logarithmische Metrik verwendet man nur, wenn auch die Größe, in ihrer Bedeutung für die Wahrnehmung, selber logarithmisch ist. Zwar könnte man sich rein-formal vorstellen, daß so ein Fall durchaus mal auftreten kann — aber dann wäre es besser, die Situation zu hinterfragen: fehlt da vielleicht die Markierung des Feed als <i>logarithmisch?</i>
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1789691026066" ID="ID_1521422421" MODIFIED="1789691072009" TEXT="Ziel ordinal und Quelle additiv(linear) ⟹ Ordinal-Step"/>
|
||||
<node CREATED="1789691081395" ID="ID_1029470467" MODIFIED="1789691128539" TEXT="Ziel nominal und Quelle nominal oder linear ⟹ Feed(codiert) ersetzt Quelle"/>
|
||||
</node>
|
||||
<node CREATED="1789691154922" ID="ID_1884775055" MODIFIED="1789691157587" TEXT="Berechnung">
|
||||
<node CREATED="1789691206195" ID="ID_521077468" MODIFIED="1789877446133" TEXT="Berechnung mit passender Genauigkeit">
|
||||
<node CREATED="1789691368028" ID="ID_1992504549" MODIFIED="1789691686368" TEXT="de/Logarithmieren : stets bestmöglichen Floating-Point">
|
||||
<node CREATED="1789691697643" ID="ID_1724775924" MODIFIED="1789691708345" TEXT="von Integraltypen ⟹ stets double"/>
|
||||
<node CREATED="1789691709035" ID="ID_28970072" MODIFIED="1789691791715" TEXT="ansonsten maximalen floating-point-Typ">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
d.h. wenn beide Seiten float sind, dann ist das wohl auch so beabsichtigt, und wir bleiben in der float-Domäne. Ebenso wenn eine Seite long-double ist, dann alles dort. Sonst double verwenden
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1789869944433" ID="ID_1523483246" MODIFIED="1789877469677" TEXT="sollte das als Typedef ausdrücken: CommonComputeType<T,U>">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1789869964502" ID="ID_1289831616" MODIFIED="1789869996988" TEXT="geht nicht als Serie von constrained templates">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...weil sich die Constraints typischerweise überlappen
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1789869998707" ID="ID_221126714" MODIFIED="1789870032835" TEXT="dann doch die Bedingung als std::contditional_t ausformulieren">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<div style="background-color: #eee0b5; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 2px">
|
||||
<div style="color: #202020; background-color: #eee0b5; font-family: DejaVu Sans Mono; font-size: 9pt; white-space: pre">
|
||||
<p style="margin-top: 0; margin-right: 0; margin-bottom: 0; margin-left: 0">
|
||||
<font color="#4a1a65"><b>template</b></font><font color="#65533c"><</font><font color="#4a1a65"><b>typename</b></font><font color="#3a1f18"> </font><font color="#a34649"><b><u>T</u></b></font><font color="#65533c">></font>
|
||||
</p>
|
||||
<p style="margin-top: 0; margin-right: 0; margin-bottom: 0; margin-left: 0">
|
||||
<font color="#4a1a65"><b>concept</b></font><font color="#3a1f18"> number </font><font color="#65533c">=</font><font color="#3a1f18"> </font><font color="#59253b">integral<T></font><font color="#3a1f18">  </font><font color="#4a1a65"><b>or</b></font><font color="#3a1f18"> </font><font color="#59253b">floating_point<T></font><font color="#65533c">;</font>
|
||||
</p>
|
||||
<p style="margin-top: 0; margin-right: 0; margin-bottom: 0; margin-left: 0">
|
||||
<br />
|
||||
|
||||
</p>
|
||||
<p style="margin-top: 0; margin-right: 0; margin-bottom: 0; margin-left: 0">
|
||||
<font color="#b88b63">/**</font>
|
||||
</p>
|
||||
<p style="margin-top: 0; margin-right: 0; margin-bottom: 0; margin-left: 0">
|
||||
<font color="#b88b63">* the best-precision floating point type to carry out</font>
|
||||
</p>
|
||||
<p style="margin-top: 0; margin-right: 0; margin-bottom: 0; margin-left: 0">
|
||||
<font color="#b88b63">* a numeric operation to combine two values</font>
|
||||
</p>
|
||||
<p style="margin-top: 0; margin-right: 0; margin-bottom: 0; margin-left: 0">
|
||||
<font color="#b88b63">*/</font>
|
||||
</p>
|
||||
<p style="margin-top: 0; margin-right: 0; margin-bottom: 0; margin-left: 0">
|
||||
<font color="#4a1a65"><b>template</b></font><font color="#65533c"><</font><font color="#3a1f18">number </font><font color="#a34649"><b><u>T</u></b></font><font color="#65533c">,</font><font color="#3a1f18">  number </font><font color="#a34649"><b><u>U</u></b></font><font color="#65533c">></font>
|
||||
</p>
|
||||
<p style="margin-top: 0; margin-right: 0; margin-bottom: 0; margin-left: 0">
|
||||
<font color="#4a1a65"><b>using</b></font><font color="#3a1f18"> </font><font color="#8c505c"><b>CommonComputeType</b></font><font color="#3a1f18"> </font><font color="#65533c">=</font><font color="#3a1f18">  </font><font color="#535773">std</font><font color="#65533c">::</font><font color="#8c505c"><b>conditional_t</b></font><font color="#65533c"><</font><font color="#59253b">integral<T></font><font color="#3a1f18">  </font><font color="#4a1a65"><b>and</b></font><font color="#3a1f18"> </font><font color="#59253b">integral<U></font><font color="#65533c">,</font><font color="#3a1f18"> </font><font color="#7f004c"><b>double</b></font>
|
||||
</p>
|
||||
<p style="margin-top: 0; margin-right: 0; margin-bottom: 0; margin-left: 0">
|
||||
<font color="#65533c">,</font><font color="#3a1f18"> </font><font color="#535773">std</font><font color="#65533c">::</font><font color="#8c505c"><b>common_type_t</b></font><font color="#65533c"><</font><font color="#a34649"><b><u>T</u></b></font><font color="#65533c">,</font><font color="#3a1f18">  </font><font color="#a34649"><b><u>U</u></b></font><font color="#65533c">>>;</font>
|
||||
</p>
|
||||
<p style="margin-top: 0; margin-right: 0; margin-bottom: 0; margin-left: 0">
|
||||
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1789876376322" ID="ID_1223578931" MODIFIED="1789949324151" TEXT="eigentliche Join-Operation in auf passendem Zwischentyp ausführen">
|
||||
<linktarget COLOR="#28b55c" DESTINATION="ID_1223578931" ENDARROW="Default" ENDINCLINATION="-139;1297;" ID="Arrow_ID_225645373" SOURCE="ID_1294384495" STARTARROW="None" STARTINCLINATION="111;6;"/>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node BACKGROUND_COLOR="#fafe99" COLOR="#fa002a" CREATED="1789876423793" ID="ID_603151342" MODIFIED="1789877266018" TEXT="Vorsicht Falle: Kombination von signed/unsigned">
|
||||
<icon BUILTIN="broken-line"/>
|
||||
<node CREATED="1789877276449" ID="ID_1205492042" MODIFIED="1789877286892" TEXT="kann mich nicht allein auf die number-promotion verlassen"/>
|
||||
<node CREATED="1789877306308" ID="ID_1833375564" MODIFIED="1789877330237" TEXT="Gegenbeispiel: short(-3) * uint64_t(2)"/>
|
||||
</node>
|
||||
<node CREATED="1789876405765" ID="ID_1109556835" MODIFIED="1789877918151" TEXT="CommonComputeType verwenden">
|
||||
<icon BUILTIN="idea"/>
|
||||
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1789877920344" ID="ID_640203687" MODIFIED="1789877965236" STYLE="fork" TEXT="damit gehen aber nun auch einfache Additionen über floating-point — wollen wir das?">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
<node CREATED="1789878009733" ID="ID_1316581925" MODIFIED="1789878034175" TEXT="könnte in dem Fall eine Verfeinerung machen">
|
||||
<node CREATED="1789878125407" ID="ID_1221061821" MODIFIED="1789878140752" TEXT="das sollte nur in dem problematischen Fall greifen"/>
|
||||
<node CREATED="1789878141565" ID="ID_1028048071" MODIFIED="1789878149899" TEXT="also promotion to larger unsigned"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#accdc3" COLOR="#3f4015" CREATED="1789944510715" ID="ID_746993319" MODIFIED="1789944521564" TEXT="Claude beauftragt">
|
||||
<icon BUILTIN="wizard"/>
|
||||
<node CREATED="1789944530056" ID="ID_1759698759" MODIFIED="1789949125520" TEXT="schlägt eine Logik-Kaskade in Metaprogramming vor">
|
||||
<icon BUILTIN="info"/>
|
||||
<node CREATED="1789944639760" ID="ID_1968290680" MODIFIED="1789944654204" TEXT="floating-point ⟹ common_type macht die Arbeit"/>
|
||||
<node CREATED="1789944655000" ID="ID_1256360330" MODIFIED="1789944661011" TEXT="gleiche signedness ⟹ dto"/>
|
||||
<node CREATED="1789944662174" ID="ID_555669740" MODIFIED="1789944682944" TEXT="Bitlänge prüfen ⟹ wenn ausreichend, int64_t"/>
|
||||
<node CREATED="1789944684283" ID="ID_257781335" MODIFIED="1789945256482">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
sonst: Promotion in <b>long double</b>
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
bei letzterem hab ich nachgehakt, Claude hat zunächst double vorgeschlagen.
|
||||
</p>
|
||||
<p>
|
||||
Einsichten:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
double kann keinen uint64_t exakt halten (das wußte ich)
|
||||
</li>
|
||||
<li>
|
||||
long double ist auf x64 entweder 80bit oder 128 bit, also ausreichend
|
||||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1789944547766" ID="ID_1252274825" MODIFIED="1789945715864" TEXT="verwendet std::type_identity<T> um den Ergebnistyp aus einer Funktion zu liefern">
|
||||
<arrowlink COLOR="#8794ab" DESTINATION="ID_921530714" ENDARROW="Default" ENDINCLINATION="-2571;328;" ID="Arrow_ID_1292265667" STARTARROW="None" STARTINCLINATION="-3659;127;"/>
|
||||
<icon BUILTIN="idea"/>
|
||||
<node CREATED="1789944580961" ID="ID_354835013" MODIFIED="1789944589683" TEXT="Ha! den Trick kannte ich noch nicht">
|
||||
<icon BUILTIN="ksmiletris"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1789944608086" ID="ID_688346228" MODIFIED="1789949122394" TEXT="gefält mir gut: der einzige problematische Fall steht als eigener Zweig">
|
||||
<icon BUILTIN="ksmiletris"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1789691232896" ID="ID_575039816" MODIFIED="1789945553816" TEXT="Konvertierung in den Ziel-Typ stets zuletzt (vor Conform)"/>
|
||||
</node>
|
||||
<node CREATED="1789691159130" ID="ID_1328281700" MODIFIED="1789691168924" TEXT="zuletzt Conform() anwenden"/>
|
||||
<node CREATED="1789691889609" ID="ID_569629897" MODIFIED="1789691899860" TEXT="Formulierung: muß Funktions-Kette bilden"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1789002587495" ID="ID_509669988" MODIFIED="1789002595532" TEXT="Design nochmal reflektieren">
|
||||
<icon BUILTIN="pencil"/>
|
||||
|
|
@ -86287,8 +86059,8 @@ class ScaleRegistry
|
|||
</node>
|
||||
<node COLOR="#338800" CREATED="1789171875485" ID="ID_1356870727" MODIFIED="1789171905187" TEXT="conform">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#338800" CREATED="1789171881280" FOLDED="true" ID="ID_339852589" MODIFIED="1789676093985" TEXT="zyklische Scale behandeln">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1789171881280" ID="ID_339852589" MODIFIED="1789250353458" TEXT="zyklische Scale behandeln">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1789250357099" ID="ID_684124457" MODIFIED="1789250365217" TEXT="Vorsicht Falle">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1789250367429" ID="ID_1987781341" MODIFIED="1789250382816" TEXT="modulus und unsigned"/>
|
||||
|
|
@ -87251,43 +87023,8 @@ Prop.1: dist%3 1 2 0 1 2 0
|
|||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<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"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1789949198651" ID="ID_294918713" MODIFIED="1789949239261" TEXT="Varianten mit »multiplicative« und deciBel">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1789949240757" ID="ID_1294384495" MODIFIED="1789949324151" TEXT="sicheres Umgehen der unsigned/signed-Problematik">
|
||||
<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" 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 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>
|
||||
<body>
|
||||
<p>
|
||||
...und dieses Herausdividieren falte ich trickreich in den log-Basis-Konvertierungsfaktor.
|
||||
</p>
|
||||
<p>
|
||||
Überraschung: die Logarithmen-Matematik funktioniert ... aber das dumme Mensch braucht endlos um zu kapieren daß die Beispielwerte stimmen
|
||||
</p>
|
||||
</body>
|
||||
</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>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1789172002831" ID="ID_939833813" MODIFIED="1789172009585" TEXT="gemische Scales handhaben">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
@ -87494,7 +87231,7 @@ Prop.1: dist%3 1 2 0 1 2 0
|
|||
<icon BUILTIN="hourglass"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1789159639409" ID="ID_654373559" MODIFIED="1789607860036" TEXT="Scale-Eigenschaften abstecken per ParameterScale_test">
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1789159639409" ID="ID_654373559" MODIFIED="1789159678163" 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>
|
||||
|
|
@ -87523,44 +87260,6 @@ Prop.1: dist%3 1 2 0 1 2 0
|
|||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</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">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...da ein Test eigentlich mehr machen sollte, als nur nochmal den Code zu wiederholen; und hier passiert nicht mehr, als ein cap an der boundrary, auf einem komplett offensichtlichen und einfachen Code-Pfad
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1789607312019" ID="ID_1154758301" MODIFIED="1789607325207" TEXT="aber man könnte einen anderen Datentyp testen (z.B. Float)"/>
|
||||
<node CREATED="1789607333006" ID="ID_1782430086" MODIFIED="1789607343123" TEXT="und zeigen daß auch das cyclicWrap hier integriert ist"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1789607351998" ID="ID_144363848" MODIFIED="1789607354317" TEXT="verify_cyclicScale">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1789607356261" ID="ID_1762601340" MODIFIED="1789607743052" TEXT="auch hier nur bedingt sinnvoll testbar">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...denn die eigentlich trickreiche Funktionalität steckt in der Library-Funktion und ist dort schon per Unit-Test abgedeckt, und das korrekte Setup wird innerhalb des Scale-Descriptors gar nicht geprüft (weil diese Prüfung in den umschließenden Kontext gehört, wo die Scale in einen Parameter-Typ eingebunden wird)
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1789607368451" ID="ID_383818308" MODIFIED="1789607375932" TEXT="kann zwei relevante Fälle demonstrieren">
|
||||
<node CREATED="1789607377402" ID="ID_1342839519" MODIFIED="1789607401203" TEXT="Winkel-Skala (unsigned short)"/>
|
||||
<node CREATED="1789607407654" ID="ID_1837015555" MODIFIED="1789607428439" TEXT="floating-point-Scala mit kleinen Werten"/>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1789607809345" ID="ID_1668358580" MODIFIED="1789607849725" TEXT="diese Tests dienen eigentlich nur dem Integrations-Check — und sind Dokumentation">
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1789675604211" ID="ID_201071963" MODIFIED="1789676070358" TEXT="verify_valueJoining">
|
||||
<icon BUILTIN="pencil"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
@ -188946,28 +188645,6 @@ std::cout << tmpl.render({"what", "World"}) << s
|
|||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1789945524270" ID="ID_921530714" MODIFIED="1789945715864" TEXT="std::type_identity<T>">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<ul>
|
||||
<li>
|
||||
Ist nur eine ansonsten leere Struct mit einer typedef "type = T"
|
||||
</li>
|
||||
<li>
|
||||
also die »Identity«-Metafunktion
|
||||
</li>
|
||||
<li>
|
||||
nützlich um eine Typ-Entscheidungslogik in einer Funktion per constexpr-if zu formulieren
|
||||
</li>
|
||||
<li>
|
||||
und natürlich allgemein, um Typen als first-class-citizens weiterzugeben
|
||||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<linktarget COLOR="#8794ab" DESTINATION="ID_921530714" ENDARROW="Default" ENDINCLINATION="-2571;328;" ID="Arrow_ID_1292265667" SOURCE="ID_1252274825" STARTARROW="None" STARTINCLINATION="-3659;127;"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1617648907316" FOLDED="true" ID="ID_899199723" MODIFIED="1617650703506" TEXT="Coroutine">
|
||||
|
|
|
|||
Loading…
Reference in a new issue