Library: introduce formating variants for decimal10

showDecimal -> decimal10 (maximal precision to survive round-trip through decimal representation=

showComplete -> max_decimal10 (enough decimal places to capture each possible distinct floating-point value)


Use these new functions to rewrite the format4csv() helper
This commit is contained in:
Fischlurch 2024-03-14 17:32:22 +01:00
parent 01a098db99
commit 3b3600379a
8 changed files with 203 additions and 45 deletions

View file

@ -52,6 +52,7 @@
#include <cxxabi.h>
#endif
#include <limits>
#include <iomanip>
#include <sstream>
#include <string>
@ -75,6 +76,15 @@ namespace { // hard-wired configuration for debugging output....
/** show only this amount of trailing bytes from an address */
const size_t DIAGNOSTICS_ADDRESS_SUFFIX_LEN = 4;
/** maximum decimal digits able to pass through a round trip without value change */
template<typename F>
constexpr size_t PRECISION_DECIMAL = std::numeric_limits<F>::digits10;
/** decimal digits require tod represent each different floating-point value */
template<typename F>
constexpr size_t PRECISION_COMPLETE = std::numeric_limits<F>::max_digits10;
}
@ -329,7 +339,18 @@ namespace util {
using std::noshowbase;
using std::ostringstream;
using std::ostream;
template<typename F>
string
showFloatingPoint (F val, size_t precision) noexcept
try {
ostringstream buffer;
buffer.precision (precision);
buffer << val;
return buffer.str();
}
catch(...)
{ return FAILURE_INDICATOR; }
/**
* @return fixed point string representation, never empty
@ -338,28 +359,16 @@ namespace util {
* we do want a predictable string representation of simple fractional
* values like `0.1` (which can not be represented as binary floats)
*/
string
showDouble (double val) noexcept
try {
ostringstream buffer;
buffer.precision (DIAGNOSTICS_DOUBLE_PRECISION);
buffer << val;
return buffer.str();
}
catch(...)
{ return FAILURE_INDICATOR; }
string showDouble (double val) noexcept { return showFloatingPoint (val, DIAGNOSTICS_DOUBLE_PRECISION); }
string showFloat (float val) noexcept { return showFloatingPoint (val, DIAGNOSTICS_FLOAT_PRECISION); }
string showDecimal (double val) noexcept { return showFloatingPoint (val, PRECISION_DECIMAL<double>); }
string showDecimal (float val) noexcept { return showFloatingPoint (val, PRECISION_DECIMAL<float>); }
string showDecimal (f128 val) noexcept { return showFloatingPoint (val, PRECISION_DECIMAL<f128>); }
string
showFloat (float val) noexcept
try {
ostringstream buffer;
buffer.precision (DIAGNOSTICS_FLOAT_PRECISION);
buffer << val;
return buffer.str();
}
catch(...)
{ return FAILURE_INDICATOR; }
string showComplete (double val) noexcept { return showFloatingPoint (val, PRECISION_COMPLETE<double>); }
string showComplete (float val) noexcept { return showFloatingPoint (val, PRECISION_COMPLETE<float>); }
string showComplete (f128 val) noexcept { return showFloatingPoint (val, PRECISION_COMPLETE<f128>); }
string

View file

@ -100,6 +100,13 @@ namespace util {
return showHash(hash,1);
}
std::string showDecimal (double) noexcept;
std::string showDecimal (float) noexcept;
std::string showDecimal (f128) noexcept;
std::string showComplete (double)noexcept;
std::string showComplete (float) noexcept;
std::string showComplete (f128) noexcept;
namespace {

View file

@ -38,6 +38,9 @@
using uchar = unsigned char;
using uint = unsigned int;
using f128 = long double;
static_assert(10 <= sizeof(f128));
const uint LIFE_AND_UNIVERSE_4EVER = 42;

View file

@ -37,6 +37,7 @@
#ifndef LIB_META_UTIL_H
#define LIB_META_UTIL_H
#include "lib/integral.hpp"
#include <typeinfo>
#include <string>
@ -425,10 +426,20 @@ namespace util {
: lib::meta::BOOL_FALSE_STR;
}
/** pretty-print a double in fixed-point format */
/** pretty-print a double in (rounded) fixed-point format */
std::string showDouble (double) noexcept;
std::string showFloat (float) noexcept;
/** show maximum reproducible decimal representation */
std::string showDecimal (double) noexcept;
std::string showDecimal (float) 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 (f128) noexcept;
std::string showSize (size_t) noexcept;

View file

@ -68,6 +68,7 @@
#define LIB_RATIONAL_H
#include "lib/integral.hpp"
#include "lib/util-quant.hpp"
#include <cmath>
@ -129,7 +130,6 @@ namespace util {
{
u = 0!=u? u:1;
auto [d,r] = util::iDiv (num, den);
using f128 = long double;
// round to smallest integer fraction, to shake off "number dust"
f128 const ROUND_ULP = 1 + 1/(f128(std::numeric_limits<int64_t>::max()) * 2);

View file

@ -80,22 +80,14 @@ namespace stat {
inline string
format4Csv (VAL const& val)
{
std::ostringstream oss;
oss.precision (std::numeric_limits<VAL>::digits10); /////////////////////////////OOO herausfinden ob hier lexical_cast genügt ==> dann toString()
oss << val;
return oss.str();
}
inline string
format4Csv (string const& val)
{
return '"'+val+'"';
}
inline string
format4Csv (bool boo)
{
return util::showBool(boo); ///////////////////////OOO würde toSting() das korrekt hinbekommen
if constexpr (std::is_floating_point_v<VAL>)
return util::showDecimal (val);
// standard textual rendering
auto res = util::toString (val);
if constexpr (std::is_arithmetic_v<VAL>)
return res; // includes bool
else
return '"'+res+'"';
}
}//(End)Implementation

View file

@ -232,6 +232,54 @@ namespace test{
void
verify_CSV_Format()
{
string line;
double val = 1.0 / 3;
int64_t ii = -100000;
appendCsvField (line, ii);
CHECK (line == "-100000"_expect);
SHOW_EXPR(val)
SHOW_EXPL(val)
SHOW_EXPR(std::to_string(val))
SHOW_EXPR(format4Csv(val));
SHOW_EXPR(util::showDecimal(val))
SHOW_EXPR(util::showComplete(val))
double vval = parseAs<double>(format4Csv(val));
SHOW_EXPR(vval)
SHOW_EXPL(vval)
SHOW_EXPR(std::to_string(vval))
SHOW_EXPR(format4Csv(vval));
SHOW_EXPR(util::showDecimal(val))
SHOW_EXPR(util::showComplete(val))
vval = parseAs<double>(boost::lexical_cast<string>(val));
SHOW_EXPR(vval)
SHOW_EXPL(vval)
SHOW_EXPR(std::to_string(vval))
SHOW_EXPR(format4Csv(vval));
SHOW_EXPR(util::showDecimal(val))
SHOW_EXPR(util::showComplete(val))
bool boo;
SHOW_EXPR(boo);
SHOW_EXPL(boo)
SHOW_EXPR(std::to_string(boo))
SHOW_EXPR(format4Csv(boo));
SHOW_EXPR(format4Csv(-42));
SHOW_EXPR(format4Csv(uint64_t(-42)));
auto moo = f128(1) / 3;
SHOW_EXPR(moo)
SHOW_EXPL(moo)
SHOW_EXPR(std::to_string(moo))
SHOW_EXPR(format4Csv(moo));
SHOW_EXPR(util::showDecimal(moo))
SHOW_EXPR(util::showComplete(moo))
auto oo = 1.0f / 3;
SHOW_EXPR(oo)
SHOW_EXPL(oo)
SHOW_EXPR(std::to_string(oo))
SHOW_EXPR(format4Csv(oo));
SHOW_EXPR(util::showDecimal(oo))
SHOW_EXPR(util::showComplete(oo))
SHOW_EXPR(format4Csv(lib::time::Time(1,2,3,4)));
}

View file

@ -112030,15 +112030,103 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="help"/>
<node CREATED="1710114695652" ID="ID_323709862" MODIFIED="1710114697384" TEXT="std::numeric_limits&lt;VAL&gt;::digits10"/>
<node CREATED="1710114699873" ID="ID_496274436" MODIFIED="1710114711248" TEXT="util::toString sollte lexical_cast verwenden...">
<node CREATED="1710114712306" ID="ID_44388315" MODIFIED="1710114716318" TEXT="pr&#xfc;fen da&#xdf; dem so ist"/>
<node CREATED="1710114717256" ID="ID_894833593" MODIFIED="1710114727188" TEXT="herausfinden was lexical-cast macht"/>
<node COLOR="#5b280f" CREATED="1710114712306" ID="ID_44388315" MODIFIED="1710357726143" TEXT="pr&#xfc;fen da&#xdf; dem so ist">
<icon BUILTIN="button_cancel"/>
<node CREATED="1710357746780" ID="ID_1619668194" MODIFIED="1710357772276" TEXT="ganz im Gegenteil: es gibt eine explizite Spezialisierung in format-object.hpp"/>
<node CREATED="1710357772888" ID="ID_305729821" MODIFIED="1710357794815" TEXT="bewu&#xdf;t eingef&#xfc;hrt, um kompakte und reproduzierbare Test-Ausgaben zu bekommen"/>
<node CREATED="1710357797645" ID="ID_1053198561" MODIFIED="1710357844866" TEXT="die enable_LexicalConversion&lt;N&gt; ist demgegen&#xfc;ber nur ein Fall-back (andere Number-Types)"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1710114730104" ID="ID_1025510498" MODIFIED="1710114735134" TEXT="empirisch vergleichen">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1710114717256" ID="ID_894833593" MODIFIED="1710361721316" TEXT="herausfinden was lexical-cast macht">
<icon BUILTIN="stop-sign"/>
<node CREATED="1710358112019" ID="ID_1362698564" MODIFIED="1710358136409" TEXT="pr&#xfc;ft zun&#xe4;chst ob eine dynamische Konvertierung gemacht werden soll">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
was auch immer das ist....
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1710358137910" ID="ID_681291528" MODIFIED="1710358179069" TEXT="delegiert an boost::detail::lexical_converter_impl&lt;string,double&gt;"/>
<node CREATED="1710362079615" ID="ID_274127702" MODIFIED="1710362103264" TEXT="definiert im Header &lt;boost&gt;/detail/lcast_precision.hpp">
<node CREATED="1710362118642" ID="ID_301368955" MODIFIED="1710362131484" TEXT="in unserem setup verwenden wir eine compile-time-Konstante"/>
<node CREATED="1710362266598" ID="ID_1714052605" MODIFIED="1710362298135" TEXT="im &#xfc;brigen ist der Code ohne weitergehende Analyse praktisch unverst&#xe4;ndlich">
<icon BUILTIN="messagebox_warning"/>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1710362330238" ID="ID_341040992" MODIFIED="1710362904452" STYLE="bubble">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
empirisch(debug) &#10233; <b>17</b>&#160;Stellen
</p>
</body>
</html>
</richcontent>
<edge COLOR="#fdfdda"/>
<linktarget COLOR="#fdfcda" DESTINATION="ID_341040992" ENDARROW="Default" ENDINCLINATION="-296;23;" ID="Arrow_ID_1692132249" SOURCE="ID_897752203" STARTARROW="None" STARTINCLINATION="133;-9;"/>
<icon BUILTIN="idea"/>
</node>
</node>
<node CREATED="1710358827138" ID="ID_1210478674" MODIFIED="1710358834940" TEXT="macht einen sprintf in den buffer">
<node CREATED="1710358837016" ID="ID_1017427931" MODIFIED="1710358852922" TEXT="precision &#x2254; boost::detail::lcast_get_precision&lt;float&gt;()"/>
<node CREATED="1710358853656" ID="ID_1603150290" LINK="https://stackoverflow.com/a/48085309" MODIFIED="1710359148107" TEXT="siehe diese Frage auf Stackoverflow">
<icon BUILTIN="idea"/>
</node>
</node>
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1710361663664" ID="ID_1543853760" MODIFIED="1710361682361" TEXT="das ist ein schwieriges Thema ... jetzt nicht l&#xf6;sbar">
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
<icon BUILTIN="yes"/>
</node>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1710361684252" ID="ID_7817959" MODIFIED="1710361707802" TEXT="#1355 clarify lexical casting">
<icon BUILTIN="hourglass"/>
</node>
</node>
</node>
<node COLOR="#338800" CREATED="1710114730104" ID="ID_1025510498" MODIFIED="1710377768700" TEXT="empirisch vergleichen">
<icon BUILTIN="button_ok"/>
<node CREATED="1710357329987" ID="ID_797995546" MODIFIED="1710357344341" TEXT="Es gibt signifikante Unteschiede">
<icon BUILTIN="idea"/>
</node>
<node CREATED="1710357346265" ID="ID_897752203" MODIFIED="1710362904451" TEXT="lexical_cast &#x27f6; vollst&#xe4;ndige Repr&#xe4;sentation des Bit-Inhalts">
<arrowlink COLOR="#fdfcda" DESTINATION="ID_341040992" ENDARROW="Default" ENDINCLINATION="-296;23;" ID="Arrow_ID_1692132249" STARTARROW="None" STARTINCLINATION="133;-9;"/>
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1710362915878" HGAP="32" ID="ID_1863139074" MODIFIED="1710362961904" TEXT="&#xfc;berpr&#xfc;ft: im Rahmen von lexical_cast reproduzierbar">
<font NAME="SansSerif" SIZE="10"/>
<icon BUILTIN="info"/>
</node>
</node>
<node CREATED="1710357375005" ID="ID_304054334" MODIFIED="1710357413860" TEXT="digits10 &#x27f6; verlustfrei bin&#xe4;r repr&#xe4;sentierbare Dezimalzahl"/>
<node COLOR="#338800" CREATED="1710115014482" ID="ID_1500611682" MODIFIED="1710433302610" TEXT="gekl&#xe4;rt: bool-Format &#x27f6; toString()">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1710361751603" ID="ID_297684858" MODIFIED="1710361783994" TEXT="Formale Analyse zeigt &#x27f9; digits10 ist der richtige Ansatz hier">
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
<icon BUILTIN="yes"/>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1710377772401" ID="ID_96383520" MODIFIED="1710432999927" TEXT="Funktion umschreiben und in das Format-Framework integrieren">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1710433003432" ID="ID_1577076163" MODIFIED="1710433096279" TEXT="neue explizite Format-Funktionen">
<icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1710433012315" ID="ID_1406333897" MODIFIED="1710433101135" TEXT="showDecimal &#x27f6; digits10"/>
<node COLOR="#435e98" CREATED="1710433019043" ID="ID_682588852" MODIFIED="1710433101152" TEXT="showComplete &#x27f6; max_digits10"/>
<node COLOR="#435e98" CREATED="1710433062092" ID="ID_1595196000" MODIFIED="1710433101152" TEXT="auch f&#xfc;r long double">
<icon BUILTIN="idea"/>
</node>
</node>
<node COLOR="#338800" CREATED="1710433074435" ID="ID_1236251004" MODIFIED="1710433095113" TEXT="format4csv : bleibt als generisches front-End">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1710433088707" ID="ID_1543435810" MODIFIED="1710433093241" TEXT="Testabdeckung">
<icon BUILTIN="flag-pink"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1710115014482" ID="ID_1500611682" MODIFIED="1710115023467" TEXT="kl&#xe4;ren: bool-Format">
<icon BUILTIN="flag-yellow"/>
</node>
</node>
<node CREATED="1710351128227" ID="ID_1587957134" MODIFIED="1710351136356" TEXT="Erg&#xe4;nzungen">