在C语言中测量经过的时间 - 纳秒 - 浮点数转换

3
我想要测量两个事件之间的时间持续时间,比如在不同时间点捕获CPU快照。 在将其乘以1000000000L之后,是否需要进行float转换?这样做正确吗?
float get_elapsed(domain_info *dom) {
    
    float temp;

    temp = (float)((dom->t2.tv_sec - dom->t1.tv_sec) * 1000000000L + (dom->t2.tv_nsec - dom->t1.tv_nsec);

    return temp;
}

2
作为一个经验法则,你本来就不应该使用float来表示浮点类型。 - undefined
3
如果需要浮点类型,建议使用双精度。 - undefined
2
假设struct timeval的POSIX定义(我认为t1t2是这样的),那么它们都是整数,结果也是整数。整数结果可以隐式转换为浮点数值(小数部分为零)。因此,不需要显式转换。实际上,也不需要使用浮点数类型。 - undefined
1
@AllanWind 对不起,我当然是指 struct timespec 而不是 struct timeval - undefined
3
不相关的,但我更倾向于传递两个const struct timespec *,而不是domain_info是什么。这样可以记录实际的数据依赖关系,并且您可以得到一个在其他情境中也有用的更通用的函数。 - undefined
显示剩余7条评论
2个回答

3
我们不知道typedef struct {} domain_info是什么意思,而且这个表达式的括号不匹配,所以无法编译通过。让我们假设你的意思是:
#include <time.h>

typedef struct {
    struct timespec t1;
    struct timespec t2;
} domain_info;

float get_elapsed(domain_info *dom){
    return (float)((dom->t2.tv_sec - dom->t1.tv_sec) * 1000000000L +(dom->t2.tv_nsec - dom->t1.tv_nsec));
}

int main(void) {
    // ...
}

编译器会自动将表达式转换为浮点数,因此您不需要显式转换或临时变量。
在我的系统中,tv_sec是一个64位的长整型,但如果它是32位的,那么在(dom->t2.tv_sec - dom->t1.tv_sec)溢出之前,您只有几秒钟的差值。如果它是有符号类型,就像在我的系统上一样,这是未定义的行为。
为了提高精度,建议使用双精度(double)而不是单精度(float),因为您将tv_sec按照因子1000000000L进行缩放,并且还对tv_nsec中的差值感兴趣。

如果t1t2相隔几纳秒,甚至相隔数千纳秒,你需要在时间中具有纳秒分辨率,这样当你相减时,才能得到准确的差异。如果t1t2相隔很多秒,纳秒可能并不重要。此外,即使t1t2只相隔几纳秒,你也需要秒数,因为在t1t2之间纳秒与秒之间可能会发生溢出的情况... - undefined
@EricPostpischil 我理解你关于它是持续时间的观点,也许我很傻,但在10到100的范围内,我不相信基于时间的(微)基准测试。只是以不同的方式重新陈述我之前说过的话(带有粗糙的C语言/数学):如果 (float) (delta_sec * 10^9 + delta_nsec) - delta_sec * 10^9 只给我大约 10^-3 的精度,那么使用纳秒就没有意义,我会称之为一个错误。我可能还是遗漏了一些重要的东西。 - undefined
@EricPostpischil 当你进行基准测试时,你是在比较多个实验,对吧?t(exeriment1)和t(experiment2),所以你是在比较它们,你是通过将一个减去另一个(/ t(experiemtn1))来做到这一点。假设t(exeriment1)是100秒,也就是100 * 1000000000L,在我的系统上是浮点数99999997952.0,然后对于t2,我做t1 + delta,并寻找t1和t2不同的第一个delta。结果是大约4096纳秒,所以如果你的实验相差不超过4毫秒,你就无法分辨。我得出结论,浮点数不适用。如果你用双精度浮点数进行相同的练习,分辨率是1纳秒。 - undefined
@EricPostpischil 努力理解(尤其是如果我错了)。 - undefined
1
在进行任何算术运算之前,典型程序执行时间的测量误差超过4096纳秒。执行时间会因为热量、多进程需求、设备中断、系统定时器等因素而波动。如果你想提出某人可能会如此精确地测量执行时间的论点,那没问题,他们需要更高的精度。但这与我的观点无关,即OP很可能在最终结果中不需要如此精确的测量。 - undefined
显示剩余6条评论

0

长的宽度够吗?

(dom->t2.tv_sec - dom->t1.tv_sec) * 1000000000Llongtime_t为32位时会出现问题。

相反,确保进行更宽的数学计算。

<stdint.h>提供了至少具有所需位宽的宏。

(dom->t2.tv_sec - dom->t1.tv_sec) * INT64_C(1000000000)

现在乘法至少是64位的。


需要将其转换为float吗?
通常情况下,默认的浮点类型是double。如果希望返回浮点类型,进行转换可以消除转换警告,并且在这里是一种良好的做法。
  • 对于引用的数据,最好使用const,因为它不会被此函数更改,这样调用代码可以传递指向const数据的指针。
double get_elapsed(const domain_info *dom){
  return (double) (//
      (dom->t2.tv_sec - dom->t1.tv_sec) * INT64_C(1000000000) + //
      (dom->t2.tv_nsec - dom->t1.tv_nsec));
}

1
TIL INT64_C() - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接