【问题标题】:Negative numbers with time count带时间计数的负数
【发布时间】:2013-12-11 19:57:55
【问题描述】:

我想知道为什么我尝试使用多种数据类型(float、double long double 等)得到负值,但结果是..或其负数或零或 NA。这是一个检查商店中客户的中间服务时间的功能,我只发布了问题代码的相关部分。提前提

struct timeval timecount[MAX_COSTUMERS+1][2];

long double getMedium(struct timeval x[][2]){
      long double diff;
      int i;
      for(i=1;i<k.clientID;i++){
          diff+= ((x[i][1].tv_usec )*0.0000001 -  (x[i][0].tv_usec)*0.0000001) ) ;
      }

      return diff;
}

void AFUNCTION(){  // Called a bunch of times
       k.clientID++;
       gettimeofday(&timecount[k.clientID][0], NULL);

   // DO A BUNCH OF STUFF


       gettimeofday(&timecount[k.clientID][1], NULL);


}

void main ( ) {

     long double aux;
     aux=getMedia(timecount);
     printf("%LG \n",aux);

}

【问题讨论】:

  • getMedia 的调用应该是getMedium 还是不同的函数? diff 累加表达式中的括号不匹配,因此这不是真正的代码 - 我们可能正在解决您没有的问题;如果我们能看到真正的代码,就没有!
  • 字段tv_usec 可能是long0.0000001 肯定是 double。所以diff += ... 的右边可能只能用double 精度数学来完成。然而代码与long double 一起累积。考虑0.0000001L 以获得统一的精度。

标签: c shell unix time


【解决方案1】:

问题是你没有将dif初始化为0。那里有垃圾数据......

double getMedium(struct timeval x[][2]){
  double diff =0;
  int i;
  for(i=1;i<k.clientID;i++){
      diff+= ((x[i][1].tv_usec )*0.0000001 -  (x[i][0].tv_usec)*0.0000001) ) ;
  }

  return diff;
}

【讨论】:

  • @Noize 这实际上甚至不应该编译有一个额外的 ) 在 diff 行。
  • @Noize 有什么阻止你做(x[i][1].tv_usec - x[i][0].tv_usec)*0.0000001?在数学上它们是相同的,但在计算上稍微更有效。此外,如果您认为 diff 的计算错误,一两个 printf 会很快告诉您问题出在哪里...
  • @nonsensickle:最好在循环的外部累加并除以 1.0e6。如果在几秒钟内需要结果,0.0000001 在任何情况下都是不正确的——一个太多的零!使用调试器会比printf 调试更好。
【解决方案2】:

你至少有三个错误,一个不明智的做法(除了使用global data !),还有一个基本的设计缺陷:

  • 如果您想要以微秒为单位的答案,那么您需要乘以 0.000001 而不是 0.0000001。简单地除以 1e6 时更不容易出错。

  • 您还没有使用tv_sec 成员; tv_usec 将在第二秒开始时翻转为零,所以如果开始时间在前一秒,你可能会得到一个负值——你肯定不会得到正确的答案。

  • 无法初始化diff

  • 您应该避免使用浮点运算进行累加。这是不必要的,并且会累积精度误差,而 long double 在这里是多余的,因为您只需要几秒到微秒的分辨率。

  • 即使您解决了第二个翻转问题,如果您的开始和结束恰好是午夜的任何一方,问题仍然存在。

以下解决了除上述最后一个问题之外的所有问题(稍后解决):

double getMedium( struct timeval x[][2] )
{
    unsigned long long diff = 0 ;
    int i ;
    for( i = 1; i < k.clientID; i++ )
    {
        unsigned long long start_usec = x[i][0].tv_usec * 1000000ULL + x[i][0].tv_usec ; 
        unsigned long long end_usec = x[i][1].tv_usec * 1000000ULL + x[i][1].tv_usec ; 
        diff += end_usec - start_usec ;
    }

    return diff / 1.0e6 ;
}

用于gettimeofday 的系统时钟分辨率未定义,可能无法在您的系统上提供微秒分辨率。如果“DO A BUNCH OF STUFF”花费的时间少于时钟分辨率,您将得到零或时钟分辨率的答案。

您可以通过以下方式确定gettimeofday 使用的时钟的分辨率:

#include <stdio.h>
#include <sys/time.h>

int main()
{
    struct timeval t ;
    unsigned long long start_usec ;
    unsigned long long end_usec ;
    gettimeofday( &t, 0 ) ;
    start_usec = t.tv_sec * 1000000ULL + t.tv_usec ;

    do
    {
        gettimeofday( &t, 0 ) ;
        end_usec = t.tv_sec * 1000000ULL + t.tv_usec ;
    } while( start_usec == end_usec ) ;

    printf( "Clock resolution = %u microsecond(s)", end_usec - start_usec ) ;

    return 0 ;
}

您当然可以通过使用标准库 clock() 函数大大简化此代码,它几乎肯定会具有与 gettimeofday() 相同的分辨率(请检查 CLOCKS_PER_SEC 的定义以确保),但没有相关联的第二天或第二天环绕的问题。

#include <time.h>

double getMedium( struct timeval x[][2] )
{
    time_t diff = 0 ;
    int i ;
    for( i = 1; i < k.clientID; i++ )
    {
        time_t start_time = clock() ; 
        time_t end_time = clock() ; 
        diff += end_time - start_time ;
    }

    return (diff * CLOCKS_PER_SEC) / 1.0e6 ;
}

您以后最好将编译器的警告级别设置为高,并将警告视为错误,例如 GCC 中的 -Wall -Werror 或 VC++ 中的 \W4 \WX。您还应该使用源代码级符号调试器来查找代码中的问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    • 1970-01-01
    • 2021-12-31
    • 2022-01-22
    相关资源
    最近更新 更多