#include #include #include #include #include typedef uint64_t u64; typedef uint32_t u32; static u64 div_u64_u32(u64 a, u32 b) { return a / b; } static u64 scale_stime(u64 stime, u64 rtime, u64 total) { /* We know one of the values has a bit set in the high 32 bits */ for (;;) { /* Make sure "rtime" is the bigger of stime/rtime */ if (stime > rtime) { u64 tmp = rtime; rtime = stime; stime = tmp; } /* Make sure 'total' fits in 32 bits */ if (total >> 32) goto drop_precision; /* Does rtime (and thus stime) fit in 32 bits? */ if (!(rtime >> 32)) break; /* Can we just balance rtime/stime rather than dropping bits? */ if (stime >> 31) goto drop_precision; /* We can grow stime and shrink rtime and try to make them both fit */ stime <<= 1; rtime >>= 1; continue; drop_precision: /* We drop from rtime, it has more bits than stime */ rtime >>= 1; total >>= 1; } /* Make sure gcc understands that this is a 32x32->64 multiply, * followed by a 64/32->64 divide */ return div_u64_u32((u64) (u32) stime * (u64) (u32) rtime, (u32)total); } int main(int argc, char *argv[]) { u64 rtime, total, stime, scaled; if (argc != 4) return; rtime = strtoll(argv[1], NULL, 10); total = strtoll(argv[2], NULL, 10); stime = strtoll(argv[3], NULL, 10); assert (total >= stime); scaled = scale_stime(stime, rtime, total); printf("%llu\n", scaled); return 0; }