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++ ;)).
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.