Opera est un langage de programmation qui effectue des opérations arithmétiques mathématiquement exactes en utilisant des nombres rationnels. Le logiciel Opera complet est disponible à :
https://github.com/pgl10/Opera en versions Windows et Linux. Il est public et gratuit. Il est fourni avec les sources en C++, les exécutables, les nombreux exemples et la documentation en français. Le projet ici présent en contient tous les fichiers à l'exception des exécutables.
Opera effectue les opérations arithmétiques prévues sur des nombres rationnels représentés par des fractions de deux entiers aussi grands que nécessaires. Il utilise 7 opérateurs ayant deux opérandes, l'opérateur - ayant un seul opérande et de nombreuses fonctions spécifiques. Il a deux modes de fonctionnement : le mode conversationnel et l'exécution de fichiers de commandes. Opera.pdf est le manuel de l'utilisateur et description.pdf en est une simple présentation rapide.
Le code source en C++ affiché ci-après montre le calcul d'une expression arithmétique avec ou sans parenthèses en respectant les priorités relatives des opérateurs utilisés. Et l'exemple affiché ensuite montre le calcul d'une approximation du nombre pi.
Source :
// Pour calculer le contenu des parenthèses
bool parentheses(std::string& ligne) {
std::string ops = "^/*-+<>";
bool pars;
do {
pars = false;
std::size_t found = ligne.find('(');
// S'il y a encore des parenthèses dans ligne
if(found != std::string::npos) {
pars = true;
std::string front, back;
if(found == 0) front = "";
else {
front = ligne.substr(0, found);
if(ops.find(front[front.size()-1]) == std::string::npos) return false;
}
std::size_t last = std::string::npos;
int niv = 0;
unsigned int suiv = found + 1;
while(suiv < ligne.size()) {
if(ligne[suiv] == ')' && niv == 0) {
last = suiv;
break;
}
if(ligne[suiv] == '(') niv = niv + 1;
if(ligne[suiv] == ')') niv = niv - 1;
suiv = suiv + 1;
}
if(last == std::string::npos) return false;
// ligne[found] = '(' correspond à ligne[last] = ')'
if(last == ligne.size()-1) back = "";
else {
back = ligne.substr(last+1);
if(ops.find(back[0]) == std::string::npos) return false;
}
std::string subligne = ligne.substr(found+1, last-found-1);
// S'il faut effectuer le même traitement à subligne
if(subligne.find('(') != std::string::npos) parentheses(subligne);
bigRa subval;
if(eval(subligne, subval)) {
static int num = 0;
num = num+1;
std::stringstream stream;
stream << num;
std::string name;
// on utilise une nouvelle variable auxiliaire
name = "&t" + stream.str();
archiverra(lect, name, subval);
ligne = front + name + back;
}
else return false;
}
}while(pars);
return true;
}
// Pour calculer la valeur d'une instruction définie
bool eval(std::string ligne, bigRa& r) {
if(ligne.size() == 0) return false;
std::string ops = "^/*-+<>";
std::size_t found;
found = ops.find(ligne[ligne.size()-1]);
// le dernier caractère de ligne ne doit pas être un opérateur
if(found != std::string::npos) return false;
if(!parentheses(ligne)) return false;
if(cval(ligne, r)) return true;
// ligne[pos] est-il un opérateur ayant 2 opérandes ?
std::size_t pos=std::string::npos;
found = ligne.find_last_of("^");
if(found != std::string::npos) pos=found;
found = ligne.find_last_of("/");
if(found != std::string::npos) pos=found;
found = ligne.find_last_of("*");
if(found != std::string::npos) pos=found;
found = ligne.find_last_of("-");
if(found != std::string::npos) {
if(found == 0) {
ligne = "0" + ligne;
found = 1;
}
pos = found;
std::size_t opb1 = ops.find(ligne[found-1]);
if(opb1 != std::string::npos) {
unsigned int k;
bool op = false;
for(k=found+1; k < ligne.size(); k++) {
std::size_t nop = ops.find(ligne[k]);
if(nop != std::string::npos) {op=true; break;}
}
if(op) ligne = ligne.substr(0, found) + "(" + ligne.substr(found, k-found) + ")" + ligne.substr(k);
else ligne = ligne.substr(0, found) + "(" + ligne.substr(found, k-found) + ")";
if(!eval(ligne, r)) return false;
r.simplifier();
return true;
}
}
found = ligne.find_last_of("+");
if(found != std::string::npos) pos=found;
found = ligne.find_last_of("<");
if(found != std::string::npos) pos=found;
found = ligne.find_last_of(">");
if(found != std::string::npos) pos=found;
// s'il n'y a ici aucun opérateur : instruction non reconnue
if(pos == std::string::npos) return false;
// si un opérateur binaire est au début ou à la fin de ligne
// l'instruction ne sera pas reconnue
if(pos==(ligne.size()-1) || pos==0) return false;
std::string left = ligne.substr(0, pos);
std::string right = ligne.substr(pos+1);
// r1 et r2 seront les deux opérandes
bigRa r1, r2;
if(!cval(left, r1))
if(!eval(left, r1)) return false;
if(!cval(right, r2))
if(!eval(right, r2)) return false;
// calcul final du résultat
if(ligne[pos] == '^') {
if(r2.getDen() > INT_MAX) {
std::cout << "Exponentiation hors limites" << std::endl;
return false;
}
int n2d = r2.getDen();
if(n2d == 0) return false;
if(n2d > 1) {
int sr1 = 1;
if(cmpRa(r1, 0) < 0) {
if((n2d&1) == 0) {
aout("Ce calcul est impossible.n");
return false;
}
sr1 = -1;
}
bigRa t1 = r1;
bool good = true;
Integer rr1n = racine(n2d, sr1*r1.getNum());
Integer r1n = sr1;
for(int i=0; i<n2d; i++) r1n = r1n*rr1n;
if(r1n == r1.getNum()) r1.setNum(sr1*rr1n);
else {
irrationnel();
good = false;
}
Integer rr1d = racine(n2d, r1.getDen());
Integer r1d = 1;
for(int i=0; i<n2d; i++) r1d = r1d*rr1d;
if(r1d == r1.getDen()) r1.setDen(rr1d);
else {
if(good) irrationnel();
good = false;
}
if(!good) {
r1 = t1;
int k = approxim(0);
if(sr1 > 0) r1 = nroot(r1, n2d, k);
else r1 = -nroot(-r1, n2d, k);
}
}
if(r2.getNum() > INT_MAX) {
std::cout << "Exponentiation hors limites" << std::endl;
return false;
}
int n2n = r2.getNum();
r=r1.puissance(n2n);
}
if(ligne[pos] == '/') r=r1.diviser(r2);
if(ligne[pos] == '*') r=r1.multiplier(r2);
if(ligne[pos] == '-') r=r1.soustraire(r2);
if(ligne[pos] == '+') r=r1.additionner(r2);
if(ligne[pos] == '<') r=cmpRa(r2, r1);
if(ligne[pos] == '>') r=cmpRa(r1, r2);
r.simplifier();
return true;
}
Exemple :
Voici un exemple de code source en langage Opera qui calcule une suite d'approximations successives de pi jusqu'à celle dont la valeur comporte c chiffres décimaux exacts.
# Ce programme pi.txt en langage Opera calcule une approximation de pi
# ayant c chiffres décimaux exacts en utilisant la formule suivante.
# pi = 4 / (1 + 1² / (3 + 2² / (5 + 3² / (7 + 4² / (9 + ... )))))
c = 36
f[1] = 3
f[2] = 19/6
delta = f[2]-f[1]
n=2
delta > f[n]/10^c
boucle
n = n + 1
k = n
d = (2*k-1)+k^2/(2*k+1)
k > 1
boucle
k = k-1
d = (2*k-1)+k^2/d
retour
f[n] = 4/d
delta = f[n]-f[n-1]
si delta < 0
delta = -delta
retour
pi = f[n]
enti pi*10^c
garder resultat.txt
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.