Files
cKit/Foundation/c_timespec.c
T
2026-08-29 01:50:50 +08:00

99 lines
1.7 KiB
C

#include <c_timespec.h>
#include <limits.h>
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
struct timespec c_timespec_mod(struct timespec ts1, struct timespec ts2)
{
int i = 0;
bool neg1 = false;
bool neg2 = false;
/* Normalise inputs to prevent tv_nsec rollover if whole-second values
* are packed in it.
*/
ts1 = c_timespec_normalise(ts1);
ts2 = c_timespec_normalise(ts2);
/* If ts2 is zero, just return ts1
*/
if (ts2.tv_sec == 0 && ts2.tv_nsec == 0)
{
return ts1;
}
/* If inputs are negative, flip and record sign
*/
if (ts1.tv_sec < 0 || ts1.tv_nsec < 0)
{
neg1 = true;
ts1.tv_sec = -ts1.tv_sec;
ts1.tv_nsec = -ts1.tv_nsec;
}
if (ts2.tv_sec < 0 || ts2.tv_nsec < 0)
{
neg2 = true;
ts2.tv_sec = -ts2.tv_sec;
ts2.tv_nsec = -ts2.tv_nsec;
}
/* Shift ts2 until it is larger than ts1 or is about to overflow
*/
while ((ts2.tv_sec < (LONG_MAX >> 1)) && c_timespec_ge(ts1, ts2))
{
i++;
ts2.tv_nsec <<= 1;
ts2.tv_sec <<= 1;
if (ts2.tv_nsec > C_NSEC_PER_SEC)
{
ts2.tv_nsec -= C_NSEC_PER_SEC;
ts2.tv_sec++;
}
}
/* Division by repeated subtraction
*/
while (i >= 0)
{
if (c_timespec_ge(ts1, ts2))
{
ts1 = c_timespec_sub(ts1, ts2);
}
if (i == 0)
{
break;
}
i--;
if (ts2.tv_sec & 1)
{
ts2.tv_nsec += C_NSEC_PER_SEC;
}
ts2.tv_nsec >>= 1;
ts2.tv_sec >>= 1;
}
/* If signs differ and result is nonzero, subtract once more to cross zero
*/
if (neg1 ^ neg2 && (ts1.tv_sec != 0 || ts1.tv_nsec != 0))
{
ts1 = c_timespec_sub(ts1, ts2);
}
/* Restore sign
*/
if (neg1)
{
ts1.tv_sec = -ts1.tv_sec;
ts1.tv_nsec = -ts1.tv_nsec;
}
return ts1;
}