Last active
December 15, 2015 15:29
-
-
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…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
OBJS = udiv_64.o | |
CFLAGS = -Wall -Wformat | |
TARGET = test | |
all: $(OBJS) | |
$(CC) -o $(TARGET) $(OBJS) | |
run: all | |
./$(TARGET) | |
clean: | |
rm $(TARGET) *.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//****************** 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