Modulus operator

is it true using the % operator on a 64-bit value requires helper functions from the C runtime library that are not available in the kernel ? what alternatives

Did you at least try it?

yes and its not working

The Microsoft C compilers will happily produce an assembly listing during compilation, by using the /FAsc option. You can see for yourself what it generates.

Here, I did it for you. Input:

#include <stdint.h>
int64_t domod( int64_t a, int64_t b )
{
    return a % b;
}

Assembly:

; Listing generated by Microsoft (R) Optimizing Compiler Version 19.22.27905.0 

include listing.inc

INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES

PUBLIC	domod
; Function compile flags: /Odtp
; File C:\tmp\x.c
_TEXT	SEGMENT
a$ = 8
b$ = 16
domod	PROC

; 3    : {

  00000	48 89 54 24 10	 mov	 QWORD PTR [rsp+16], rdx
  00005	48 89 4c 24 08	 mov	 QWORD PTR [rsp+8], rcx

; 4    :     return a % b;

  0000a	48 8b 44 24 08	 mov	 rax, QWORD PTR a$[rsp]
  0000f	48 99		 cdq
  00011	48 f7 7c 24 10	 idiv	 QWORD PTR b$[rsp]
  00016	48 8b c2	 mov	 rax, rdx

; 5    : }

  00019	c3		 ret	 0
domod	ENDP
_TEXT	ENDS
END

So, the answer is "no, it does not require helper functions."

1 Like

thank you very much !

It would be shocking if integer modulus was compiled to anything except a single CPU instruction on any platform / architecture.

When you say it's not working, what symptom do you see? A compile / link problem? A load error? an unexpected result at runtime?

unexpected result at runtime yes

Can you share an example? It would be a big surprise if this didn't work properly on any modern CPU

  __int64 ourtimes = (__int64)(time / frequency);
  __int64 ourtimefract = (__int64)(time % frequency);
  double results  = (ourtimes  % (60 * 60 * 24 * 365)) + (double)ourtimefract / (double)((__int64)frequency);

If you need a cast, then the variable time or frequency must be declared as something other than a signed 64 bit integer? The numeric literals aren't typed, but that's probably not a huge issue. What values are you seeing versus the ones you expect?

Remember that, the way you have written it, the cast is done AFTER the division/modulus. If time and frequency are int or long, that will be a 32-bit computation.

2 Likes

values that i expect time: 1044112317857 ourtimes: 260, ourtimefract: 2032778317 results: 260.507180 what im getting time: 4440447143908 ourtimes: 1107, ourtimefract: 3593104405 results: 1107.896 since i cant print floats in kernel by splitting it into its integer and fractional components The fractional part is scaled and printed separately

how are the time & frequency variables declared? What's the value of frequency?

why can't you print a double? At least you can dump the bytes and interpret the exponent and mantissa later

time variable Declared as unsigned __int64 and initialized using rdtsc the frequency Declared same variable measured it using KeQueryPerformanceCounter and rdtsc frequency is 4007998229 which very accurate for 9900ks cpu

I don't see the problem. Assuming your divisor is 4,000,000,000, both of those computations are correct. Is your actual complaint that rdtsc and KeQueryPerformanceCounter produce different results? You're aware that KQPC does not use rdtsc for its counting, right? Did you check KeQueryPerformanceFrequency?

4440447143908 divided by 4007998229 is 1107 with remainder 3593104405.

If those variables are already 64 bit signed integers, the casts are redundant.

I'm not sure what you are trying to calculate on your final line, but if you just want a double with the number of seconds (including part seconds), you could just cast time and frequency to double and divide them directly. The results would be just about the same level of accuracy and would avoid extra instructions

double results = (double)time / (double)frequency;