Mixed C++/Assembly: A Fast Algorithm to Find the First n Prime Numbers


This demo program finds the first n prime numbers using a fast algorithm with x86 32-bit assembly language.

This project has been tested with Visual Studio .Net 2008 (C++)

There are two constants rows (preset to 20) and cols (preset to 10) to make a tabular display. The number
of prime numbers to find is n = rows * cols (here, 200). We could modify these values to change
the tabular display rows and cols as well as the number of prime numbers
to find.

We have used the same algorithm already introduced for C++ and Java
languages. See the notes for these articles:


“Fast Algorithm to Find the First n Prime Numbers” (C++)


“Java (1) ArrayList: Fast Algorithm to Find the First n Prime Numbers”


“Java (2) Array: Fast Algorithm to Find the First n Prime Numbers”

We have used the algorithm given in the C++ version. The code given
in that article could be considered as the pseudo algorithm used to
write the equivalent assembly program.

You may download the full project source file in ZIP format from the FileFactory site:
Download Source Project

The main program for this demo is main.cpp:

// main.cpp
// The main program for fast prime algorithm

/*
This demo program finds the first n prime numbers using
a fast algorithm with x86 32-bit assembly language.

There are two constants rows (preset to 20) and cols (preset to 10)
to make a tabular display. The number of prime numbers to find is
n = rows * cols (here, 200). We could modify these values to change
the tabular display rows and cols as well as the number of prime numbers
to find.

We have used the same algorithm already introduced for C++ and Java
languages. See the notes for these articles:

"Fast Algorithm to Find the First n Prime Numbers" (C++)
Link: https://911programming.wordpress.com/2010/05/10/fast-algorithm-to-find-the-first-n-prime-numbers/

"Java (1) ArrayList: Fast Algorithm to Find the First n Prime Numbers"
Link: https://911programming.wordpress.com/2010/05/20/java-1-arraylist-fast-algorithm-to-find-the-first-n-prime-numbers/

"Java (2) Array: Fast Algorithm to Find the First n Prime Numbers"
Link: https://911programming.wordpress.com/2010/05/21/java-2-array-fast-algorithm-to-find-the-first-n-prime-numbers/

We have used the algorithm given in the C++ version. The code given
in that article could be considered as the pseudo algorithm used to
write the equivalent assembly program.

*/

#include <iostream>
using namespace std;

extern "C" int fastprime (int *, int);

int main ()
{
	const int rows = 20;
	const int cols = 10;

	// n is automatically adjusted with rows and cols
	const int n = rows * cols;
	int table [n];

	// Find the prime numbers.
	int count = fastprime (table, n);

	if (count <= 0)
	{
		cerr << "*** fastprime: returned unexpected value: " << count << endl;
		return 1;
	}

	// display result in tabular format:

	// for rows row
	for (int i = 0; i < rows; i++)
	{
		// for cols column
		for (int j = 0; j < cols; j++)
		{
			cout << table [i * cols + j] << '\t';
		}

		cout << "\n";
	}

	// print the number of prime numbers evaluated:
	cout << "\nThe number of evaulated prime numbers: " << count << "\n" <<endl;

	return 0;
}

The fastprime function is in the assembly file prime.asm:

; prime.asm
; The source assembly file for function fastprime.

; The code provided for assembly function fastprime
; finds (evaluates) the first n prime numbers.
; This function is meant to be linked to a C/C++.
; The C/C++ code performs the invoke or call.
; This functions uses the standard C calling convention and linkage.
; we have used a fair advantage of 32-bit memory addressing modes.

.386
.model	flat, C

; Dummy!; simply a decorative declaration. Not used in this code.
public	globData

.data
; Dummy!; simply a decorative global variable definition.
; Not used in this code.
globData	dd	1134

; C function declaration:
; int fastprime (int * prime_table, int prime_count);

; C function paramter prime_table: array (pointer to DWORD)
; to save the evaluated prime numbers:
; It is the location in stack where this argument passed to the function.
prime_table	textequ	<DWORD PTR [ebp + 8]>

; C function paramter prime_count: the number of prime numbers to find.
; It is the location in stack where this argument passed to the function.
prime_count	textequ <DWORD PTR [ebp + 12]>

; C function local variable: number
; declared like: int number;
; It is the location in stack where this local variable placed.
number		textequ <DWORD PTR [ebp - 4]>

; C function local variable: prime_bool
; declared like: bool prime_bool;
; For simplicity, we used DWORD (Int32) to represent bool data type.
; It is the location in stack where this local variable placed.
prime_bool	textequ <DWORD PTR [ebp - 8]>

; The role of registers used in this algorithm
; EAX :	general purpose use. Finally, it contains the number of
;		prime numbers evaluated. No need tp preseve and retrieve.
;
; EBX :	The base address of the array in which the prime numbers
;		are saved.
; EDX : Used in MUL and DIV operations. In DIV it contains the
;		remainder of division (result of %).
; ESI : Offset to array (DWORD aligned) where the next evaluated
;		prime number should be saved. It also denotes the number
;		of prime numbers evaluated so far at any time.
;		The return value is evantually the value of this register
;		which is saved in EAX.
; EDI :	When looking for a divisor, it is the offset of the next
;		prime number in table (among those already evaluated) which
;		is to be examined for the next number to evaluate as prime.

.code

; C function definition:
; int fastprime (int * prime_table, int prime_count);
; { //...

fastprime	proc

	; Complete creating high-level language stack frame.
	; The first half is done by caller code, pushing function args
	; into stack.
	push	ebp
	mov		ebp, esp

	; Reserve space for local variables
	sub		esp, 8

	; Preserve used registers.
	push	ebx
	push	edx
	push	esi
	push	edi

	; Set the number of already evaluated prime numbers to zero.
	mov		esi, 0

	; Check if the requested number of prime numbers is positive
	mov		eax, prime_count
	cmp		eax, 0
	jle		L100

	; Set the base address of the array
	mov		ebx, prime_table
	; Check if it is not NULL
	cmp		ebx, 0
	je		L100

	; Set the first prime number: 2, manually
	mov		DWORD PTR [ebx][esi], 2

	; Inc count
	inc		esi

	; Perform the for loop for number(s).

	; for number = 3
	mov		number, 3
	jmp		L4

L3:
	; Step of loop: number += 2
	add		number, 2

L4:
	; condition of loop: while (current_count < final_count)
	cmp		esi, prime_count
	jae		L100				; if consition failed exit for loop.
								; Make ready for return

	; First, assume this number is prime
	; prime_bool = true;
	mov		prime_bool, 1

	; Perform the for loop for divisor(s).
	; Divisor to test is picked from the prime numbers already evaluated.

	; for divisor = table [0]
	; that is index is set to 0
	mov		edi, 0
	jmp		L6

L5:
	; Step of loop: edi++ (for table [edi])
	inc		edi

L6:
	; loop condition: while (table [edi] * table [edi] <= number)
	mov		eax, [ebx][edi * 4]
	mul		eax

	cmp		eax, number
	ja		L7				; if condition failed, exit for loop
							; Make ready to report as prime

	; Set High DWORD to 0. make ready for evaluating number % table [edi]
	mov		edx, 0
	mov		eax, number
	div		DWORD PTR [ebx][edi * 4]

	; EDX contains the remainder, check if table [edi] is a
	; divisor of number
	cmp		edx, 0
	jne		L5				; If it is not a divisor, check next
							; prime number.

	; Otherwise, report it as NOT prime
	mov		prime_bool, 0	

L7:
	; the flow of program comes here in two cases:
	; 1) We have found a divisor, and therefore, this number is NOT prime.
	; 2) We have tested all possible prime numbers in table, and none is
	;    a divisor for this number. Therefore, this number is prime.
	; prime_bool value denotes which one is the case:
	; Check if it is 0 (false) or non-zero (true).
	mov		eax, prime_bool
	; and instruction is the most efficient way to check it:
	and		eax, eax
	jz		L3				; If zero (false), the number is NOT prime.
							; Skip it (don't write it in table).

	; Otherwise, it is a prime number; save it in table
	mov		eax, number
	mov		[ebx][esi * 4], eax
	; update current count and table index;
	inc		esi
	; Go for next number.
	jmp		L3			

L100:
	; Get ready for return:
	; Set the return value (the number of prime numbers evaluated so far).
	mov		eax, esi

	; Retrieve used registers:
	pop		edi
	pop		esi
	pop		edx
	pop		ebx

	; remove / destruct high-level language stack frame.
	mov		esp, ebp
	pop		ebp
	ret
fastprime	endp

end
This entry was posted in Assembly, C/C++ and tagged , , . Bookmark the permalink.

Leave a comment