Nombre narcissique (win32, asm)

Description

Bonjour,

Je vous presente (sans pretention aucune), un code (C/ASM) permettant de savoir si un nombre est narcissique ou pas.
Nombre narcissique : http://membres.lycos.fr/villemingerard/Formes/Narcissi.htm
J'ai vu une autre definition qui reprenait celle ci, mais qui envisageait aussi le cas ou la somme des factorielles des chiffres (ou parties de chiffres) d'un nombre etait egale a ce nombre. (cf lien precedent, vous comprendrez mieux). Etant donné qu'au point de vu programmation, verifier les factorielles etc.. ne m'apprenait rien (reprise du code sur les puissance, cf lien ;)), je ne l'ai pas codé.

Si j'ai fait ce code en ASM, c'est juste une petite revanche envers moi meme, car je suis, un jour, tombé sur cet exercice, et j'ai perdu mon temps a le coder, alors que c'etait simple...Enfin bon, certains me comprendront ;)

Je souhaite bien entendu aussi avoir des avis, surtout negatif pour me dire ce qui ne va pas.

Source / Exemple :


#include <windows.h>
#include "resource.h"

WNDPROC oldEditProc;
HINSTANCE hInstance;

/*__declspec(naked) void __stdcall PuissFPU(int n, int exp) 
{
	__asm {
		mov		ecx, [esp + 8] //eax == exp
		fild	dword ptr[esp + 4] //empile n, ST(1) == n	
		dec		ecx
		jle		Fin
		fld		ST //empile n, ST(0) == n, Contiendra le resultat
Deb:
		fmul	ST(1), ST
		dec		ecx
		test	ecx, ecx
		jne		Deb	
		fstp	ST
Fin:
		fistp dword ptr[esp - 4]
		mov		ecx, [esp - 4]
		ret		8
	}
}*/

//Resultat renvoyé dans ecx
__declspec(naked) void __fastcall Puiss(int n, int exp)
{

	__asm {
		mov		eax, ecx
		dec		edx
		jle		End
Deb:
		imul	ecx, eax
		dec		edx
		test	edx, edx
		jne		Deb
End:	
		ret		0
	}
}

int __stdcall len(int n)
{
	if (n >= 1000000000) return 10;
	if (n >= 100000000) return 9;
	if (n >= 10000000) return 8;
	if (n >= 1000000) return 7;
	if (n >= 100000) return 6;
	if (n >= 10000) return 5;
	if (n >= 1000) return 4;
	if (n >= 100) return 3;
	if (n >= 10) return 2;

	return 1;
}

__declspec(naked) int __fastcall sPuiss(int n, int exp)
{
	__asm {
		mov		eax, ecx
		dec		edx
Deb:
		imul	eax, ecx
		dec		edx
		test	edx, edx
		jne		Deb
		ret		0
	}
}

int Narcissique(int n)
{
	int lSomme, lSommePrec, lTemp;
	int i, j, iTaille, exp, iPuissDix = 10;
 
	iTaille = len(n);

	for (exp = 2; exp < 32; ++exp) {
		iPuissDix = 10;
		for (i = 1; i < iTaille; ++i) {
			if (iTaille % i) goto EndFor;
			lTemp = n;
			lSomme = 0;
			while (lTemp) {
				lSomme += sPuiss(lTemp % iPuissDix, exp);
				lTemp /= iPuissDix;
			}
			if (lSomme == n) return 1;
			if (lSomme == lSommePrec) break;
			if (lSomme > n && i == 1) return 0;
			if (lSomme > n) break;
			lSommePrec = lSomme;
		EndFor:
			iPuissDix *= 10;
		}
	}

	return 0;
}

//0 < Exp <= 4
//lTemp dans eax
//Modulo dans ecx
//Restaure edx
__declspec(naked) void __fastcall asmDivide(int Exp, int lTemp)
{
	__asm {
		mov		eax, edx

		cmp		ecx, 1
		jne		L1
		mov		[esp - 4], edx
		//Division par 10
		mov   edx, 3435973837
		mul   edx
		shr   edx, 3
		//Modulo (lTemp - (Resultat * 10))
		mov		eax, edx
		mov		ecx, edx
		shl		eax, 3
		shl		ecx, 1
		add		eax, ecx
		mov		ecx, [esp - 4]
		sub		ecx, eax
		mov		eax, edx
		ret		0
L1:
		cmp		ecx, 2
		jne		L2
		mov		[esp - 4], edx
		//100
		mov   edx, 2748779069
		inc   eax
		mul   edx
		shr   edx, 6
		//Modulo (lTemp - (Resultat * 100))
		mov		eax, edx
		mov		ecx, edx 
		mov		edx, 100
		mul		edx
		mov		edx, ecx
		mov		ecx, [esp - 4]
		sub		ecx, eax
		mov		eax, edx
		ret		0
L2:
		cmp		ecx, 3
		jne		L3
		mov		[esp - 4], edx
		//1000
		mov   edx, 2199023256
		mul   edx
		shr   edx, 9
		//Modulo (lTemp - (Resultat * 1000))
		mov		eax, edx
		mov		ecx, edx 
		mov		edx, 1000
		mul		edx
		mov		edx, ecx
		mov		ecx, [esp - 4]
		sub		ecx, eax
		mov		eax, edx
		ret		0
L3:
		cmp		ecx, 4
		jne		L4
		mov		[esp - 4], edx
		//10000
		mov   edx, 3518437209
		mul   edx
		shr   edx, 13
		//Modulo (lTemp - (Resultat * 10000))
		mov		eax, edx
		mov		ecx, edx 
		mov		edx, 10000
		mul		edx
		mov		edx, ecx
		mov		ecx, [esp - 4]
		sub		ecx, eax
		mov		eax, edx
		ret		0
L4:
		xor		eax, eax
		xor		ecx, ecx
		ret		0
	}
}

__declspec(naked) int __stdcall asmNarcissique(int n)
{
	//(ESP)				=> iTaille
	//(ESP + 4)		=> exp
	//(ESP + 8)		=> i
	//(ESP + 12)	=> lSommePrec
	//(ESP + 24)	=> n
	__asm {
		mov		edx, [esp + 4]
		push	esi
		push	edi
		push	ebx
		lea		esi, [esp - 16]
		mov		esp, esi
		xor		ecx, ecx
		mov		eax, 1
		mov		[esi + 4], ecx
		mov		[esi + 8], ecx
		mov		ecx, 0FFFFFFFFh
		mov		[esi + 12], ecx						;on initialise avec la plus grande valeur possible.
		push	edx
		call	len												;Taille du nombre
		;shr		eax, 1
		mov		[esi], eax								;sauve taille sur la pile
DebExp:
    mov		eax, [esi + 4]						;exp
		inc		eax
		cmp		eax, 32
		jg		ret0
		xor		ecx, ecx
		mov		[esi + 4], eax
		mov		[esi + 8], ecx
DebTaille:
		mov		ecx, [esi + 8]						;i
		mov		eax, [esi]								;iTaille
		inc		ecx
		mov		[esi + 8], ecx						;sauve i
		shr		eax, 1
		cmp		ecx, eax									
		jg		DebExp
		mov		eax, [esi]
		xor		edx, edx
		div		ecx
		test	edx, edx									;teste 'modulo' qui est dans edx
		jne		DebTaille
		mov		edi, [esi + 32]						;n
		xor		ebx, ebx									;iSomme == 0
WhileTmp:	;edi == lTemp
		test	edi, edi
		jz		Comp
		mov		edx, edi
		call	asmDivide									;lTemp == eax, Modulo == ecx
		mov		edx, [esi + 4]
		mov		edi, eax
		call	Puiss											;ecx == resultat
		add		ebx, ecx
		mov		ecx, [esi + 8]						;ressort i de la stack
		jmp		WhileTmp
		mov		[esi + 12], ebx						;SommePrec
Comp:
		mov		eax, [esi + 32]
		cmp		ebx, eax									; if (Somme == n) return 1;
		jg		TestI
		jne		C1
		mov		eax, 1
		add		esp, 16
		pop		ebx
		pop		edi
		pop		esi
		ret		4
TestI:
		cmp		ecx, 1
		jne		DebExp
		jmp		ret0
	C1:
		mov		eax, [esi + 12]
		cmp		edx, eax
		jne		DebTaille
ret0:
		xor		eax, eax
		add		esp, 16
		pop		ebx
		pop		edi
		pop		esi
		ret		4		
	}
}	

char szBuffer[16];

LRESULT CALLBACK EditProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
{
	if (WM_CHAR == message) {
		if ((wparam < 48 || wparam > 57) && wparam != VK_BACK) { MessageBeep(0); return 0; }
		if (szBuffer[0]) {
			szBuffer[0] = 0;
			SetDlgItemText(GetParent(hwnd), IDST_NARC, szBuffer);
		}
	}
	
	return CallWindowProc(oldEditProc, hwnd, message, wparam, lparam);
}

BOOL CALLBACK DlgProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
{	
	int iNarc = 0;

	switch (message) {
		case WM_INITDIALOG:
			SetClassLong(hwnd, GCL_HICON, (long)LoadIcon(0, IDI_APPLICATION));
      oldEditProc = SetWindowLong(GetDlgItem(hwnd, IDEC_NARC), GWL_WNDPROC, (long)EditProc);
			SendMessage(GetDlgItem(hwnd, IDEC_NARC), EM_SETLIMITTEXT, 10, 0);
			PostMessage(hwnd, WM_NEXTDLGCTL, GetDlgItem(hwnd, IDEC_NARC), 1);
			return 0;
		case WM_COMMAND:
			if (IDCANCEL == wparam) {
				EndDialog(hwnd, 0);
			} else if (IDOK == wparam) {
				int i = 0;

				GetDlgItemText(hwnd, IDEC_NARC, szBuffer, 10);
				iNarc = atoi(szBuffer);
				
				if (!asmNarcissique(iNarc)) *((DWORD *)szBuffer) = 0x004E4F4E;	//"NON"
				else *((DWORD *)szBuffer) = 0x0049554F; //"OUI"
				SetDlgItemText(hwnd, IDST_NARC, szBuffer);			
			}
			return 0;
	}

	return 0;
}

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE p, LPSTR q, int r)
{ 
	hInstance = hInst;
  DialogBoxParam(hInst, (LPCTSTR)IDD_NARC, 0, DlgProc, 0);	
	return 0;
}

Conclusion :


J'ai codé la version FPU de la fonction Puissance, mais elle est beaucoup plus lente que la version avec registres generaux.
Le code ASM est un petit peu (mais notablement) plus rapide que le code C avec toutes optimisations (de VC++ ;)).

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.