2021年1月21日星期四

How to write an algorithm that mimics a Calculator using Immediate Execution

I'm hoping someone could help me fix a bug in my calculator that I dont know how to get around.

For starters, I'm making a little program that models a calculator using immediate execution. As an overview, I had to dig through the internet to find out how immediate execution works for calculators so here's an explanation.

Traditional scientific calculators that respond immediately to key presses have an X and a Y register. The X register is hidden and the Y register appears on the display. When you enter a value it is shifted into the Y register. If you press a binary operator key like + or * the value in the Y register is copied into the X register, the operation is stored, and the Y register is set to accept a new entry. If you then press another binary operator key then the X and Y registers are combined using the stored pending operator, the result is placed in the X register, the key press is stored as a new pending operator, and the Y register is reset to accept a new entry. There are variations around this for the = key (a no-op), for example. Citation

So far, I have implemented this in Swift using a superclass (AbstractCalculator) and a subclass of it (AbstractBinaryCalculator)

open class AbstractCalculator {        public var _currentOperator : String = ""      public var _currentNumberEnteredIn : String = ""        public init() {}        /**       Inputs a single digit into the current number being entered       - Parameter digit: A single digit       */      open func inputDigit(_ digit : Character) {          self._currentNumberEnteredIn += String(digit)      }            open func inputEqualsSign() {          fatalError("Need to override in subclasses")      }                    open func inputOperator(_ calculatorOperator : String) {          fatalError("Need to override in subclasses")      }      }        open class AbstractBinaryCalculator : AbstractCalculator {        public var _operatorDictionary = [String : ((String, String) -> String)]()        public var _accumulatedResult : String = ""            open override func inputDigit(_ digit: Character) {          self._currentNumberEnteredIn += String(digit)      }        open func _saveCurrentNumberToAccumulatedResultIfNeeded() {          if self._accumulatedResult.isEmpty {              self._accumulatedResult = self._currentNumberEnteredIn          }      }        open override func inputOperator(_ calculatorOperator: String) {          if canPerformCalculation() {              self._performCalculationAndSetAccumulatedResult()          }          self._currentOperator = calculatorOperator          self._saveCurrentNumberToAccumulatedResultIfNeeded()          self._currentNumberEnteredIn = ""      }        open override func inputEqualsSign() {          if canPerformCalculation() {              self._performCalculationAndSetAccumulatedResult()          }      }        public func canPerformCalculation() -> Bool {          let hasAccumulatedResult = !self._accumulatedResult.isEmpty          let hasCurrentOperator = !self._currentOperator.isEmpty          let isCurrentNumberEntered = !self._currentNumberEnteredIn.isEmpty          return (hasAccumulatedResult && hasCurrentOperator && isCurrentNumberEntered)      }        open func _performCalculationAndSetAccumulatedResult() {          let result = getResultUsingCurrentFunctionOnAccumulatedResultAndCurrentNumber()          self._accumulatedResult = result      }        public func getResultUsingCurrentFunctionOnAccumulatedResultAndCurrentNumber() -> String {          let function = getMathOperatorFunction()          let currentNumberEnteredIn = self._currentNumberEnteredIn          let accumulatedResult = self._accumulatedResult          let result = function(accumulatedResult, currentNumberEnteredIn)          return result      }        public func getMathOperatorFunction() -> (String, String) -> String {          let mathOperator = self._currentOperator          let function = self._operatorDictionary[mathOperator]!          return function      }        /**       Adds a new function to the calculator.       - Parameter operatorFunction: An AbstractCalculatorOperator object       */      public func addOperatorFunction(_ operatorFunction : AbstractBinaryCalculatorOperator) {          let mathOperator = operatorFunction.getOperatorSymbol()          let function = operatorFunction.getFunction()          self.addOperatorFunction(mathOperator, function: function)      }        /**       Adds a new function to the calculator.       - Parameter operatorSymbol: The symbol for the operator (+,-,% etc)       - Parameter function: The function that will perform logic.       */      public func addOperatorFunction(_ operatorSymbol : String, function : @escaping (String,   String) -> String) {          self._listOfMathOperators.append(operatorSymbol)          self._operatorDictionary[operatorSymbol] = function      }      }  

And to test out the calculators' functionality and test I made a small simple subclass of AbstractBinaryCalculator called IntegerCalculator.

public class IntegerCalculator : AbstractBinaryCalculator {        public override init() {          super.init()          self.addOperatorFunction("+", function: self.add(number1:number2:))          self.addOperatorFunction("-", function: self.subtract(number1:number2:))          self.addOperatorFunction("*", function: self.multiply(number1:number2:))      }            private func add(number1 : String, number2 : String) -> String {          let result = Int(number1)! + Int(number2)!          return String(result)      }        private func subtract(number1 : String, number2 : String) -> String {          let result = Int(number1)! - Int(number2)!          return String(result)      }        private func multiply(number1 : String, number2 : String) -> String {          let result = Int(number1)! * Int(number2)!          return String(result)      }    }  

I then began to test out the code by running tests and all of them passed until I got to "testCalculation9" where I just don't know how to fix it. Can someone help me fix this bug?

import XCTest  @testable import AbstractCalculator    final class AbstractCalculatorTests: XCTestCase {      func testCalculation1() throws {            let intCalculator = IntegerCalculator()            XCTAssertEqual(intCalculator._currentNumberEnteredIn, "", "Incorrect")              }    func testCalculation2() throws {      let integerCalculator = IntegerCalculator()      integerCalculator.inputDigit("2")        XCTAssertEqual(integerCalculator._currentNumberEnteredIn, "2", "Incorrect")        integerCalculator.inputOperator("+")        XCTAssertEqual(integerCalculator._currentNumberEnteredIn, "", "Incorrect")      XCTAssertEqual(integerCalculator._accumulatedResult, "2", "Incorrect")      XCTAssertEqual(integerCalculator._currentOperator, "+", "Incorrect")  }    func testCalculation3() throws {      let integerCalculator = IntegerCalculator()      integerCalculator.inputDigit("2")      integerCalculator.inputOperator("+")      integerCalculator.inputDigit("5")        XCTAssertEqual(integerCalculator._currentNumberEnteredIn, "5", "Incorrect")      XCTAssertEqual(integerCalculator._accumulatedResult, "2", "Incorrect")      XCTAssertEqual(integerCalculator._currentOperator, "+", "Incorrect")      XCTAssertTrue(integerCalculator.canPerformCalculation())  }    func testCalculation4() throws {      let integerCalculator = IntegerCalculator()      integerCalculator.inputDigit("2")      integerCalculator.inputOperator("+")      integerCalculator.inputDigit("5")      integerCalculator.inputEqualsSign()        XCTAssertEqual(integerCalculator._currentNumberEnteredIn, "5", "Incorrect")      XCTAssertEqual(integerCalculator._accumulatedResult, "7", "Incorrect")      XCTAssertEqual(integerCalculator._currentOperator, "+", "Incorrect")  }    func testCalculation5() throws {      let integerCalculator = IntegerCalculator()      integerCalculator.inputDigit("2")      integerCalculator.inputOperator("+")      integerCalculator.inputDigit("5")      integerCalculator.inputEqualsSign()      integerCalculator.inputEqualsSign()        XCTAssertEqual(integerCalculator._currentNumberEnteredIn, "5", "Incorrect")      XCTAssertEqual(integerCalculator._accumulatedResult, "12", "Incorrect")      XCTAssertEqual(integerCalculator._currentOperator, "+", "Incorrect")  }    func testCalculation6() throws {      let integerCalculator = IntegerCalculator()      integerCalculator.inputDigit("2")      integerCalculator.inputOperator("*")      integerCalculator.inputDigit("2")      integerCalculator.inputEqualsSign()      integerCalculator.inputEqualsSign()      integerCalculator.inputEqualsSign()        XCTAssertEqual(integerCalculator._currentNumberEnteredIn, "2", "Incorrect")      XCTAssertEqual(integerCalculator._accumulatedResult, "16", "Incorrect")      XCTAssertEqual(integerCalculator._currentOperator, "*", "Incorrect")  }    func testCalculation7() throws {      let integerCalculator = IntegerCalculator()      integerCalculator.inputDigit("2")      integerCalculator.inputOperator("+")      integerCalculator.inputDigit("7")      integerCalculator.inputOperator("*")      integerCalculator.inputDigit("2")      integerCalculator.inputOperator("+")      integerCalculator.inputDigit("5")      integerCalculator.inputEqualsSign()        XCTAssertEqual(integerCalculator._currentNumberEnteredIn, "5", "Incorrect")      XCTAssertEqual(integerCalculator._accumulatedResult, "23", "Incorrect")      XCTAssertEqual(integerCalculator._currentOperator, "+", "Incorrect")        //Need setting for pemdas complient and non pemdas compliment.    }    func testCalculation8() throws {      let integerCalculator = IntegerCalculator()      integerCalculator.inputDigit("2")      integerCalculator.inputOperator("+")      integerCalculator.inputDigit("7")      integerCalculator.inputOperator("*")      integerCalculator.inputDigit("2")      integerCalculator.inputOperator("+")      integerCalculator.inputDigit("5")      integerCalculator.inputEqualsSign()      integerCalculator.inputEqualsSign()        XCTAssertEqual(integerCalculator._currentNumberEnteredIn, "5", "Incorrect")      XCTAssertEqual(integerCalculator._accumulatedResult, "28", "Incorrect")      XCTAssertEqual(integerCalculator._currentOperator, "+", "Incorrect")        //Need setting for pemdas complient and non pemdas compliment.    }    func testCalculation9() throws {      let integerCalculator = IntegerCalculator()      integerCalculator.inputDigit("2")      integerCalculator.inputOperator("+")      integerCalculator.inputDigit("7")      integerCalculator.inputOperator("*")      integerCalculator.inputDigit("2")      integerCalculator.inputOperator("+")      integerCalculator.inputDigit("5")      integerCalculator.inputEqualsSign()      integerCalculator.inputOperator("+")      integerCalculator.inputDigit("9")      integerCalculator.inputEqualsSign()        XCTAssertEqual(integerCalculator._currentNumberEnteredIn, "9", "Incorrect")      XCTAssertEqual(integerCalculator._accumulatedResult, "32", "Incorrect") //XCTAssertEqual failed: ("37") is not equal to ("32")       XCTAssertEqual(integerCalculator._currentOperator, "+", "Incorrect")            }      }  
https://stackoverflow.com/questions/65839427/how-to-write-an-algorithm-that-mimics-a-calculator-using-immediate-execution January 22, 2021 at 12:44PM

没有评论:

发表评论