Skip to content

Instantly share code, notes, and snippets.

@TechplexEngineer
Last active December 15, 2015 15:29
Show Gist options
  • Save TechplexEngineer/5282091 to your computer and use it in GitHub Desktop.
Save TechplexEngineer/5282091 to your computer and use it in GitHub Desktop.
Simple example of how to do unsigned 64bit division in c rev2: If you quit out, it doesn't print the R & Q as they are false. rev3: added some test cases rev4: fixed comment spacing rev5: one can set test cases rev6: fixed case 2. Case 10 remains broken rev7: fixed segvault issue rev8: works for all 10 test cases! rev9: added more debug comments…
OBJS = udiv_64.o
CFLAGS = -Wall -Wformat
TARGET = test
all: $(OBJS)
$(CC) -o $(TARGET) $(OBJS)
run: all
./$(TARGET)
clean:
rm $(TARGET) *.o
//****************** ECE 271 64bit Division Algorithm *************************
// @file udiv64.c
// @author Blake Bourque
// @date 4/5/13
// @note udiv_64 in c
//*****************************************************************************
#include <stdint.h>
#include <stdio.h>
//uncomment the following line for step by step
// #define DEBUG
#define START_CASE 0 //0-9
#ifdef DEBUG
#define debugPrintF(...) fprintf(stdout, __VA_ARGS__)
#else
#define debugPrintF(...)
#endif
int clz (uint64_t x);
void udiv_64(uint64_t divs, uint64_t divd, uint64_t* remainder, uint64_t* quotient);
#define NUM_TEST_CASES 10
//cases
const uint64_t divisors[NUM_TEST_CASES] = { //(denominator)
0x062AFBDE1181C71C,
0x0000000000000000,
0x03157DEF08C0E38E,
0x0000000000000001,
0x03157DEF08C0E38E,
0x0000040000000000,
0x000000000001E240,
0x0000000000000281,
0x0000000000ABCDEF,
0x00000000000ABCDE,
};
const uint64_t dividends[NUM_TEST_CASES] = { //(numerator)
0x062AFBDE1181C71C,
0x062AFBDE1181C71C,
0x062AFBDE1181C71C,
0x03157DEF08C0E38E,
0x03157DEF08C0E38D,
0x00002D09F87B3660,
0x0123456789ABCDEF,
0x0316CCCCD30227FD,
0x00000000000ABCDE,
0x000000734CB98D58,
};
//answers
//quotient
const uint64_t quotients[NUM_TEST_CASES] = {
0x0000000000000001,
0x0000000000000000,
0x0000000000000002,
0x03157DEF08C0E38E,
0x0000000000000000,
0x000000000000000B,
0x0000009A9EAC038A,
0x00013BD396E4D886,
0x0000000000000000,
0x00000000000ABCDE,
};
//remainder
const uint64_t remainders[NUM_TEST_CASES] = {
0x0000000000000000,
0x0000000000000000,
0x0000000000000000,
0x0000000000000000,
0x03157DEF08C0E38D,
0x00000109F87B3660,
0x000000000001176F,
0x0000000000000077,
0x00000000000ABCDE,
0x00000000000ABCD4,
};
//******************************************************************************************
//* Your main program starts here
//******************************************************************************************
int main(void)
{
int i;
uint64_t rem = 0;
uint64_t quo = 0;
for (i=START_CASE; i<NUM_TEST_CASES; i++) { //i = case to start with 0 is the first 1-NUM_TEST_CASES is last
printf("Case #%d\n", i+1);
printf("Numer: 0x%.16llX\n", dividends[i]);
printf("Denom: 0x%.16llX\n", divisors[i]);
udiv_64(divisors[i], dividends[i], &rem, &quo);
if (quo == quotients[i])
printf("Q: 0x%.16llX\n", quo);
else
printf("ERROR: Q: 0x%.16llX SHOULD BE: 0x%.16llX\n", quo ,quotients[i]);
if (rem == remainders[i])
printf("R: 0x%.16llX\n", rem);
else
printf("ERROR: R: 0x%.16llX SHOULD BE: 0x%.16llX\n", rem, remainders[i]);
printf("\n");
}
return 0;
}
void udiv_64(uint64_t divs, uint64_t divd, uint64_t* remainder, uint64_t* quotient) {
uint64_t R = divd; //remainder (numerator)
uint64_t Q = 0; //quotient
int x=0, y=0;
uint64_t a=0, b=0;
uint32_t g=0;
uint32_t msb_a_32;
uint16_t msb_b_16;
uint64_t u;
int count = 0;
if (divs == 0) {
*remainder = 0;
*quotient = 0;
return;
}
while (R >= divs && divs != 0) {
debugPrintF("\nCount: %u\n", count);
x = clz(R);
a = R << x;
debugPrintF("a: 0x%llX x=%d\n", a, x);
y = clz(divs);
b = divs << y;
debugPrintF("b: 0x%llX y=%d\n", b, y);
msb_a_32 = a>>32;
msb_b_16 = b>>48;
//debugPrintF("u = (0x%.8lX << (%d - 16)) >> %d\n", g, y, x);
if (y < 16) {
x += (16-y);
y = 0;
} else {
y -= 16;
}
here:
debugPrintF(" g = \t0x%lX / 0x%.8X\n", msb_a_32, msb_b_16);
g = (uint32_t)((msb_a_32 / msb_b_16) & 0x00000000FFFFFFFF);
debugPrintF("g: 0x%.16llX\n", g);
u = ((uint64_t)g<<y)>>x;
debugPrintF(" u = (0x%.8lX << %d) >> %d\n", g, y, x);
debugPrintF("u: 0x%.16llX\n", u);
debugPrintF(" divs: 0x%llX\n", (divs));
debugPrintF(" u*divs = 0x%llX\n", (u*divs));
debugPrintF(" R = 0x%X\n", R);
if ( (u*divs) > R) {
debugPrintF("--Going Again--\n");
fflush(stdout);
msb_b_16 +=1;
goto here;
}
Q += u;
debugPrintF("\nQ: 0x%.16llX\n", Q);
debugPrintF(" R = 0x%.16llX - (0x%.16llX * 0x%.16llX) \n", R, u, divs);
R = R - (u*divs);
debugPrintF("R: 0x%.16llX\n", R);
debugPrintF("\nType [1] to continue: ");
#ifdef DEBUG
int nxt = 0;
scanf("%d", &nxt);
if( nxt != 1)
break;
debugPrintF("\n");
#endif // /DEBUG
count ++;
}
debugPrintF("\n");
if(R < divs) {
*remainder = R;
*quotient = Q;
} else
printf("Run Terminated!\n");
}
//Count Leading Zeros (CLZ)
//Adapted from Wikipedia: http://en.wikipedia.org/wiki/Find_first_set#Algorithms
int clz (uint64_t x) {
uint64_t t;
int r;
if (x == 0)
return 0;
t = 0x8000000000000000; //mask
r = 0; //number of zeros counter
while ((x & t) == 0 && r < 64) {
t = t >> 0x1;
r ++;
}
return r;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment