Skip to content

Commit 0aceed0

Browse files
authored
Merge pull request #54 from visitorckw/introduce-mult-frac
Enhance precision and safety in time calculations
2 parents 1023b4c + 35e2206 commit 0aceed0

File tree

1 file changed

+15
-2
lines changed

1 file changed

+15
-2
lines changed

utils.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,19 @@
1919
#endif
2020
#endif
2121

22+
/* Calculate "x * n / d" without unnecessary overflow or loss of precision.
23+
*
24+
* Reference:
25+
* https://elixir.bootlin.com/linux/v6.10.7/source/include/linux/math.h#L121
26+
*/
27+
static inline uint64_t mult_frac(uint64_t x, uint64_t n, uint64_t d)
28+
{
29+
const uint64_t q = x / d;
30+
const uint64_t r = x % d;
31+
32+
return q * n + r * n / d;
33+
}
34+
2235
void semu_timer_init(semu_timer_t *timer, uint64_t freq)
2336
{
2437
timer->freq = freq;
@@ -30,12 +43,12 @@ static uint64_t semu_timer_clocksource(uint64_t freq)
3043
#if defined(HAVE_POSIX_TIMER)
3144
struct timespec t;
3245
clock_gettime(CLOCKID, &t);
33-
return (t.tv_sec * freq) + (t.tv_nsec * freq / 1e9);
46+
return t.tv_sec * freq + mult_frac(t.tv_nsec, freq, 1e9);
3447
#elif defined(HAVE_MACH_TIMER)
3548
static mach_timebase_info_data_t t;
3649
if (mach_clk.denom == 0)
3750
(void) mach_timebase_info(&t);
38-
return mach_absolute_time() * freq / t.denom * t.numer;
51+
return mult_frac(mach_absolute_time() * freq, t.numer, t.denom);
3952
#else
4053
return time(0) * freq;
4154
#endif

0 commit comments

Comments
 (0)