Signaler

Calculatrice Rpn [Résolu]

Posez votre question etbienwi 13Messages postés lundi 16 octobre 2017Date d'inscription 7 novembre 2017 Dernière intervention - Dernière réponse le 7 nov. 2017 à 22:28 par etbienwi
Bonjour,
Je travaille sur une calculatrice Rpn.
J'ai une énumération Opérations qui contient les différentes opérations et la méthode de calcul associé.
package calculatrice;

 public enum Operations{
	 Plus("+"){

		@Override
		public double eval(double x, double y) {
				 return x + y;
		}	 
	 },
	 MOINS("-"){
		@Override
		public double eval(double x, double y) {
			return x - y;
		}
},
	 MULT("*"){

		@Override
		public double eval(double x, double y) {
			
			return x*y ;
		}
}, 
	DIV("/"){

		@Override
		public double eval(double x, double y) {
			
			return x/y;
		}
};
				
private String symbole;
	 
private  Operations(String s){
		 this.symbole = s;
	 }
	 	 public abstract double eval(double x, double y);
 
 };

Je dois faire une classe Moteur qui permet d’enregistrer les opérandes et d’effectuer le calcul.
J'ai utilisé une pile pour ranger les opérandes mais je suis perdu pour le calcul en utilisant l'énumération.

package calculatrice;

import java.util.*;

public class MoteurRPN  {
	Stack<Double> p = new Stack<Double> ();
	
	public void enregistrer(Double v) {
		p.push(v);
	}
	
	public void calcul() {
		Operations op = Operations.Plus;
		if (op == Operations.Plus) {
			Double v = p.pop();
			Double y = p.pop();
			double result ;
			result = Operations.Plus.eval(v, y);
			p.push(result);
			
		}
			
		
		}
	}

Voila mon essai pour l'addition, est ce possible de faire comme cela?Je ne sais pas trop comment je suis sensé gérer les chiffres et opérateurs.

Merci d'avance.
Utile
+0
plus moins
Bonjour,

Je trouve maladroit de faire une méthode abstract dans l'enum et faire autant de classes concrètes que de valeurs de l'enum.

Il y a des alternatives plus intéressantes.

package calculatrice;

public enum Operations {
    PLUS("+"), MOINS("-"), MULT("*"), DIV("/");

    private String symbole;

    private Operations(String s) {
        symbole = s;
    }

    public final double eval(double x, double y) {
        switch (this) {
        case PLUS:
            return x + y;
        case MOINS:
            return x - y;
        case MULT:
            return x * y;
        case DIV:
            return x / y;
        default:
            throw new IllegalStateException("eval(double,double) is not implemented for " + this);
        }
    }
};

Ou en Java 8 ou 9 :

package calculatrice;

import java.util.function.BiFunction;

public enum Operations {
    PLUS("+", (x, y) -> x + y),
    MOINS("-", (x, y) -> x - y),
    MULT("*", (x, y) -> x * y),
    DIV("/", (x, y) -> x / y);

    private final String symbole;
    private final BiFunction<Double, Double, Double> function;

    private Operations(String s, BiFunction<Double, Double, Double> function) {
        symbole = s;
        this.function = function;
    }

    public double eval(double x, double y) {
        return function.apply(x, y);
    }
};

Quant à ton moteur, tu ne peux pas stocker que les opérandes dans ta stack, il faut aussi stocker les opérateurs.

Exemple :
MOINS PLUS 3 4 1
qui donne
Moins(Plus(3,4),1)
c'est à dire (3+4)-1

Pour faire ça il faudrait que tu ais une interface (par exemple Token) partagée entre ton enum Operations (qu'il serait sage de renommer Operator) et une classe Operand, et que dans ta pile tu ne manipules que des Token (alternativement des Operator et ses Operand)

Exemple :

public enum TokenType {
    OPERAND, OPERATOR
}

public interface Token {
    TokenType getType();
}

public class Operand implements Token {
    private final double value;

    public Operand(double value) {
        this.value = value;
    }

    public double getValue() {
        return value;
    }

    @Override
    public TokenType getType() {
        return TokenType.OPERAND;
    }
}

public enum Operator implements Token {
    PLUS((x, y) -> x + y),
    MOINS((x, y) -> x - y),
    MULT((x, y) -> x * y),
    DIV((x, y) -> x / y);

    private final BiFunction<Double, Double, Double> function;

    private Operator(BiFunction<Double, Double, Double> function) {
        this.function = function;
    }

    public Operand eval(Operand x, Operand y) {
        return new Operand(function.apply(x.getValue(), y.getValue()));
    }

    @Override
    public TokenType getType() {
        return TokenType.OPERATOR;
    }
};

public static Operand nextOperand(Stack<Token> tokens) {
    Token token = tokens.pop();
    switch (token.getType()) {
    case OPERAND:
        return (Operand) token;
    case OPERATOR:
        Operand op1 = nextOperand(tokens);
        Operand op2 = nextOperand(tokens);
        return ((Operator) token).eval(op1, op2);
    default:
        throw new IllegalStateException("Unknown " + token.getType());
    }
}

public static void main(String[] args) {
    Stack<Token> tokens = new Stack<Token>();
    tokens.push(new Operand(1));
    tokens.push(new Operand(4));
    tokens.push(new Operand(3));
    tokens.push(Operator.PLUS);
    tokens.push(Operator.MOINS);
    System.out.println(nextOperand(tokens).getValue()); // 6.0
}
etbienwi 13Messages postés lundi 16 octobre 2017Date d'inscription 7 novembre 2017 Dernière intervention - 6 nov. 2017 à 23:38
Bonjour,
Merci beaucoup, avec les exemples j'ai bien compris maintenant comme cela fonctionne( Grace aux liens je vais pouvoir approfondir ).
Je veux essayer maintenant d'utiliser la classe scanner de java.util pour entrer mes opérandes et faire le calcul. J'ai fait une autre classe qui est sensé utiliser la classe opérande. Cette dernière fait déjà tout le travail et je ne sais pas comment les lier.
J'ai obtenu cela:

public void lancement() {
Stack<Token> tokens = new Stack<Token>();
System.out.println("Veuillez saisir l'opérande");
Double str = sc.nextDouble();
new Operand(str = sc.nextDouble());
tokens.push (new Operand(str));

}


Est ce c'est de cette manière que l'on est sensé le faire?
Merci d'avance.
Répondre
KX 15004Messages postés samedi 31 mai 2008Date d'inscription ModérateurStatut 13 novembre 2017 Dernière intervention - 6 nov. 2017 à 23:45
La ligne
new Operand(str = sc.nextDouble());
ne sert à rien, mais sinon le reste c'est ça... ceci dit c'est assez limité de partir du principe que l'on a forcément une opérande alors qu'on devrait aussi pouvoir saisir un opérateur.
Répondre
etbienwi 13Messages postés lundi 16 octobre 2017Date d'inscription 7 novembre 2017 Dernière intervention - 7 nov. 2017 à 15:26
J'ai essaye de configurer la saisie pour qu'on puisse mettre des opérandes et des opérateurs.
J'ai voulu utiliser la même méthode que pour le nextOperand mais je ne m'en sors pas vraiment.

public static Double lancement() {
Stack<Token> tokens = new Stack<Token>();
double d;
System.out.println("combien de parametre aller vous rentrer");
int nbr = sc.nextInt();
for(int i =1; i<=nbr; i++) {
System.out.println("Veuillez saisir l'opérande");
String str = sc.next();
Token token =( ?);
switch (token.getType()) {
case OPERAND:
d = Double.parseDouble (str);
tokens.push (new Operand(d));
case Operator:
tokens.push( Operator.valueOf(str));
break;
}
}
double h = cacul(tokens);
return h;

comment faire pour que ce qui rentre en paramètre puisse être considéré comme une Opérande ou un Opérateur.
Répondre
KX 15004Messages postés samedi 31 mai 2008Date d'inscription ModérateurStatut 13 novembre 2017 Dernière intervention - 7 nov. 2017 à 18:12
Un exemple :

private static Optional<Token> parseOperator(String line) {
    try {
        return Optional.of(Operator.valueOf(line));
    } catch (RuntimeException e) {
        return Optional.empty();
    }
}

private static Optional<Token> parseOperand(String line) {
    try {
        return Optional.of(new Operand(Double.parseDouble(line)));
    } catch (RuntimeException e) {
        return Optional.empty();
    }
}

@SuppressWarnings("resource")
public static Stack<Token> readTokens() {
    Stack<Token> tokens = new Stack<Token>();
    Scanner sc = new Scanner(System.in);
    while (true) {
        System.out.println("Saisir une opérande [double], un opérateur " + EnumSet.allOf(Operator.class) + " ou une ligne vide pour terminer.");
        String line = sc.nextLine();
        if (line.isEmpty())
            return tokens;
        Token token = parseOperator(line).orElse(parseOperand(line).orElse(null));
        if (token != null) {
            tokens.push(token);
        } else {
            System.out.println("Saisie invalide : " + line);
        }
    }
}
Répondre
etbienwi 13Messages postés lundi 16 octobre 2017Date d'inscription 7 novembre 2017 Dernière intervention - 7 nov. 2017 à 22:28
Merci beaucoup pour ton aide et tes explications.Maintenant qu'il différencie les opérandes et les opérateurs , je n'ai plus eu qu'à récupérer le résultat et à l'afficher. Je vais tacher de me familiariser avec tout ce que j'ai appris(Lire les documentations) pour pouvoir les réutiliser au bon moment.
Répondre
Donnez votre avis

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.

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

Vous n'êtes pas encore membre ?

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