Mon interpréteur Fractran

Description

Fractran est un langage ésotérique de programmation inventé par John Conway.

La documentation disponible sur Internet à ce sujet est assez abondante.

Un programme Fractran est une suite ordonnée de k fractions positives : q1, q2,...,qk

On commence avec une valeur initiale entière et positive x0

Et on calcule xi+1 = qj*xi où qj est la première fraction telle que qj*xi soit entier.

En continuant ainsi, il peut arriver ensuite :

- Soit aucune fraction qj ne convient : la valeur finale xn est le résultat.
On peut donc écrire f(x0)=xn
- Soit les itérations continuent indéfiniment. Ceci arrive toujours si on
retrouve une valeur xi déjà trouvée précédemment, il y a un bouclage dans ce cas.
Mais on peut aussi avoir des itérations indéfiniment sans bouclage.

Ci-joints, des exemples permettent le calcul de la somme, du minimum ou du pgcd
de deux entiers et même des premiers nombres premiers dans l'ordre croissant.

Dans cette version basique de l'interpréteur Fractran, on arrête arbitrairement
les itérations à la 10000-ième.
De plus, on contrôle les valeurs intermédiaires et on arrête aussi les itérations
quand l'une de ces valeurs dépasse le maximum des entiers sur 8 octets utilisés ici.

Il y a un supplément d'informations dans le fichier explications.txt
et un mode d'emploi dans le fichier emploi.txt

Cette deuxième version comporte quelques améliorations et beaucoup
des commentaires de CptPingu y sont repris. Merci CptPingu.

Source / Exemple :


 
/************************************************
*  Interpréteur Fractran version 2.4 par pgl10  *
*                                               *
*  Pour l'utiliser il faut faire :              *
*                                               *
*  fractran x0 fractions.txt [output.txt]       *
*                                               *
************************************************/
   
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <stdint.h>
   
void my_pause() {
    std::cout << std::endl;
    system("pause");    
}
   
void erreur(std::string message) {
    std::cout << std::endl << message << std::endl;
    my_pause();
}
   
int stringToInt(const std::string& s) {
    int x;
    std::istringstream buff(s.c_str());
    buff >> x;
    return x;
}
   
void fractions(std::string ligne, int* nf, int** num, int** den) {
    // On compte le nombre de fractions 
    *nf = 0;
    int ll = ligne.length();
    for(int i=0; i<ll; i++) {
        if(ligne.c_str()[i] == '/') *nf=*nf+1;
    }
    // On met en place la liste des nf fractions
    *num = new int[*nf];
    *den = new int[*nf];
    std::size_t begin, end = -1;
    for(int i=0; i<*nf; i++) {
        begin = ligne.find_first_of("0123456789", end + 1);
        end = ligne.find_first_not_of("0123456789", begin + 1);
        (*num)[i] = stringToInt(ligne.substr(begin, end - begin));
        begin = ligne.find_first_of("0123456789", end + 1);
        end = ligne.find_first_not_of("0123456789", begin + 1);
        (*den)[i] = stringToInt(ligne.substr(begin, end - begin));
    }
}
   
std::string facteurs(uint64_t x) {
    // Pour imprimer x0 ou xn en facteurs premiers
    // On calcule seulement les facteurs de 2 à 23 de x
    int expos[9], prems[9]={2,3,5,7,11,13,17,19,23};
    uint64_t xx;
    xx=x;
    for(int i=0; i<9; i++) {
        expos[i]=0;
        while(xx%prems[i]==0) {
            expos[i]++;
            xx/=prems[i];
        }
    }
    // On calcule la chaine de sortie
    std::string s ("");
    int t=0;
    for(int i=0; i<9; i++) t+=expos[i];
    if(t == 0) return s;
    std::stringstream ss;
    for(int i=0; i<9; i++) {
        if(expos[i] != 0) {
            ss << "(" << prems[i] << "^" << expos[i] << ")"; 
        }       
    }
    if(xx != 1) ss << "*" << xx;
    ss >> s;
    return " = " + s;
}
   
int fractran(char* fi_fracts, uint64_t x, std::ostream& out) {
    // On calcule max = (2^64)-1 : le maximum des uint64_t
    int n=1;
    uint64_t max=1;
    for(int i=1; i<64; i++) {n*=2; max+=n;} 
    // Le programme Fractran est dans la première ligne du fichier fi_fracts
    std::string ligne;
    std::ifstream in_file(fi_fracts, std::ios::in); 
    if(in_file) std::getline(in_file, ligne);
    else {
        std::cout << "Erreur pour le fichier contenant les fractions" << std::endl;
        return 1;
    }
    // On affiche l'entête
    out << std::endl << "Programme Fractran avec les fractions de " << std::string(fi_fracts) 
        << " : " << std::endl << std::endl << ligne << std::endl << std::endl;
    // On affiche la valeur initiale
    out << "et la valeur initiale x0 : " << x << facteurs(x) << std::endl << std::endl;
    // On calcule les nf fractions num[i]/den[i] pour i = 0 à nf-1
    int nf;
    int *num, *den;
    fractions(ligne, &nf, &num, &den);
    // On itère en cherchant à chaque fois la première fraction qui convient.
    bool fini=false;
    n = 0; 
    do {
        out << "n = " << n << "    x = " << x << std::endl;
        int i;
        for(i=0; i<nf; i++) {
            // Si le calcul dépasse la limite des entiers sur 8 octets.
            if(x>(max/num[i])) {
                out << std::endl << "Stop : x est trop grand !" << std::endl;
                fini=true;
                break;
            }
            // Si la i-ième fraction fournit un x suivant entier.
            if((x*num[i])%den[i]==0) {
                x=x*num[i]/den[i]; 
                break;
            }
        }
        // Si aucune fraction fournit un x suivant entier : on a la valeur finale.
        if(i==nf) {
            out << std::endl << "Stop : la suite est finie !" << std::endl;
            out << std::endl << "Et la valeur finale xn : " << x << facteurs(x) << std::endl;
            fini=true;
        }
        n=n+1;
        // Si n est trop grand : on arrête arbitrairement à la 10000-ième itération.
        if(n==10000) {
            out << std::endl << "Stop : n est arbitrairement trop grand !" << std::endl;
            fini=true;
        }
    }while(!fini);
    delete [] num;
    delete [] den;
    return 0;
}
   
int main(int argc, char *argv[]) { 
    // Il faut 3 ou 4 arguments seulement dans l'appel 
    if(argc<3 || argc>4) {
        erreur("Il faut faire : fractran x0 fractions.txt [output.txt]");
        return 1;
    }
    //  On lit la valeur initiale x0
    uint64_t x0;
    if(!(sscanf_s(argv[1], "%I64d", &x0)>0)) {
        erreur("Erreur de lecture pour la valeur initiale");
        return 1;
    }
    if(x0 < 1) {
        erreur("Il faut que x0 soit un entier positif");
        return 1;
    }
    // On ouvre le fichier éventuel de sortie des résultats 
    // et on effectue le programme Fractran
    // contenu dans argv[2] avec la valeur initiale x0
    // Les résultats sont affichés dans le fichier demandé ou sur la console.
    if(argc==4) {
        std::ofstream out_file(argv[3]);
        fractran(argv[2], x0, out_file);
    }
    else fractran(argv[2], x0, std::cout);
    my_pause();
    return 0;
}

Conclusion :


Merci pour vos commentaires et remarques.

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.