2009-02-15 94 views
1

POSIX使用struct timeval来表示时间间隔。如何从一个32位的int表示timec中的时间转换为一个32位的int表示时间的二进制小数(以秒为单位)?

struct timeval 
{ 
    time_t tv_sec; 
    unsigned tv_usec; 
}; 

GHS完整性表示以下述方式Time

struct Time 
{ 
    time_t Seconds; 
    unsigned Fraction; 
}; 

例如,0.5秒被表示为0x80000000和0.25sec被表示为0x40000000

什么是从timeval转换为Time的最佳方法?

(附:答案是没有的POSIX库链接到诚信和使用POSIX调用。)

回答

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位整数也没有浮点可用的选项,你可以用一个额外的变量迭代地做到这一点。我在考虑是否有一种更简单(并且考虑到这是计时代码的更便宜的方法)来做这样的缩放,而不是做相当于用两个32位整数进行迭代64位乘法和除法的方式。在我想到的两个想法中,人们不会做甚至缩放,甚至可能产生高达9位的结果,而补偿的结果不会更便宜。如果在我脑海里出现新的东西,我会在这里发布,但这是一个有趣的挑战。其他人有没有一个好的算法或片段?也许在预先计算好的小桌子的帮助下?

+0

如果浮点中间不正常,但在64位整数是,为什么不乘以第一和然后呢? – mghie 2009-02-15 10:57:55

+0

对,我正要补充一点,但后来我的脑海里想要实现32位整数缩放 – 2009-02-15 11:09:06

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位整数和双浮点数。

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 
相关问题