From afb00b5d7d4a912a460a6fba31bb5426e9ac1673 Mon Sep 17 00:00:00 2001 From: YUH-Z Date: Wed, 2 Oct 2024 22:26:47 -0400 Subject: [PATCH] support exp operator --- src/enums/operator-keys.enum.ts | 1 + src/models/calculator.model.spec.ts | 40 +++++++++++++++++++++++++++++ src/models/calculator.model.ts | 36 ++++++++++++++++++++++---- 3 files changed, 72 insertions(+), 5 deletions(-) diff --git a/src/enums/operator-keys.enum.ts b/src/enums/operator-keys.enum.ts index 11fcbbf..286c1a2 100644 --- a/src/enums/operator-keys.enum.ts +++ b/src/enums/operator-keys.enum.ts @@ -3,4 +3,5 @@ export enum OperatorKeys { MINUS = "-", MULT = "*", DIV = "/", + EXP = "exp", } diff --git a/src/models/calculator.model.spec.ts b/src/models/calculator.model.spec.ts index e4bdaa6..7f7f588 100644 --- a/src/models/calculator.model.spec.ts +++ b/src/models/calculator.model.spec.ts @@ -269,6 +269,46 @@ describe("CalculatorModel", (): void => { calculator.pressActionKey(ActionKeys.EQUALS); expect(calculator.display()).toEqual("1"); }); + + it("should display e**1 with `exp(1)`", (): void => { + calculator.pressOperatorKey(OperatorKeys.EXP); + calculator.pressNumericKey(NumericKeys.ONE); + calculator.pressActionKey(ActionKeys.EQUALS); + const displayValue: string = calculator.display(); + expect(displayValue).toEqual("2.718281828459045"); + }); + + it("should display e**4 with `exp(4)`", (): void => { + calculator.pressOperatorKey(OperatorKeys.EXP); + calculator.pressNumericKey(NumericKeys.FOUR); + calculator.pressActionKey(ActionKeys.EQUALS); + const displayValue: string = calculator.display(); + expect(displayValue).toEqual("54.598150033144236"); + }); + + it("should display (e**9)+7 with `exp(9)+7)`", (): void => { + calculator.pressOperatorKey(OperatorKeys.EXP); + calculator.pressNumericKey(NumericKeys.NINE); + calculator.pressOperatorKey(OperatorKeys.PLUS); + calculator.pressNumericKey(NumericKeys.SEVEN); + calculator.pressActionKey(ActionKeys.EQUALS); + const displayValue: string = calculator.display(); + expect(displayValue).toEqual("8110.083927575384"); + }); + + it("should display (e**9)*7 with `exp(9)*7)`", (): void => { + calculator.pressOperatorKey(OperatorKeys.EXP); + calculator.pressNumericKey(NumericKeys.NINE); + calculator.pressOperatorKey(OperatorKeys.MULT); + calculator.pressNumericKey(NumericKeys.SEVEN); + calculator.pressActionKey(ActionKeys.EQUALS); + const displayValue: string = calculator.display(); + expect(displayValue).toEqual("56721.58749302769"); + }); + + // TODO(max): Test exp(negative) + // TODO(max): Support exp(exp(n)) + // TODO(max): Test 1+2+3+4... are they even legal? }); describe("CalculatorStateMachine", (): void => { diff --git a/src/models/calculator.model.ts b/src/models/calculator.model.ts index 5ee68c3..96fea3c 100644 --- a/src/models/calculator.model.ts +++ b/src/models/calculator.model.ts @@ -23,7 +23,7 @@ export class CalculatorModel implements ICalculatorModel { this._buffer += key; } - private pushNumber(): void { + private pushBuffer(): void { const num: number = parseFloat(this._buffer); this._numberStack.push(num); this._buffer = ""; @@ -37,13 +37,28 @@ export class CalculatorModel implements ICalculatorModel { } public pressOperatorKey(key: OperatorKeys): void { - this.pushNumber(); + this.pushBuffer(); if (this.getState() === State.ENTERING_FIRST_OPERAND) { - this.setState(State.ENTERING_SECOND_OPERAND); + if ( + this._operatorStack.length > 0 && + this._operatorStack[this._operatorStack.length - 1] === OperatorKeys.EXP + ) { + this._operatorStack.pop(); + const num: number = this.popNumber(); + console.log("doing exp", num); + const result: number = Math.exp(num); + console.log("...it's", result); + this._numberStack = [result]; + } + if (key !== OperatorKeys.EXP) { + // I do not understand what is going on here + this.setState(State.ENTERING_SECOND_OPERAND); + } } else if (this.getState() === State.ENTERING_SECOND_OPERAND) { if (key === OperatorKeys.PLUS || key === OperatorKeys.MINUS) { const op: OperatorKeys = this._operatorStack.pop(); // We can always collapse the stack. + assert(this._numberStack.length === 2); const right: number = this.popNumber(); const left: number = this.popNumber(); const result: number = this.compute(op, left, right); @@ -95,11 +110,22 @@ export class CalculatorModel implements ICalculatorModel { this._buffer += "."; break; case ActionKeys.EQUALS: { - this.pushNumber(); + this.pushBuffer(); if (this.getState() === State.ENTERING_FIRST_OPERAND) { - this._buffer = this.popNumber().toString(); + if ( + this._operatorStack[this._operatorStack.length - 1] === + OperatorKeys.EXP + ) { + this._operatorStack.pop(); + const num: number = this.popNumber(); + const result: number = Math.exp(num); + this._buffer = result.toString(); + } else { + this._buffer = this.popNumber().toString(); + } } else if (this.getState() === State.ENTERING_SECOND_OPERAND) { const op: OperatorKeys = this._operatorStack.pop(); + assert(this._numberStack.length === 2); const right: number = this.popNumber(); const left: number = this.popNumber(); const result: number = this.compute(op, left, right);