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:
parent
01a098db99
commit
3b3600379a
8 changed files with 203 additions and 45 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -112030,15 +112030,103 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<icon BUILTIN="help"/>
|
||||
<node CREATED="1710114695652" ID="ID_323709862" MODIFIED="1710114697384" TEXT="std::numeric_limits<VAL>::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üfen daß 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üfen daß 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ßt eingeführt, um kompakte und reproduzierbare Test-Ausgaben zu bekommen"/>
|
||||
<node CREATED="1710357797645" ID="ID_1053198561" MODIFIED="1710357844866" TEXT="die enable_LexicalConversion<N> ist demgegenü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üft zunä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<string,double>"/>
|
||||
<node CREATED="1710362079615" ID="ID_274127702" MODIFIED="1710362103264" TEXT="definiert im Header <boost>/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 übrigen ist der Code ohne weitergehende Analyse praktisch unverstä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) ⟹ <b>17</b> 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 ≔ boost::detail::lcast_get_precision<float>()"/>
|
||||
<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ö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 ⟶ vollständige Reprä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="überprü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 ⟶ verlustfrei binär repräsentierbare Dezimalzahl"/>
|
||||
<node COLOR="#338800" CREATED="1710115014482" ID="ID_1500611682" MODIFIED="1710433302610" TEXT="geklärt: bool-Format ⟶ toString()">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1710361751603" ID="ID_297684858" MODIFIED="1710361783994" TEXT="Formale Analyse zeigt ⟹ 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 ⟶ digits10"/>
|
||||
<node COLOR="#435e98" CREATED="1710433019043" ID="ID_682588852" MODIFIED="1710433101152" TEXT="showComplete ⟶ max_digits10"/>
|
||||
<node COLOR="#435e98" CREATED="1710433062092" ID="ID_1595196000" MODIFIED="1710433101152" TEXT="auch fü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ären: bool-Format">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1710351128227" ID="ID_1587957134" MODIFIED="1710351136356" TEXT="Ergänzungen">
|
||||
|
|
|
|||
Loading…
Reference in a new issue