Skip to content
Open

ha1 #101

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 76 additions & 31 deletions app/src/main/java/htw/berlin/prog2/ha1/Calculator.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@ public class Calculator {

private String screen = "0";

private double latestValue;
private double latestValue = 0;

private String latestOperation = "";

//Hilft zu erkennen, ob der Bildschirminhalt neu ist oder nicht
private boolean isNewInput = true;

/**
* @return den aktuellen Bildschirminhalt als String
*/
Expand All @@ -23,69 +26,85 @@ public String readScreen() {

/**
* Empfängt den Wert einer gedrückten Zifferntaste. Da man nur eine Taste auf einmal
* drücken kann muss der Wert positiv und einstellig sein und zwischen 0 und 9 liegen.
* drücken kann, muss der Wert positiv und einstellig sein und zwischen 0 und 9 liegen.
* Führt in jedem Fall dazu, dass die gerade gedrückte Ziffer auf dem Bildschirm angezeigt
* oder rechts an die zuvor gedrückte Ziffer angehängt angezeigt wird.
* oder rechts an die zuvor gedrückte Ziffer angehängt angezeigt wird. Wird die Taste nach einer Operation gedrückt,
* wird der Bildschirminhalt zurückgesetzt.
* @param digit Die Ziffer, deren Taste gedrückt wurde
*/
public void pressDigitKey(int digit) {
if(digit > 9 || digit < 0) throw new IllegalArgumentException();

if(screen.equals("0") || latestValue == Double.parseDouble(screen)) screen = "";

screen = screen + digit;
//Wenn eine Operationstaste gedrückt wurde, wird der Bildschirminhalt zurückgesetzt
if (isNewInput) {
screen = "";
isNewInput = false;
}

screen += digit;
}

/**
* Empfängt den Befehl der C- bzw. CE-Taste (Clear bzw. Clear Entry).
* Einmaliges Drücken der Taste löscht die zuvor eingegebenen Ziffern auf dem Bildschirm
* so dass "0" angezeigt wird, jedoch ohne zuvor zwischengespeicherte Werte zu löschen.
* Einmaliges Drücken der Taste löscht die zuvor eingegebenen Ziffern auf dem Bildschirm,
* sodass "0" angezeigt wird, jedoch ohne zuvor zwischengespeicherte Werte zu löschen.
* Wird daraufhin noch einmal die Taste gedrückt, dann werden auch zwischengespeicherte
* Werte sowie der aktuelle Operationsmodus zurückgesetzt, so dass der Rechner wieder
* Werte sowie der aktuelle Operationsmodus zurückgesetzt, sodass der Rechner wieder
* im Ursprungszustand ist.
*/
public void pressClearKey() {
screen = "0";
latestOperation = "";
latestValue = 0.0;
isNewInput = true;
}

/**
* Empfängt den Wert einer gedrückten binären Operationstaste, also eine der vier Operationen
* Addition, Substraktion, Division, oder Multiplikation, welche zwei Operanden benötigen.
* Beim ersten Drücken der Taste wird der Bildschirminhalt nicht verändert, sondern nur der
* Rechner in den passenden Operationsmodus versetzt.
* Beim zweiten Drücken nach Eingabe einer weiteren Zahl wird direkt des aktuelle Zwischenergebnis
* Beim zweiten Drücken nach Eingabe einer weiteren Zahl wird direkt das aktuelle Zwischenergebnis
* auf dem Bildschirm angezeigt. Falls hierbei eine Division durch Null auftritt, wird "Error" angezeigt.
* @param operation "+" für Addition, "-" für Substraktion, "x" für Multiplikation, "/" für Division
*/
public void pressBinaryOperationKey(String operation) {
latestValue = Double.parseDouble(screen);
calculateIntermediateResult();
latestOperation = operation;
isNewInput = true;
}

/**
* Empfängt den Wert einer gedrückten unären Operationstaste, also eine der drei Operationen
* Quadratwurzel, Prozent, Inversion, welche nur einen Operanden benötigen.
* Beim Drücken der Taste wird direkt die Operation auf den aktuellen Zahlenwert angewendet und
* der Bildschirminhalt mit dem Ergebnis aktualisiert.
* der Bildschirminhalt mit dem Ergebnis aktualisiert. Falls hierbei eine Quadratwurzel aus einer
* negativen Zahl berechnet werden soll, wird "Error" angezeigt.
* @param operation "√" für Quadratwurzel, "%" für Prozent, "1/x" für Inversion
*/
public void pressUnaryOperationKey(String operation) {
latestValue = Double.parseDouble(screen);
latestOperation = operation;
var result = switch(operation) {
case "√" -> Math.sqrt(Double.parseDouble(screen));
case "%" -> Double.parseDouble(screen) / 100;
case "1/x" -> 1 / Double.parseDouble(screen);
double currentValue = Double.parseDouble(screen);
double result;

if (operation.equals("√") && currentValue < 0) {
screen = "Error";
isNewInput = true;
return;
}

result = switch (operation) {
case "√" -> Math.sqrt(currentValue);
case "%" -> currentValue / 100;
case "1/x" -> 1 / currentValue;
default -> throw new IllegalArgumentException();
};
screen = Double.toString(result);
if(screen.equals("NaN")) screen = "Error";
if(screen.contains(".") && screen.length() > 11) screen = screen.substring(0, 10);

screen = formatResult(result);
isNewInput = true;
}


/**
* Empfängt den Befehl der gedrückten Dezimaltrennzeichentaste, im Englischen üblicherweise "."
* Fügt beim ersten Mal Drücken dem aktuellen Bildschirminhalt das Trennzeichen auf der rechten
Expand All @@ -94,7 +113,7 @@ public void pressUnaryOperationKey(String operation) {
* Beim zweimaligem Drücken, oder wenn bereits ein Trennzeichen angezeigt wird, passiert nichts.
*/
public void pressDotKey() {
if(!screen.contains(".")) screen = screen + ".";
if (!screen.contains(".")) screen += ".";
}

/**
Expand All @@ -118,16 +137,42 @@ public void pressNegativeKey() {
* und das Ergebnis direkt angezeigt.
*/
public void pressEqualsKey() {
var result = switch(latestOperation) {
case "+" -> latestValue + Double.parseDouble(screen);
case "-" -> latestValue - Double.parseDouble(screen);
case "x" -> latestValue * Double.parseDouble(screen);
case "/" -> latestValue / Double.parseDouble(screen);
default -> throw new IllegalArgumentException();
calculateIntermediateResult();
latestOperation = ""; // Setzt Operation zurück
}

/**
* Berechnet das Zwischenergebnis der aktuellen Operation und aktualisiert den Bildschirminhalt.
* Wird aufgerufen, wenn eine binäre Operationstaste gedrückt wird oder die "="-Taste.
* Bei Division durch Null wird "Error" angezeigt.
*
*/
private void calculateIntermediateResult() {
double currentValue = Double.parseDouble(screen);

latestValue = switch (latestOperation) {
case "+" -> latestValue + currentValue;
case "-" -> latestValue - currentValue;
case "x" -> latestValue * currentValue;
// Division durch Null wird als Fehler behandelt
case "/" -> currentValue == 0 ? Double.POSITIVE_INFINITY : latestValue / currentValue;
default -> currentValue;
};
screen = Double.toString(result);
if(screen.equals("Infinity")) screen = "Error";
if(screen.endsWith(".0")) screen = screen.substring(0,screen.length()-2);
if(screen.contains(".") && screen.length() > 11) screen = screen.substring(0, 10);

screen = formatResult(latestValue);
isNewInput = true;
}

/**
* Formatiert das Ergebnis als String, sodass es auf dem Bildschirm angezeigt werden kann.
* Entfernt ".0" am Ende von ganzen Zahlen.
* @param result das Ergebnis als double
* @return
*/
private String formatResult(double result) {
if (Double.isInfinite(result)) return "Error";
String resultStr = Double.toString(result);
if (resultStr.endsWith(".0")) resultStr = resultStr.substring(0, resultStr.length() - 2);
return resultStr.length() > 11 ? resultStr.substring(0, 10) : resultStr;
}
}
142 changes: 142 additions & 0 deletions app/src/test/java/htw/berlin/prog2/ha1/CalculatorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -90,5 +90,147 @@ void testMultipleDecimalDots() {


//TODO hier weitere Tests erstellen

@Test
@DisplayName("should display result after subtracting two negative numbers")
void testNegativeSubstraction() {
Calculator calc = new Calculator();

calc.pressDigitKey(3);
calc.pressNegativeKey();
calc.pressBinaryOperationKey("-");
calc.pressDigitKey(8);
calc.pressNegativeKey();
calc.pressEqualsKey();

String expected = "5";
String actual = calc.readScreen();

assertEquals(expected, actual);
}
@Test
@DisplayName("should clear the previous number and display the new number")
void testClearKey() {
Calculator calc = new Calculator();

calc.pressDigitKey(3);
calc.pressClearKey();
calc.pressDigitKey(8);
calc.pressBinaryOperationKey("+");
calc.pressDigitKey(5);
calc.pressEqualsKey();
calc.pressClearKey();
calc.pressClearKey();
calc.pressBinaryOperationKey("+");
calc.pressDigitKey(2);
calc.pressEqualsKey();

String expected = "2";
String actual = calc.readScreen();

assertEquals(expected, actual);
}

@Test
@DisplayName("should display result after inverting a number")
void testInverseKey() {
Calculator calc = new Calculator();

calc.pressDigitKey(5);
calc.pressUnaryOperationKey("1/x");


String expected = "0.2";
String actual = calc.readScreen();

assertEquals(expected, actual);
}

@Test
@DisplayName("should display result after adding two big numbers")
void testBigNumbers() {
Calculator calc = new Calculator();

calc.pressDigitKey(9);
calc.pressDigitKey(9);
calc.pressDigitKey(9);
calc.pressDigitKey(9);
calc.pressDigitKey(9);
calc.pressDigitKey(9);
calc.pressBinaryOperationKey("+");
calc.pressDigitKey(9);
calc.pressDigitKey(9);
calc.pressDigitKey(9);
calc.pressDigitKey(9);
calc.pressDigitKey(9);
calc.pressDigitKey(9);
calc.pressEqualsKey();

String expected = "1999998";
String actual = calc.readScreen();

assertEquals(expected, actual);
}

@Test
@DisplayName("should display error when dividing by zero after a prior operation")
void testDivisionByZeroAfterOperation() {
Calculator calc = new Calculator();

calc.pressDigitKey(9);
calc.pressBinaryOperationKey("-");
calc.pressDigitKey(4);
calc.pressEqualsKey();

calc.pressBinaryOperationKey("/");
calc.pressDigitKey(0);
calc.pressEqualsKey();

String expected = "Error";
String actual = calc.readScreen();

assertEquals(expected, actual);
}

//Gab "NaN" statt "Error" aus
@Test
@DisplayName("should display error when dividing zero by zero")
void testZeroDividedByZero() {
Calculator calc = new Calculator();

calc.pressDigitKey(0);
calc.pressBinaryOperationKey("/");
calc.pressDigitKey(0);
calc.pressEqualsKey();

String expected = "Error";
String actual = calc.readScreen();

assertEquals(expected, actual);
}

//multple operations was not possible
@Test
@DisplayName("should display result after multiple operations")
void testMultipleOperations() {
Calculator calc = new Calculator();

calc.pressDigitKey(5);
calc.pressBinaryOperationKey("+");
calc.pressDigitKey(5);
calc.pressBinaryOperationKey("-");
calc.pressDigitKey(3);
calc.pressBinaryOperationKey("x");
calc.pressDigitKey(2);
calc.pressBinaryOperationKey("/");
calc.pressDigitKey(2);
calc.pressEqualsKey();

String expected = "7";
String actual = calc.readScreen();

assertEquals(expected, actual);
}

}