calculator: extend the calculator logic with scientific operators
authorAlexis Laferrière <alexis.laf@xymus.net>
Sun, 1 May 2016 19:11:14 +0000 (15:11 -0400)
committerAlexis Laferrière <alexis.laf@xymus.net>
Wed, 11 May 2016 18:13:52 +0000 (14:13 -0400)
Signed-off-by: Alexis Laferrière <alexis.laf@xymus.net>

examples/calculator/src/calculator_logic.nit

index 46f9ca3..775e8e3 100644 (file)
@@ -24,33 +24,35 @@ class CalculatorContext
        # Result of the last operation
        var result: nullable Numeric = null
 
-       # Last operation pushed with `push_op`, to be executed on the next push
+       # Last operation pushed with `push_op`
        var last_op: nullable Text = null
 
+       # Is `last_op` an unary operation or a '='?
+       var last_op_was_unary = false
+
        # Value currently being entered
        var current: nullable String = null
 
        # Text to display on screen
        fun display_text: String
        do
-               var result = result
-               var last_op = last_op
-               var current = current
-
                var buf = new FlatBuffer
 
-               if result != null and (current == null or last_op != "=") then
-                       if last_op == "=" then buf.append "= "
+               var last_op = last_op
+               var result = result
+               if result != null then
+                       if last_op_was_unary then buf.append "{last_op or else "?"} "
 
                        buf.append result.to_s
                        buf.add ' '
                end
 
-               if last_op != null and last_op != "=" then
+               if last_op != null and not last_op_was_unary then
                        buf.append last_op
                        buf.add ' '
                end
 
+               var current = current
                if current != null then
                        buf.append current.to_s
                        buf.add ' '
@@ -62,30 +64,74 @@ class CalculatorContext
        # Push operation `op`, will usually execute the last operation
        fun push_op(op: Text)
        do
+               # Constants
+               # TODO Protect constants to preserve full precision and to forbid appending extra digits
+               if op == "π" then
+                       if last_op_was_unary then clear
+                       current = pi.to_s
+                       return
+               else if op == "e" then
+                       if last_op_was_unary then clear
+                       current = 2.718282.to_s
+                       return
+
+               # Clear screen
+               else if op == "C" then
+                       clear
+                       return
+               end
+
+               # For all operators, apply pending operators
                apply_last_op_if_any
-               if op == "C" then
-                       self.result = null
-                       last_op = null
+
+               var result = self.result or else 0
+
+               last_op = op
+               last_op_was_unary = true
+
+               # Unary operators
+               if op == "√" then
+                       self.result = result.to_f.sqrt
+               else if op == "x²" then
+                       self.result = result.to_f.pow(2.0)
+               else if op == "x!" then
+                       self.result = result.to_i.factorial
+               else if op == "sin" then
+                       self.result = result.to_f.sin
+               else if op == "cos" then
+                       self.result = result.to_f.cos
+               else if op == "tan" then
+                       self.result = result.to_f.tan
+
+               # =
+               else if op == "=" then
+                       current = null
+
+               # Binary operators
                else
-                       last_op = op # store for next push_op
+                       self.result = result # Set as same or 0
+                       last_op_was_unary = false
+                       current = null
                end
+       end
 
-               # prepare next current
-               self.current = null
+       # Clear all state
+       private fun clear
+       do
+               result = null
+               last_op = null
+               current = null
        end
 
        # Push a digit
        fun push_digit(digit: Int)
        do
+               if last_op_was_unary then clear
+
                var current = current
                if current == null then current = ""
                current += digit.to_s
                self.current = current
-
-               if last_op == "=" then
-                       self.result = null
-                       last_op = null
-               end
        end
 
        # Switch entry mode from integer to decimal
@@ -118,6 +164,12 @@ class CalculatorContext
                                result = result.div(current.to_n)
                        else if op == "*" or op == "×" then
                                result = result.mul(current.to_n)
+                       else if op == "%" then
+                               result = result.to_i % current.to_i
+                       else if op == "xⁿ" then
+                               result = result.to_f.pow(current.to_f)
+                       else if op == "log" then
+                               result = result.to_f.log_base(current.to_f)
                        end
                end