gpt4 book ai didi

c - timeval_subtract说明

转载 作者:太空狗 更新时间:2023-10-29 15:52:44 25 4
gpt4 key购买 nike

有了“timeval_subtract”函数来查找两种结构timeval类型之间经过的时间,有人能解释一下“通过更新y来执行后续减法的进位”和其他部分的目的和步骤吗?我了解函数的目的以及如何在程序中实现它,但我想了解它在程序中是如何工作的,而且在任何地方都找不到任何解释,而且我似乎无法理解它。

int timeval_subtract (struct timeval *result, struct timeval *x,struct timeval  *y)  
{
/* Perform the carry for the later subtraction by updating y. */
if (x->tv_usec < y->tv_usec) {
int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
y->tv_usec -= 1000000 * nsec;
y->tv_sec += nsec;
}
if (x->tv_usec - y->tv_usec > 1000000) {
int nsec = (y->tv_usec - x->tv_usec) / 1000000;
y->tv_usec += 1000000 * nsec;
y->tv_sec -= nsec;
}

/* Compute the time remaining to wait.
tv_usec is certainly positive. */
result->tv_sec = x->tv_sec - y->tv_sec;
result->tv_usec = x->tv_usec - y->tv_usec;

/* Return 1 if result is negative. */
return x->tv_sec < y->tv_sec;
}

它是一个与gnu c库相关的函数,用于确定经过的时间 http://www.gnu.org/software/libc/manual/html_node/Elapsed-Time.html,因此我不想寻找改进,而只是解释为什么在它内部进行除法、加法、减法和乘法。这些具体的算术运算是如何实现的?/为什么要做/不做?我已经完成了这一步,但我仍然无法理解。我将继续这样做,直到我这样做(甚至在有人向我解释之后),但我希望从一个已经理解它的人那里得到一些见解。这个平台是unix,我刚开始使用它,但我认为它不会改变函数内部正在进行的操作。这更多的是关于正在执行的算法而不是正在使用的算法的问题。

最佳答案

乍一看,它似乎包含了一个分成两部分的时间:
struct timeval-微秒,理想情况下应该始终小于1000000,但代码建议允许更大的值
tv_usec-秒(1000000的倍数)
以微秒为单位的时间是1000000。
相反,人们会认为这是真的:
tv_sec=以微秒为单位的时间/1000000
tv_usec=以微秒为单位的时间%1000000。
该函数用于计算tv_sectv_sec之间的时差(逻辑上为tv_usec-*x),并将其存储在另一个*y*x中。
一个简单的测试程序给了我们一些提示:

#include <stdio.h>

struct timeval
{
long tv_sec;
long tv_usec;
};

int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y)
{
// preserve *y
struct timeval yy = *y;
y = &yy;

/* Perform the carry for the later subtraction by updating y. */
if (x->tv_usec < y->tv_usec) {
int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
y->tv_usec -= 1000000 * nsec;
y->tv_sec += nsec;
}
if (x->tv_usec - y->tv_usec > 1000000) {
int nsec = (y->tv_usec - x->tv_usec) / 1000000;
y->tv_usec += 1000000 * nsec;
y->tv_sec -= nsec;
}

/* Compute the time remaining to wait.
tv_usec is certainly positive. */
result->tv_sec = x->tv_sec - y->tv_sec;
result->tv_usec = x->tv_usec - y->tv_usec;

/* Return 1 if result is negative. */
return x->tv_sec < y->tv_sec;
}

struct timeval testData00 = { 0, 0 };
struct timeval testData01 = { 0, 1 };

int main(void)
{
struct timeval diff;
int res;

res = timeval_subtract(&diff, &testData00, &testData00);
printf("%d %ld:%ld\n", res, diff.tv_sec, diff.tv_usec);

res = timeval_subtract(&diff, &testData01, &testData01);
printf("%d %ld:%ld\n", res, diff.tv_sec, diff.tv_usec);

res = timeval_subtract(&diff, &testData01, &testData00);
printf("%d %ld:%ld\n", res, diff.tv_sec, diff.tv_usec);

res = timeval_subtract(&diff, &testData00, &testData01);
printf("%d %ld:%ld\n", res, diff.tv_sec, diff.tv_usec);

return 0;
}

输出( ideone):
0 0:0
0 0:0
0 0:1
1 -1:999999

从上一个测试结果来看,函数返回(-1):999999而不是-(0:1)。两个值表示相同的负时间(或时间差),单位为微秒:
-1*1000000+999999=-1个
-(0*1000000+1)=-1
那么,它到底是如何工作的呢?
如果 *y= struct timeval那么只有第二个 *result可能执行:
  if (x->tv_usec - y->tv_usec > 1000000) {  
int nsec = (y->tv_usec - x->tv_usec) / 1000000;
y->tv_usec += 1000000 * nsec;
y->tv_sec -= nsec;
}

这将检查微秒部分的差异是否大于1秒。如果是,则它从 x->tv_usec(以微秒计)中减去此差的整秒,并将其添加到 y->tv_usec(以秒计)。这只是在 if中重新分配时间,而没有真正更改它。你可以像这样重写这个 if来更清楚地看到它:
  if (x->tv_usec - y->tv_usec > 1000000) {  
int nsec = (x->tv_usec - y->tv_usec) / 1000000;
y->tv_usec -= 1000000 * nsec;
y->tv_sec += nsec;
}

这里要注意的一件重要事情是,当输入 y->tv_usecy->tv_sec*y在0到999999(包括0到999999)范围内时,这个 if的主体不会执行(因此,当 *x= *ytv_usec在0到999999范围内时,*实际上可能永远不会执行)。
现在还不清楚这个 if的净效应。
然而,这里可以看到一件有趣的事情。如果我们用 x->tv_usec=0:1000001和 y->tv_usec=0:0调用这个函数,结果将是错误的: difference = (-1):2000001 (instead of 1:1) and the return value of the function = 1 (instead of 0)。这表明该函数并不真正适合于 tv_usecs甚至 if。因为这个行为,我要声明这个函数也不适合输入中的负 *x。面对这种行为,我将忽略这些案件。看起来已经够不对了。
让我们看看第一个 *y
  /* Perform the carry for the later subtraction by updating y. */  
if (x->tv_usec < y->tv_usec) {
int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
y->tv_usec -= 1000000 * nsec;
y->tv_sec += nsec;
}

正如注释和代码所示,当我们需要处理“数字”之间的“进位”时,就好像我们是在加而不是减。但没关系,我们会看到的。
我们回学校呆一会儿吧。
你怎么做37-12?
你这样做:
7 - 2 = 5
3 - 1 = 2

所以37-12=25。
现在,57-38怎么样?
你这样做:
10/*because 7 < 8*/ + 7 - 8 = 9
5 - 3 - 1/*borrow, because of the above*/ = 1

所以57-38=19。看到了吗?
还有支票:
  if (x->tv_usec < y->tv_usec) {  

检查我们是否需要处理这笔借款。
那么,这里发生了什么?让我们再看看:
  if (x->tv_usec < y->tv_usec) {  
int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
y->tv_usec -= 1000000 * nsec;
y->tv_sec += nsec;
}

如果 tv_usec > 1000000 tv_usec > 999999,它以整秒计算两者之间的差异,就像另一个 tv_usec一样,它将这些整秒相加,然后从 if中减去它们,只需在 x->tv_usec中重新分配时间,而不改变它。
在函数( y->tv_usec)的末尾,将从 y->tv_usec中减去最后加到 x->tv_usec中的额外的一个( if),因此这1作为我刚才在57-38=19示例中提醒您的借阅函数。
除了借钱和重新分配时间之外,这里还发生了什么?
就像我之前说的,我只会忽略负 y->tv_sec和大于999999,因为可能处理不正确。
这样,我将 y->tv_usec设为0,只剩下真正有意义的值 *y(包括0到999999)。
所以,如果 + 1条件是真的,我基本上是从 y->tv_sec中减去1000000,然后加上1(借)。
这和57-38=19时一样:
10/*because 7 < 8*/ + 7 - 8 = 9
5 - 3 - 1/*borrow, because of the above*/ = 1

与此类似,1000000将在稍后的此处添加: x->tv_sec
这第一个 result->tv_sec = x->tv_sec - y->tv_sec;是这个函数的核心。
如果我必须编写一个具有类似行为的函数,我将要求输入时间为非负,微秒部分不大于999999,我将只编写以下内容:
int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y)
{
result->tv_sec = x->tv_sec - y->tv_sec;

if ((result->tv_usec = x->tv_usec - y->tv_usec) < 0)
{
result->tv_usec += 1000000;
result->tv_sec--; // borrow
}

return result->tv_sec < 0;
}

如果出于某种奇怪的原因,我想在输入中支持999999,我会首先将多余的从 tv_usecs移动到 (y->tv_usec - x->tv_usec) / 1000000然后执行上述操作,如下所示:
int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y)
{
struct timeval xx = *x;
struct timeval yy = *y;
x = &xx; y = &yy;

if (x->tv_usec > 999999)
{
x->tv_sec += x->tv_usec / 1000000;
x->tv_usec %= 1000000;
}

if (y->tv_usec > 999999)
{
y->tv_sec += y->tv_usec / 1000000;
y->tv_usec %= 1000000;
}

result->tv_sec = x->tv_sec - y->tv_sec;

if ((result->tv_usec = x->tv_usec - y->tv_usec) < 0)
{
result->tv_usec += 1000000;
result->tv_sec--; // borrow
}

return result->tv_sec < 0;
}

在这里,目的很明确,代码也很容易理解。

关于c - timeval_subtract说明,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15846762/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com