POSIX使用struct timeval
来表示时间间隔。
struct timeval
{
time_t tv_sec;
unsigned tv_usec;
};
GHS Integrity以下列方式代表Time
,
struct Time
{
time_t Seconds;
unsigned Fraction;
};
例如,0.5秒表示为0x80000000
,0.25秒表示为0x40000000
。
从timeval
转换为Time
的最佳方式是什么?
(p.s。答案不是将POSIX库链接到Integrity并使用POSIX调用。)
答案 0 :(得分:5)
这是一种代表时间的不寻常方式。
无论如何,如果你有64位整数或浮点(前者更有可能在嵌入式系统上),有两种简单的方法可以做到这一点:
/* assuming long is 64-bit and int is 32-bit
or in general long twice the size of int: */
Fraction = (long) tv_usec * UINT_MAX / 1000000 /* usecs to fraction */
tv_usec = (long) Fraction * 1000000 / UINT_MAX /* fraction to usecs */
/* assuming floating points are available: */
Fraction = tv_usec * ((double) UINT_MAX / 1000000) /* usecs to fraction */
tv_usec = Fraction * ((double) 1000000 / UINT_MAX) /* fraction to usecs */
显然两者都只是整数近似值,因为一个尺度中的大多数值不能在另一个尺度中表示为整数。在一个方向上,您可能会失去一些精度,因为Fraction
形式可以表示更精细的时间 - Fraction
形式的一个增量小于0.00024微秒。但是,只有当你的计时器能够实际测量那些不太可能的值时 - 大多数计时器甚至无法以微秒级进行测量,并且你在tv_usec
中看到的值通常是四舍五入的。
如果64位整数和浮点都不是可用的选项,则可以使用额外的变量迭代地执行。我正在考虑是否有更简单(并且更便宜,考虑到这是时序代码)的方式进行这样的缩放比做等效的迭代64位乘法和除法有两个32位整数。在我想到的两个想法中,一个人不会做出精确的均衡缩放,并且可能产生最多9位的结果,并且补偿的结果不会更便宜。如果我想到了新的东西,我会在这里发布,但这是一个有趣的挑战。有没有其他人有一个好的算法或片段?也许借助一张小型预先计算的桌子?
答案 1 :(得分:0)
您可能想要了解浮点表示,因为Fraction似乎是有效数字的第一位。
Time t;
u64 s = 1000000 * t.Seconds +
u64(1000000 * reinterpret_cast<double>(0x3FF0000000000000|((u64)t.Fraction>>12)))
timeval tv;
tv.tv_sec = s / 1000000
tv.tv_usec = s % 1000000
这是foobar但它真的有用......你需要64位整数和双浮点。
答案 2 :(得分:0)
我已经实施了@Tom Alsberg的建议(double
变体)。有警告(比较frac_t == uint32_t
和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";
}
输出(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
输出(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