mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
fix ZAM "cat" of doubles/times to include trailing ".0" per normal BiF behavior
This commit is contained in:
parent
86d1812d49
commit
4cafacf90b
5 changed files with 48 additions and 15 deletions
|
@ -143,12 +143,7 @@ void ODesc::Add(double d, bool no_exp) {
|
|||
|
||||
Add(tmp);
|
||||
|
||||
auto approx_equal = [](double a, double b, double tolerance = 1e-6) -> bool {
|
||||
auto v = a - b;
|
||||
return v < 0 ? -v < tolerance : v < tolerance;
|
||||
};
|
||||
|
||||
if ( approx_equal(d, nearbyint(d), 1e-9) && std::isfinite(d) && ! strchr(tmp, 'e') )
|
||||
if ( util::approx_equal(d, nearbyint(d), 1e-9) && std::isfinite(d) && ! strchr(tmp, 'e') )
|
||||
// disambiguate from integer
|
||||
Add(".0");
|
||||
}
|
||||
|
|
|
@ -534,11 +534,6 @@ void IntervalVal::ValDescribe(ODesc* d) const {
|
|||
bool did_one = false;
|
||||
constexpr auto last_idx = units.size() - 1;
|
||||
|
||||
auto approx_equal = [](double a, double b, double tolerance = 1e-6) -> bool {
|
||||
auto v = a - b;
|
||||
return v < 0 ? -v < tolerance : v < tolerance;
|
||||
};
|
||||
|
||||
for ( size_t i = 0; i < units.size(); ++i ) {
|
||||
auto unit = units[i].first;
|
||||
auto word = units[i].second;
|
||||
|
@ -547,7 +542,7 @@ void IntervalVal::ValDescribe(ODesc* d) const {
|
|||
if ( i == last_idx ) {
|
||||
to_print = v / unit;
|
||||
|
||||
if ( approx_equal(to_print, 0) ) {
|
||||
if ( util::approx_equal(to_print, 0, 1e-6) ) {
|
||||
if ( ! did_one )
|
||||
d->Add("0 secs");
|
||||
|
||||
|
@ -571,7 +566,7 @@ void IntervalVal::ValDescribe(ODesc* d) const {
|
|||
d->SP();
|
||||
d->Add(word);
|
||||
|
||||
if ( ! approx_equal(to_print, 1) && ! approx_equal(to_print, -1) )
|
||||
if ( ! util::approx_equal(to_print, 1, 1e-6) && ! util::approx_equal(to_print, -1, 1e-6) )
|
||||
d->Add("s");
|
||||
|
||||
did_one = true;
|
||||
|
|
|
@ -68,10 +68,18 @@ void FixedCatArg::RenderInto(ZVal* zframe, int slot, char*& res) {
|
|||
break;
|
||||
|
||||
case TYPE_DOUBLE:
|
||||
case TYPE_TIME:
|
||||
n = modp_dtoa2(z.AsDouble(), res, 6);
|
||||
case TYPE_TIME: {
|
||||
auto d = z.AsDouble();
|
||||
n = modp_dtoa2(d, res, 6);
|
||||
res += n;
|
||||
|
||||
if ( util::approx_equal(d, nearbyint(d), 1e-9) && std::isfinite(d) && ! strchr(tmp, 'e') ) {
|
||||
// disambiguate from integer
|
||||
*(res++) = '.';
|
||||
*(res++) = '0';
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_PATTERN:
|
||||
text = z.AsPattern()->AsPattern()->PatternText();
|
||||
|
|
26
src/util.cc
26
src/util.cc
|
@ -2550,6 +2550,32 @@ TEST_CASE("util split") {
|
|||
}
|
||||
}
|
||||
|
||||
TEST_CASE("util approx_equal") {
|
||||
CHECK(approx_equal(47.0, 47.0) == true);
|
||||
CHECK(approx_equal(47.0, -47.0) == false);
|
||||
CHECK(approx_equal(47.00001, 47.00002) == false);
|
||||
CHECK(approx_equal(47.00001, 47.00002, 1e-5) == true);
|
||||
CHECK(approx_equal(47.0, -47.0, 1e2) == true);
|
||||
CHECK(approx_equal(47.0, -47.0, 94 + 1e-10) == true);
|
||||
CHECK(approx_equal(47.0, -47.0, 94) == false);
|
||||
|
||||
constexpr auto inf = std::numeric_limits<double>::infinity();
|
||||
CHECK_FALSE(approx_equal(inf, inf));
|
||||
CHECK_FALSE(approx_equal(-inf, inf));
|
||||
CHECK_FALSE(approx_equal(inf, -inf));
|
||||
CHECK_FALSE(approx_equal(inf, inf, inf));
|
||||
|
||||
constexpr auto qnan = std::numeric_limits<double>::quiet_NaN(); // There's also `signaling_NaN`.
|
||||
CHECK_FALSE(approx_equal(qnan, qnan));
|
||||
CHECK_FALSE(approx_equal(-qnan, qnan));
|
||||
CHECK_FALSE(approx_equal(qnan, -qnan));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether two double values are approximately equal within some tolerance value.
|
||||
*/
|
||||
bool approx_equal(double a, double b, double tolerance) { return std::abs(a - b) < std::abs(tolerance); }
|
||||
|
||||
} // namespace zeek::util
|
||||
|
||||
extern "C" void out_of_memory(const char* where) {
|
||||
|
|
|
@ -571,6 +571,15 @@ std::string json_escape_utf8(const std::string& val, bool escape_printable_contr
|
|||
*/
|
||||
std::string json_escape_utf8(const char* val, size_t val_size, bool escape_printable_controls = true);
|
||||
|
||||
/**
|
||||
* Checks for values that are approximately equal.
|
||||
* @param a first value to compare
|
||||
* @param b second value to compare
|
||||
* @param tolerance how close they need to be to deem them "approximately equal"
|
||||
* @return true if `a` is within the given tolerance of `b`, false otherwise
|
||||
*/
|
||||
bool approx_equal(double a, double b, double tolerance = std::numeric_limits<double>::epsilon());
|
||||
|
||||
/**
|
||||
* Splits a string at all occurrences of a delimiter. Successive occurrences
|
||||
* of the delimiter will be split into multiple pieces.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue