I've implemented @Tom Alsberg's suggestion (double
variant). There are caveats (compare output for frac_t == uint32_t
and frac_t == uint64_t
).
#include <iomanip> // setw()
#include <iostream>
#include <limits>
typedef unsigned frac_t;
const frac_t FRACTIONS_PER_SECOND = std::numeric_limits<frac_t>::max();
template <class Uint>
Uint fraction2usec(Uint fraction) {
return static_cast<Uint>(fraction * 1e6 / FRACTIONS_PER_SECOND + 0.5);
}
template <class Uint>
Uint usec2fraction(Uint usec) {
return static_cast<Uint>(usec / 1e6 * FRACTIONS_PER_SECOND + 0.5);
}
int main(void) {
uintmax_t fractions[] = {
0, 1, 0x10c6, 0x10c6f7a0b5edull,
static_cast<uintmax_t>(FRACTIONS_PER_SECOND / 2. + 0.5),
static_cast<uintmax_t>(FRACTIONS_PER_SECOND / 4. + 0.5),
FRACTIONS_PER_SECOND,
FRACTIONS_PER_SECOND + 0x1ull,
};
const int w1 = 2*sizeof(uintmax_t) , w2 = 10;
for (size_t i = 0; i < (sizeof(fractions) / sizeof(*fractions)); ++i)
std::cout << std::hex << std::setw(w1) << fractions[i] << ": "
<< std::dec << std::setw(w2) << fraction2usec(fractions[i])
<< ", " << std::hex << std::setw(w1)
<< usec2fraction(fraction2usec(fractions[i])) << "\n";
}
Output (frac_t == uint32_t
):
0: 0, 0
1: 0, 0
10c6: 1, 10c7
10c6f7a0b5ed: 4294967297, 10c6f7a0b5ee
80000000: 500000, 80000000
40000000: 250000, 40000000
ffffffff: 1000000, ffffffff
100000000: 1000000, ffffffff
Output (frac_t == uint64_t
):
0: 0, 0
1: 0, 0
10c6: 0, 0
10c6f7a0b5ed: 1, 10c6f7a0b5ee
8000000000000000: 500000, 8000000000000000
4000000000000000: 250000, 4000000000000000
ffffffffffffffff: 1000000, 0
0: 0, 0