如何将表示使用时间的32位int转换为32位int,表示时间为秒的二进制分数?

时间:2009-02-15 10:44:49

标签: c++ c embedded

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调用。)

3 个答案:

答案 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_tfrac_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