Skip to content

Commit

Permalink
[sigrokproject#71] Fix rounding issues that make the tests fail
Browse files Browse the repository at this point in the history
  • Loading branch information
Giles314 committed Aug 4, 2024
1 parent eeb33a6 commit 791eec0
Showing 1 changed file with 18 additions and 7 deletions.
25 changes: 18 additions & 7 deletions pv/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,11 +199,21 @@ static QString pad_number(unsigned int number, int length)

QString format_time_minutes(const Timestamp& t, signed precision, bool sign)
{
const Timestamp whole_seconds = floor(abs(t));
const Timestamp days = floor(whole_seconds / (60 * 60 * 24));
const unsigned int hours = fmod(whole_seconds / (60 * 60), 24).convert_to<uint>();
const unsigned int minutes = fmod(whole_seconds / 60, 60).convert_to<uint>();
const unsigned int seconds = fmod(whole_seconds, 60).convert_to<uint>();
// Add the maximum representation error left by the last displayed digit
// so we can call floor for all computed values so that we never get 24 hours or 60 seconds
// but still avoiding adding half precision error :
// 0.9 for last digit will still be represented as 1 because 0.5 have been added before calling floor
const Timestamp abs_t_and_floor_margin = abs(t) + ldexp(Timestamp(0.1), std::max(0, precision)) * 0.5;
// Do integer computation it will be faster. Also limit number of divisions (and modulos).
// Note: unsigned longs (with at least 32 bits) can store at least 136 years of seconds. Should be enough...
const unsigned long whole_seconds = floor(abs_t_and_floor_margin).convert_to<unsigned long>();
const unsigned long days = std::floor(whole_seconds / (60 * 60 * 24));
unsigned long remain_seconds = whole_seconds - days * (60 * 60 * 24);
// int (with at least 16 bits) are still sufficient for remaining parts
const unsigned int hours = (unsigned int)std::floor(remain_seconds / (60 * 60));
remain_seconds -= hours * (60 * 60);
const unsigned int minutes = (unsigned int)std::floor(remain_seconds / 60);
const unsigned int seconds = (unsigned int)(remain_seconds - minutes * 60);

QString s;
QTextStream ts(&s);
Expand All @@ -217,7 +227,8 @@ QString format_time_minutes(const Timestamp& t, signed precision, bool sign)

// DD
if (days) {
ts << days.str().c_str() << ":";
ts << days << ":";
ts << pad_number(hours, use_padding ? 2 : 0) << ":";
use_padding = true;
}

Expand All @@ -238,7 +249,7 @@ QString format_time_minutes(const Timestamp& t, signed precision, bool sign)
if (precision) {
ts << ".";

const Timestamp fraction = fabs(t) - whole_seconds;
const Timestamp fraction = abs(t) - floor(abs(t));

ostringstream ss;
ss << fixed << setprecision(precision) << setfill('0') << fraction;
Expand Down

0 comments on commit 791eec0

Please sign in to comment.