namespace pv {
namespace util {
-static const QString SIPrefixes[17] = {
- "y", "z",
- "a", "f", "p",
- "n", QChar(0x03BC), "m",
- "",
- "k", "M", "G",
- "T", "P", "E",
- "Z", "Y"};
-const int EmptySIPrefix = 8;
-const int FirstSIPrefixPower = -(EmptySIPrefix * 3);
-const double MinTimeDelta = 1e-15; // Anything below 1 fs can be considered zero
+static QTextStream& operator<<(QTextStream& stream, SIPrefix prefix)
+{
+ switch (prefix) {
+ case SIPrefix::yocto: return stream << 'y';
+ case SIPrefix::zepto: return stream << 'z';
+ case SIPrefix::atto: return stream << 'a';
+ case SIPrefix::femto: return stream << 'f';
+ case SIPrefix::pico: return stream << 'p';
+ case SIPrefix::nano: return stream << 'n';
+ case SIPrefix::micro: return stream << QChar(0x03BC);
+ case SIPrefix::milli: return stream << 'm';
+ case SIPrefix::kilo: return stream << 'k';
+ case SIPrefix::mega: return stream << 'M';
+ case SIPrefix::giga: return stream << 'G';
+ case SIPrefix::tera: return stream << 'T';
+ case SIPrefix::peta: return stream << 'P';
+ case SIPrefix::exa: return stream << 'E';
+ case SIPrefix::zetta: return stream << 'Z';
+ case SIPrefix::yotta: return stream << 'Y';
+
+ default: return stream;
+ }
+}
+
+int exponent(SIPrefix prefix)
+{
+ return 3 * (static_cast<int>(prefix) - static_cast<int>(SIPrefix::none));
+}
+
+static SIPrefix successor(SIPrefix prefix)
+{
+ assert(prefix != SIPrefix::yotta);
+ return static_cast<SIPrefix>(static_cast<int>(prefix) + 1);
+}
// Insert the timestamp value into the stream in fixed-point notation
// (and honor the precision)
return stream << QString::fromStdString(str);
}
-QString format_si_value(const Timestamp& v, QString unit, int prefix,
+QString format_si_value(const Timestamp& v, QString unit, SIPrefix prefix,
unsigned int precision, bool sign)
{
- if (prefix < 0) {
+ if (prefix == SIPrefix::unspecified) {
// No prefix given, calculate it
if (v.is_zero()) {
- prefix = EmptySIPrefix;
+ prefix = SIPrefix::none;
} else {
- int exp = -FirstSIPrefixPower;
-
- prefix = 0;
- while ((fabs(v) * pow(10.0, exp)) > 999.0 &&
- prefix < (int)(countof(SIPrefixes) - 1)) {
- prefix++;
+ int exp = exponent(SIPrefix::yotta);
+ prefix = SIPrefix::yocto;
+ while ((fabs(v) * pow(Timestamp(10), exp)) > 999 &&
+ prefix < SIPrefix::yotta) {
+ prefix = successor(prefix);
exp -= 3;
}
}
}
- assert(prefix >= 0);
- assert(prefix < (int)countof(SIPrefixes));
+ assert(prefix >= SIPrefix::yocto);
+ assert(prefix <= SIPrefix::yotta);
- const Timestamp multiplier = pow(Timestamp(10),
- (int)- prefix * 3 - FirstSIPrefixPower);
+ const Timestamp multiplier = pow(Timestamp(10), -exponent(prefix));
QString s;
QTextStream ts(&s);
<< qSetRealNumberPrecision(precision)
<< (v * multiplier)
<< ' '
- << SIPrefixes[prefix]
+ << prefix
<< unit;
return s;
return QString("%1").arg(number, length, 10, QChar('0'));
}
-static QString format_time_in_full(double t, signed precision)
+static QString format_time_in_full(const Timestamp& t, signed precision)
{
- const unsigned int whole_seconds = abs((int) t);
- const unsigned int days = whole_seconds / (60 * 60 * 24);
- const unsigned int hours = (whole_seconds / (60 * 60)) % 24;
- const unsigned int minutes = (whole_seconds / 60) % 60;
- const unsigned int seconds = whole_seconds % 60;
+ 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>();
QString s;
QTextStream ts(&s);
bool use_padding = false;
if (days) {
- ts << days << ":";
+ ts << days.str().c_str() << ":";
use_padding = true;
}
if (precision >= 0) {
ts << pad_number(seconds, use_padding ? 2 : 0);
- const double fraction = fabs(t) - whole_seconds;
+ const Timestamp fraction = fabs(t) - whole_seconds;
if (precision > 0 && precision < 1000) {
- QString fs = QString("%1").arg(fraction, -(2 + precision), 'f',
- precision, QChar('0'));
+ std::ostringstream ss;
+ ss
+ << std::fixed
+ << std::setprecision(2 + precision)
+ << std::setfill('0')
+ << fraction;
+ std::string fs = ss.str();
ts << ".";
// Start at index 2 to skip the "0." at the beginning
ts << fs[1 + i];
- if ((i > 0) && (i % 3 == 0))
+ if ((i > 0) && (i % 3 == 0) && (i != precision))
ts << " ";
}
}
return s;
}
-static QString format_time_with_si(double t, QString unit, int prefix,
- unsigned int precision)
+static QString format_time_with_si(const Timestamp& t, QString unit,
+ SIPrefix prefix, unsigned int precision)
{
// The precision is always given without taking the prefix into account
// so we need to deduct the number of decimals the prefix might imply
- const int prefix_order =
- -(prefix * 3 + pv::util::FirstSIPrefixPower);
+ const int prefix_order = -exponent(prefix);
const unsigned int relative_prec =
- (prefix >= EmptySIPrefix) ? precision :
+ (prefix >= SIPrefix::none) ? precision :
std::max((int)(precision - prefix_order), 0);
return format_si_value(t, unit, prefix, relative_prec);
}
-static QString format_time(double t, int prefix, TimeUnit unit, unsigned int precision)
+QString format_time(const Timestamp& t, SIPrefix prefix, TimeUnit unit,
+ unsigned int precision)
{
// Make 0 appear as 0, not random +0 or -0
- if (fabs(t) < MinTimeDelta)
+ if (t.is_zero())
return "0";
// If we have to use samples then we have no alternative formats
- if (unit == Samples)
+ if (unit == TimeUnit::Samples)
return format_time_with_si(t, "sa", prefix, precision);
// View in "normal" range -> medium precision, medium step size
return format_time_in_full(t, precision);
}
-QString format_time(const Timestamp& t, int prefix, TimeUnit unit, unsigned int precision)
-{
- return format_time(t.convert_to<double>(), prefix, unit, precision);
-}
-
QString format_second(const Timestamp& second)
{
- return format_si_value(second, "s", -1, 0, false);
+ return format_si_value(second, "s", SIPrefix::unspecified, 0, false);
}
} // namespace util