我需要在C中实现时间戳比较(不使用任何库)。
由于该例程将被大量使用,因此我试图找出一种最佳算法。
我的输入数据是两个时间戳a和b,每个时间戳包括以下内容:
year
month
day
hour
minute
在C伪代码中:
struct Timestamp {
int year;
int month;
int day;
int hour;
int minute;
};
struct Timestamp a;
struct Timestamp b;
我正在尝试几种方法,包括嵌套if和组合每个值的开关:
int timestamp_comparison(int a, int b) {
if(a>b) return 2;
if(a=b) return 1;
if(a<b) return 0;
}
...
c_year = timestamp_comparison(a.year, b.year);
c_month = timestamp_comparison(a.month, b.month);
c_day = timestamp_comparison(a.day, b.day);
c_hour = timestamp_comparison(a.hour, b.hour);
c_minute = timestamp_comparison(a.minute, b.minute);
comparison = c_year * 10000 + c_month * 1000 + c_day * 100 + c_hour * 10 + c_minute;
...
但是我想知道是否已经有我可以利用的算法。 我不喜欢使用外部库。
答案 0 :(得分:4)
我建议不要使用返回值0
,1
和2
,而建议使用<0
,0
和>0
。这更常见,与strcmp
等qsort
或bsearch
的语义匹配,并且可以通过简单的减法并与0比较来实现。
/*
* @retval <0 if a < b
* @retval 0 if a == b
* @retval >0 if a > b
*/
int compare_timestamps(struct Timestamp a, struct Timestamp b)
{
int result;
result = a.year - b.year;
if(result != 0) return result;
result = a.month - b.month;
if(result != 0) return result;
result = a.day - b.day;
if(result != 0) return result;
result = a.hour - b.hour;
if(result != 0) return result;
result = a.minute - b.minute;
return result;
}
如吉姆·米歇尔(Jim Mischel)的评论中所述,该算法假定减法不会导致整数翻转。这对于month
,day
,hour
和minute
字段的常规值有效。对于“通常”年份值,这是一个合理的假设。如果year
对于abs(a.year) + abs(b.year) > INT_MAX
字段无效。要处理year
.. INT_MIN
整个范围内的INT_MAX
值,必须更改算法。
答案 1 :(得分:0)
在比较时间戳时,有2个问题起作用
年份范围
如果.year
的使用范围是[INT_MIN...INT_MAX]
,请避免使用a.year - b.year
,因为它可能会溢出。
主要值
成员总是在其主要范围内吗?示例:minute
的范围是0-59吗?
是的,一个简单的比较并返回-1,0,1使用了常见的C习惯用法(a>b) - (a<b)
,许多编译器可以识别并发出有效的代码。
int timestamp_compare(const struct Timestamp *ts2, const struct Timestamp *ts1) {
if (ts1->year != ts2->year) return (ts2->year > ts1->year) - (ts2->year < ts1->year);
if (ts1->month != ts2->month) return (ts2->month > ts1->month) - (ts2->month < ts1->month);
if (ts1->day != ts2->day) return (ts2->day > ts1->day) - (ts2->day < ts1->day);
if (ts1->hour != ts2->hour) return (ts2->hour > ts1->hour) - (ts2->hour < ts1->hour);
return (ts2->day > ts1->day) - (ts2->day < ts1->day);
}
如果不是,则形成分钟的线性计数,然后进行比较。
long long minutes(const struct Timestamp *ts) {
return ((tbd_day_number(ts->year, ts->month, ts->day)*24LL + ts->hour)*60 + ts->minute;
}
int timestamp_compare(const struct Timestamp *ts2, const struct Timestamp *ts1) {
long long m1 = minutes(ts1);
long long m2 = minutes(ts2);
return (m2 > m1) - (m2 < m1);
}
答案 2 :(得分:0)
如果您的结构以某种排序方式包含其成员,例如您的情况(年份比月份重要,依此类推……),并且由于在结构中,成员“最有可能”存储在连续的方式:
参见:Using Contiguous Memory of C Struct Members
您可以像这样尝试逐字节比较:
#include <stdlib.h>
// members of struct are stored contigously
struct Timestamp
{
int year;
int month;
int day;
int hour;
int minute;
};
int timestamp_comparison(const struct Timestamp a, const struct Timestamp b)
{
unsigned i;
unsigned struct_size = sizeof(struct Timestamp) / sizeof(int);
const int* t1 = (const int*)&a;
const int* t2 = (const int*)&b;
// compare byte by byte
for (i = 0; i < struct_size; i++)
{
if (*t1 != *t2)
return *t1 - *t2;
++t1;
++t2;
}
return 0;
}
int main()
{
// example
struct Timestamp a = {1, 1, 2, 1, 1};
struct Timestamp b = {1, 1, 1, 7, 1};
int comp = timestamp_comparison(a, b);
return 0;
}
我并不是说这比已经发布的答案更好,只是有所不同。对于像您这样的其他任何结构,其作用方式也相同。
答案 3 :(得分:-1)
这里有一个小改进:
您的PC正在使用二进制文件运行,因此基数2是他最好的选择
您可以替换:
comparison = c_year * 10000 + c_month * 1000 + c_day * 100 + c_hour * 10 + c_minute;
依据(您的值均小于4),因此您可以:
comparison = c_year * 256 + c_month * 64 + c_day * 16 + c_hour *4 + c_minute;
或者这个(可读性较差,但“没有”算术):
comparison = c_year << 8 | c_month <<6 | c_day <<4 | c_hour <<2 | c_minute;
但是,如果您确实通过这种方式提高了速度,则只能通过性能分析来验证。
根据您的数据,仅比较所需的内容可能会更快:
int val;
if(1!=(val=timestamp_comparison(a.year, b.year)))
return val;
if(1!=(val=timestamp_comparison(a.month, b.month)))
return val;
if(1!=(val=timestamp_comparison(a.c_day, b.c_day)))
return val;
if(1!=(val=timestamp_comparison(a.c_hour, b.c_hour)))
return val;
return timestamp_comparison(a.c_minute, b.c_minute);
但是正如我上面提到的,当进行优化时,概要分析是您的朋友。
P.s。
if(a>b) return 2;
if(a=b) return 1;
if(a<b) return 0;
是一个不寻常的定义。更常见的是:
if(a>b) return value >=1
if(a=b) return 0;
if(a<b) return value <=-1