/*************************************************************************************************************************************/
/* */
/* C O M B I N A I S O N S D E Q U A T R E N O M B R E S : */
/* */
/* */
/* Author of '$xtc/combinaisons.01$vv$c' : */
/* */
/* Jean-Francois COLONNA (LACTAMME, 20140704120117). */
/* */
/*************************************************************************************************************************************/
#include "INCLUDES.01.I"
extern double pow();
#define RESULTAT_ATTENDU \
24
#define nNOMBRES \
4
enum ListeDesNombres
{
N1=1
,N2=3
,N3=4
,N4=6
};
typedef struct
{
int Numerateur;
int Denominateur;
}
Fraction;
/* Definition d'une fraction (nombre rationnel). */
#define UNITE \
1
#define Numer(fraction) \
(fraction.Numerateur)
#define Denom(fraction) \
(fraction.Denominateur)
#define EGAL(fraction,numerateur,denominateur) \
{ \
Numer(fraction) = numerateur; \
Denom(fraction) = denominateur; \
}
enum NomDesOperateurs
{
ADDITION=0
,SOUSTRACTION
,MULTIPLICATION
,DIVISION
,EXPONENTIATION
,nOPERATEURS
};
#define UNDEF \
4444719
int FaireCommeSiTousLesOperateursEtaientNonCommutatifs=FAUX;
int AccepterLesMultiplicationsParUn=VRAI;
int AccepterLesDivisionsParUn=VRAI;
int AccepterLesExponentiationsParUn=VRAI;
int PouvoirUtiliserPlusieursFoisChaqueNombre=FAUX;
/* Divers indicateurs de controle du fonctionnement de la fonction 'operation(...)'. */
int ListeOperators[nOPERATEURS]= { ADDITION, SOUSTRACTION, MULTIPLICATION, DIVISION, EXPONENTIATION };
int ListeUtilises[nOPERATEURS]= { VRAI, VRAI, VRAI, VRAI, FAUX };
int ListeCommutativites[nOPERATEURS]={ VRAI, FAUX, VRAI, FAUX, FAUX };
/* Liste des 'nOPERATEURS' operateurs autorises et utilisables 0, 1, 2,... fois. */
int ListeNombresEntiers[nNOMBRES]={N1,N2,N3,N4};
Fraction ListeNombres[nNOMBRES];
/* Liste des 'nNOMBRES' nombres autorises et obligatoires une seule fois... */
#define ri \
(INDEX0-UNDEF)
Fraction operation(int xIndex,Fraction x,int IndexOperateur,Fraction y,int yIndex)
/* Fonction calculant : */
/* */
/* x.operateur.y */
/* */
/* Les arguments '?Index' indiquent si le nombre correspondant ('x' ou 'y') est l'un */
/* des nombres de la liste 'ListeNombres' (auquel cas c'est index superieur ou egal a */
/* 'INDEX0') ou bien un resultat anterieur (auquel cas il est inferieur a 'INDEX0'). */
{
Fraction resultat;
EGAL(resultat,UNDEF,UNDEF);
/* La valeur 'UNDEF' est choisie de facon a ce qu'une operation la donnant comme resultat */
/* soit eliminee de la recherche ulterieurement... */
if ( (ListeUtilises[IndexOperateur] == VRAI)
&& ( ( (Numer(x) != UNDEF)
&& (Denom(x) != UNDEF)
&& (Numer(y) != UNDEF)
&& (Denom(y) != UNDEF)
)
)
&& ( ( (Denom(x) != 0)
&& (Denom(y) != 0)
)
)
&& ( (FaireCommeSiTousLesOperateursEtaientNonCommutatifs == VRAI)
|| (ListeCommutativites[IndexOperateur] == FAUX)
/* Cas ou l'operateur ne commute pas. */
|| ( (ListeCommutativites[IndexOperateur] == VRAI)
&& ( (xIndex < INDEX0)
|| (yIndex < INDEX0)
)
)
/* Cas ou l'operateur commute et porte sur deux nombres 'x' et 'y' dont l'un au moins des */
/* deux n'est pas elementaire. */
|| ( (ListeCommutativites[IndexOperateur] == VRAI)
&& ( (xIndex >= INDEX0)
&& (yIndex >= INDEX0)
&& (xIndex < yIndex)
)
)
/* Cas ou l'operateur commute et porte sur deux nombres 'x' et 'y' elementaires tel que */
/* l'index du premier est inferieur a celui du second ; le cas 'xIndex>yIndex' n'a donc */
/* pas a etre teste a cause donc de la commutativite. */
)
)
{
switch (ListeOperators[IndexOperateur])
{
case ADDITION:
{
EGAL(resultat
,(Numer(x)*Denom(y))+(Numer(y)*Denom(x))
,(Denom(x)*Denom(y))
);
break;
}
case SOUSTRACTION:
{
EGAL(resultat
,(Numer(x)*Denom(y))-(Numer(y)*Denom(x))
,(Denom(x)*Denom(y))
);
break;
}
case MULTIPLICATION:
{
if ( ( (Numer(x) != Denom(x))
&& (Numer(y) != Denom(y))
)
|| (AccepterLesMultiplicationsParUn == VRAI)
)
{
EGAL(resultat
,(Numer(x)*Numer(y))
,(Denom(x)*Denom(y))
);
}
else
{
/* La multiplication par 1 est indeterminee de facon a l'exclure de la recherche. */
}
break;
}
case DIVISION:
{
if (Numer(y) != 0)
{
if ( (Numer(y) != Denom(y))
|| (AccepterLesDivisionsParUn == VRAI)
)
{
EGAL(resultat
,(Numer(x)*Denom(y))
,(Denom(x)*Numer(y))
);
}
else
{
/* La division par 1 est indeterminee de facon a l'exclure de la recherche. */
}
}
else
{
/* La division par 0 est indeterminee de facon a l'exclure de la recherche. */
}
break;
}
case EXPONENTIATION:
{
if ( ((Numer(x)*Denom(x)) > 0)
&& ((Numer(y)*Denom(y)) > 0)
)
if ( (Numer(y) != Denom(y))
|| (AccepterLesExponentiationsParUn == VRAI)
)
{
EGAL(resultat
,pow(Numer(x),Numer(y)/Denom(y))
,pow(Denom(x),Numer(y)/Denom(y))
);
}
else
{
/* L'exponentiation unitaire est indeterminee de facon a l'exclure de la recherche. */
}
else
{
/* L'exponentiation negative ou nulle est indeterminee de facon a l'exclure de la recherche. */
}
break;
}
default:
{
fprintf(stderr,"L'operateur '%d' n'est pas reconnu\n",ListeOperators[IndexOperateur]);
}
}
}
else
{
}
return(resultat);
}
#define CONVERSION(operateur) \
COND(operateur == ADDITION \
,"+" \
,COND(operateur == SOUSTRACTION \
,"-" \
,COND(operateur == MULTIPLICATION \
,"*" \
,COND(operateur == DIVISION \
,"/" \
,COND(operateur == EXPONENTIATION \
,"^" \
,"?" \
) \
) \
) \
) \
)
#define FORMAT_s__ \
"%s"
#define FORMAT_ds_ \
"%d%s"
#define FORMAT_sd_ \
"%s%d"
#define FORMAT_dsd \
"(%d%s%d)"
#define EDITION(sequence) \
{ \
arbre++; \
\
if ( (Numer(R3) == RESULTAT_ATTENDU) \
&& (Denom(R3) == UNITE) \
) \
{ \
printf("arbre %d : ",arbre); \
sequence; \
printf(" = %d\n",Numer(R3)); \
} \
else \
{ \
} \
}
#define N1 \
ListeNombres[n1]
#define N2 \
ListeNombres[n2]
#define N3 \
ListeNombres[n3]
#define N4 \
ListeNombres[n4]
#define P1 \
Numer(N1)
#define P2 \
Numer(N2)
#define P3 \
Numer(N3)
#define P4 \
Numer(N4)
#define O1 \
CONVERSION(ListeOperators[o1])
#define O2 \
CONVERSION(ListeOperators[o2])
#define O3 \
CONVERSION(ListeOperators[o3])
main()
{
int n1,n2,n3,n4;
/* Index des 'nNOMBRES' nombres. */
for (n1=INDEX0 ; n1<nNOMBRES ; n1++)
{
EGAL(N1,ListeNombresEntiers[n1],UNITE);
/* Conversion des nombres entiers N en nombres rationnels N/1. */
}
for (n1=INDEX0 ; n1<nNOMBRES ; n1++)
{
for (n2=INDEX0 ; n2<nNOMBRES ; n2++)
{
for (n3=INDEX0 ; n3<nNOMBRES ; n3++)
{
for (n4=INDEX0 ; n4<nNOMBRES ; n4++)
{
if ( (PouvoirUtiliserPlusieursFoisChaqueNombre == VRAI)
|| ( (P1 != P2)
&& (P1 != P3)
&& (P1 != P4)
&& (P2 != P3)
&& (P2 != P4)
&& (P3 != P4)
)
)
/* Les 'nNOMBRES' nombres doivent etre tous utilises et ce une seule fois... */
{
int o1,o2,o3;
/* Index des 3 (=(nNOMBRES-1)) operateurs utiles (il en faut un de moins que de nombres...). */
for (o1=INDEX0 ; o1<nOPERATEURS ; o1++)
{
for (o2=INDEX0 ; o2<nOPERATEURS ; o2++)
{
for (o3=INDEX0 ; o3<nOPERATEURS ; o3++)
{
int arbre=0;
/* Identification de l'arbre utilise (1,2,...). */
Fraction R1,R2,R3;
R1=operation(n1,N1,o1,N2,n2);
R2=operation(n3,N3,o3,N4,n4);
R3=operation(ri,R1,o2,R2,ri);
EDITION(
{
printf(FORMAT_dsd,P1,O1,P2);
printf(FORMAT_s__,O2);
printf(FORMAT_dsd,P3,O3,P4);
}
);
/* Test de l'arbre symetrique ("1") : */
/* */
/* n1 n2 n3 n4 */
/* \ / \ / */
/* \ / \ / */
/* o1 o3 */
/* (R1) (R2) */
/* \ / */
/* \ / */
/* \ / */
/* \ / */
/* o2 */
/* (R3) */
/* */
/* soit : */
/* */
/* arbre 1 : (n1.o1.n2).o2.(n3.o3.n4) */
/* */
R1=operation(n1,N1,o1,N2,n2);
R2=operation(ri,R1,o2,N3,n3);
R3=operation(ri,R2,o3,N4,n4);
EDITION(
{
printf("(");
printf(FORMAT_dsd,P1,O1,P2);
printf(FORMAT_sd_,O2,P3);
printf(")");
printf(FORMAT_sd_,O3,P4);
}
);
/* Test du premier arbre dissymetrique ("2") : */
/* */
/* n1 n2 */
/* \ / */
/* \ / */
/* o1 n3 */
/* (R1) / */
/* \ / */
/* o2 n4 */
/* (R2) / */
/* \ / */
/* o3 */
/* (R3) */
/* */
/* soit : */
/* */
/* arbre 2 : ((n1.o1.n2).o2.n3).o3.n4 */
/* */
R1=operation(n2,N2,o2,N3,n3);
R2=operation(n1,N1,o1,R1,ri);
R3=operation(ri,R2,o3,N4,n4);
EDITION(
{
printf("(");
printf(FORMAT_ds_,P1,O1);
printf(FORMAT_dsd,P2,O2,P3);
printf(")");
printf(FORMAT_sd_,O3,P4);
}
);
/* Test du second arbre dissymetrique ("3") : */
/* */
/* */
/* n2 n3 */
/* \ / */
/* \ / */
/* n1 o2 */
/* \ (R1) */
/* \ / */
/* o1 n4 */
/* (R2) / */
/* \ / */
/* o3 */
/* (R3) */
/* */
/* soit : */
/* */
/* arbre 3 : (n1.o1.(n2.o2.n3)).o3.n4 */
/* */
R1=operation(n3,N3,o3,N4,n4);
R2=operation(n2,N2,o2,R1,ri);
R3=operation(n1,N1,o1,R2,ri);
EDITION(
{
printf(FORMAT_ds_,P1,O1);
printf("(");
printf(FORMAT_ds_,P2,O2);
printf(FORMAT_dsd,P3,O3,P4);
printf(")");
}
);
/* Test du troisieme arbre dissymetrique ("4") : */
/* */
/* */
/* */
/* */
/* */
/* n3 n4 */
/* \ / */
/* \ / */
/* n2 o3 */
/* \ (R1) */
/* \ / */
/* n1 o2 */
/* \ (R2) */
/* \ / */
/* o1 */
/* (R3) */
/* */
/* soit : */
/* */
/* arbre 4 : n1.o1.(n2.o2.(n3.o3.n4)) */
/* */
R1=operation(n2,N2,o2,N3,n3);
R2=operation(ri,R1,o3,N4,n4);
R3=operation(n1,N1,o1,R2,ri);
EDITION(
{
printf(FORMAT_ds_,P1,O1);
printf("(");
printf(FORMAT_dsd,P2,O2,P3);
printf(FORMAT_sd_,O3,P4);
printf(")");
}
);
/* Test du quatrieme arbre dissymetrique ("5") : */
/* */
/* */
/* n2 n3 */
/* \ / */
/* \ / */
/* o2 n4 */
/* (R1) / */
/* \ / */
/* n1 o3 */
/* \ (R2) */
/* \ / */
/* o1 */
/* (R3) */
/* */
/* soit : */
/* */
/* arbre 5 : n1.o1.((n2.o2.n3).o3.n4) */
/* */
}
}
}
}
else
{
}
}
}
}
}
}