Parameters: implementation for metric conversions
LIN -> LIN yet either additive or multiplicative LOG -> LIN LIN -> LOG and different kinds of logarithms all computations using a common intermediary numeric type, preferably a suitably sized floating-point
This commit is contained in:
parent
16bb331be0
commit
129eb0c1bd
4 changed files with 218 additions and 26 deletions
|
|
@ -42,6 +42,7 @@ namespace lib {
|
|||
namespace par {
|
||||
namespace err = lumiera::error;
|
||||
|
||||
using util::_Fmt;
|
||||
using std::optional;
|
||||
|
||||
|
||||
|
|
@ -78,6 +79,7 @@ namespace par {
|
|||
bool isValid() const;
|
||||
bool isFactor() const;
|
||||
bool isCyclic() const;
|
||||
bool isLogarithmic() const;
|
||||
|
||||
/* ===== conforming operations ===== */
|
||||
|
||||
|
|
@ -88,15 +90,16 @@ namespace par {
|
|||
VAL join (VAL const&, SRC const&, Scale<SRC> const&) const;
|
||||
VAL join (VAL const&, VAL const&) const;
|
||||
|
||||
private:
|
||||
template<typename TAR>
|
||||
VAL asFactor (VAL const&) const;
|
||||
/* ===== conversion helpers ===== */
|
||||
|
||||
template<typename TAR>
|
||||
VAL baseScale (Metric targetMetric) const;
|
||||
auto asFactor (VAL const&) const;
|
||||
|
||||
template<typename TAR>
|
||||
VAL asLogarithm (Metric targetMetric, VAL const&) const;
|
||||
auto baseScale (Metric targetMetric) const;
|
||||
|
||||
template<typename TAR>
|
||||
auto asLogarithm (Metric targetMetric, VAL const&) const;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -153,6 +156,15 @@ namespace par {
|
|||
return VAL(0) != cyclicLim;
|
||||
}
|
||||
|
||||
template<typename VAL>
|
||||
inline bool
|
||||
Scale<VAL>::isLogarithmic() const
|
||||
{
|
||||
return metric == DEC
|
||||
or metric == NAT
|
||||
or metric == BIN;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ===== conforming operations ===== */
|
||||
|
|
@ -181,7 +193,7 @@ namespace par {
|
|||
REQUIRE (*minVal < *maxVal);
|
||||
if (std::is_floating_point_v<VAL>)
|
||||
if (not (std::abs (rawVal) < cyclicLim))
|
||||
throw err::Invalid {util::_Fmt{"Parameter value %4.2g beyond supported numeric precision "
|
||||
throw err::Invalid {_Fmt{"Parameter value %4.2g beyond supported numeric precision "
|
||||
"for cyclic wrapping into [%1.2g...%1.2g[ "}
|
||||
% rawVal % *minVal % *maxVal
|
||||
};
|
||||
|
|
@ -213,7 +225,7 @@ namespace par {
|
|||
if (feedScale.isLogarithmic())
|
||||
assignConverted (res, value * feedScale.template asFactor<VAL> (srcFeed));
|
||||
else
|
||||
if (this->isFactor())
|
||||
if (feedScale.isFactor())
|
||||
assignConverted (res, value * srcFeed);
|
||||
else
|
||||
assignConverted (res, value + srcFeed);
|
||||
|
|
@ -247,28 +259,77 @@ namespace par {
|
|||
);
|
||||
}
|
||||
|
||||
/** transform a logarithmic value into an exponential factor */
|
||||
template<typename VAL>
|
||||
template<typename TAR>
|
||||
inline VAL
|
||||
inline auto
|
||||
Scale<VAL>::asFactor (VAL const& value) const
|
||||
{
|
||||
UNIMPLEMENTED ("transform a logarithmic value into an exponential factor");
|
||||
}
|
||||
|
||||
template<typename VAL>
|
||||
template<typename TAR>
|
||||
inline VAL
|
||||
Scale<VAL>::baseScale (Metric targetMetric) const
|
||||
using WorkType = CommonComputeType<VAL,TAR>;
|
||||
switch (metric)
|
||||
{
|
||||
UNIMPLEMENTED ("provide the adaptation factor from this logarithmic scale to the given other logarithmic scale");
|
||||
case NAT: return std::exp (WorkType(value));
|
||||
case BIN: return std::exp2 (WorkType(value));
|
||||
case DEC: return std::pow<WorkType> (10, 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 VAL
|
||||
inline auto
|
||||
Scale<VAL>::asLogarithm (Metric targetMetric, VAL const& value) const
|
||||
{
|
||||
UNIMPLEMENTED ("transform this value into a suitable logarithm for the target scale");
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -42,8 +42,9 @@ namespace par {
|
|||
|
||||
using util::isNeg;
|
||||
using std::same_as;
|
||||
using std::floating_point;
|
||||
using std::integral;
|
||||
using std::signed_integral;
|
||||
using std::floating_point;
|
||||
using std::numeric_limits;
|
||||
|
||||
|
||||
|
|
@ -146,6 +147,18 @@ _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 T, number U>
|
||||
using CommonComputeType = std::conditional_t<integral<T> and integral<U>, double
|
||||
, std::common_type_t<T, U>>;
|
||||
|
||||
|
||||
|
||||
}} // namespace lib::par
|
||||
#endif /*LIB_PAR_TYPE_HANDLER_H*/
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ namespace test{
|
|||
simpleUsage();
|
||||
verify_Conforming();
|
||||
verify_cyclicScale();
|
||||
verify_valueJoining();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -156,13 +157,28 @@ namespace test{
|
|||
}
|
||||
|
||||
|
||||
/** @test
|
||||
/** @test Base value and data feeds from differing Scales can be joined together
|
||||
* @todo WIP 9/26 🔁 define ⟶ implement
|
||||
*/
|
||||
void
|
||||
verify_valueJoining()
|
||||
{
|
||||
Scale<float> scale;
|
||||
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
|
||||
|
||||
////////////////////////////OOO die folgende Konvertierung entgleist....
|
||||
SHOW_EXPR(short(-3) * uint64_t(2))
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -85656,13 +85656,41 @@
|
|||
<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 CREATED="1789690952586" ID="ID_806764948" MODIFIED="1789690977990" TEXT="sonst delogarithmieren, Feed addieren, re-logarithmieren"/>
|
||||
<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>
|
||||
|
||||
</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>
|
||||
|
||||
</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="1789691213662" TEXT="Genauigkeit steigern">
|
||||
<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">
|
||||
|
|
@ -85678,6 +85706,80 @@
|
|||
</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>
|
||||
|
||||
</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>
|
||||
|
||||
</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 BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1789876376322" ID="ID_1223578931" MODIFIED="1789876404350" TEXT="eigentliche Join-Operation in auf passendem Zwischentyp ausführen">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node CREATED="1789876405765" ID="ID_1109556835" MODIFIED="1789876417629" TEXT="CommonComputeType verwenden"/>
|
||||
<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>
|
||||
<node CREATED="1789691232896" ID="ID_575039816" MODIFIED="1789691803456" TEXT="Konvertierung in den Ziel-Typ stets zuletzt (vor Conform)"/>
|
||||
</node>
|
||||
|
|
|
|||
Loading…
Reference in a new issue