2019年7月15日月曜日

電卓のチャタリング対策、演算子修正操作、2バイト演算子を組み込む

電卓の場合、チャタリング対策で、**とかの操作で2重に演算がはじまらないようにすること、*のあとに/に修正するなどの演算子の操作謝りの修正、*=、ー=のような自分自身に対する演算操作を組み込む必要があります。

これが結構大変でした。

まず、演算子の2度押しかどうかは、演算子を押した結果を保存して、その後演算子が続いたときの処理を実装する、という基本的な識別を実装しました。

            if checkChattering {
                if previousOperater == String(char) {
                    return
                }
                else{
                    // =+ , -+ , +=
                    if char == "=" { // += -= /= *=
                        if previousOperater.count == 1 {
                            previousOperater = String(previousOperater) + String(char)
                        }
                        print("Operater1 " + previousOperater)
                        if let result = calQueue.push(previousOperater){
                            if let numberString = formattedNumberStringForPop(result){
                                print (numberString)
                            }
                        }
                        return
                    }
                    else {
                        calQueue.changeOperater(String(char))
                        previousOperater = String(char)
                        print("Operater2 " + String(char))
                        return
                    }
                }
            }

こんな感じです。

実装としては、checkChatterngという前が演算子だった場合の識別のほかに、前の演算子がなんであったのかを記憶しておく必要があり、previousOperaterというのを設けています。charはcurrentOperaterとかいう名前にすればよかったですね。

最初の処理は、同じ演算子が2度押しの場合は差し戻し処理です。

次に+=、*=などの自身への演算処理で2度押しかつ=であれば走ります。
前の演算子が、+=などではない場合は、+=などを演算子とします。
で、この演算子を計算キュー に送り込み、計算結果を得ることになります。

次に、+/などの修正処理ですが、計算キュー の演算子そのものをすり替える関数をもけてすり替え処理をおこなっている、というところになります。

そのほかに、数値のプラスマイナスを入れ替える処理と、クリア処理を加えました。

            else if char == "p" {
                    let q = queue.value()
                    if q.prefix(1) == "-" {
                        queue.setValue(String(q.suffix(q.count - 1)))
                        if let numberString = formattedNumberStringForPop(queue.value()){
                            print (numberString)
                        }
                    }
                    else if q.prefix(1) != "0" {
                        queue.setValue("-" + q)
                        if let numberString = formattedNumberStringForPop(queue.value()){
                            print (numberString)
                        }
                    }
                    return
            }
            else if char == "c"{
                self.initialize()
                print("Clear")
                print(queue.value())
            }

プラスマイナスの入れ替えは、はじめの1文字が”ー”ならば、マイナスを取る、初めの1文字が”0”でない場合は、”ー”をつけるという感じです。

次にクリアで苦労しました。キュー には数字のキュー と計算キュー の2つがあるのですが、計算キュー のクリア関数を実装しておらず、計算結果でキュー が残ったまま計算していました。なぜかわからず全体をたどるハメになりました・・

ちなみに、+=、ー=などの計算ですが、こんな感じになります。

        if noEqualOperaterSet.contains(operaterQueue!) {
            switch operaterQueue {
            case "+":
                let retVal = Decimal(string: operand1!)! + Decimal(string: operand2!)!
                return NSDecimalNumber(decimal: retVal).stringValue
            case "-":
                let retVal = Decimal(string: operand1!)! - Decimal(string: operand2!)!
                return NSDecimalNumber(decimal: retVal).stringValue
            case "/":
                let retVal = Decimal(string: operand1!)! / Decimal(string: operand2!)!
                return NSDecimalNumber(decimal: retVal).stringValue
            case "*":
                let retVal = Decimal(string: operand1!)! * Decimal(string: operand2!)!
                return NSDecimalNumber(decimal: retVal).stringValue
            case "+=":
                let retVal = Decimal(string: operand2!)! + Decimal(string: operand1!)!
                return NSDecimalNumber(decimal: retVal).stringValue
            case "-=":
                let retVal = Decimal(string: operand2!)! - Decimal(string: operand1!)!
                return NSDecimalNumber(decimal: retVal).stringValue
            case "/=":
                let retVal = Decimal(string: operand2!)! / Decimal(string: operand1!)!
                return NSDecimalNumber(decimal: retVal).stringValue
            case "*=":
                let retVal = Decimal(string: operand2!)! + Decimal(string: operand1!)!
                return NSDecimalNumber(decimal: retVal).stringValue
            default: return nil
            }
        }

ここでは、当初+=はうまくいくのに、ー=が上手く計算できず、なにがなんだかわかりませんでししたが、トレースした結果、この処理の場合、オペランドを入れ替えないと上手く動かないことがわかりました。頭の中で+=しか想像せずにコーディングした結果ですね・・・

つづいてこの2バイト演算子の計算をさせるための処理がこちらです。

            default: // += -= /= *=
                if operand1 != nil {
                    if operand2 == nil{
                        operand2 = operand1
                        operaterQueue = inputData
//                        print ("oprand1 operand2 " + operand1! + " " + operand2!)
                        let returnVal = equalOperation()
                        let ret =  String2formattedNumberString (returnVal!)
                        operand2 = ret
//                        print ("oprand1 operand2 " + operand1! + " " + operand2!)
                        return ret
                    }
                    else {
                        operaterQueue = inputData
//                        print ("oprand1 operand2 " + operand1! + " " + operand2!)
                        let returnVal = equalOperation()
                        let ret =  String2formattedNumberString (returnVal!)
                        operand2 = ret
 //                       print ("oprand1 operand2 " + operand1! + " " + operand2!)
                        return ret
                    }
                }
                else {
                    print ("operand1 is nil")
                }

オペランド2がない場合、自分自身をオペランド2にして、結果をオペランド2に渡します。そうすると自分自身がオペランド1に残り続け、オペランド2に結果が残り、結果と自分自身とを処理しつづけるということになります。

修正の結果、いろいろと計算してみて問題なさそうなので、計算エンジンはほぼできあがったという感じです。

以下は試験データです。上手く動いてるっぽいですw

0
1
12
123
1,234
12,345
123,451
123,451.
123,451.2
123,451.23
123,451.234
123,451.2345
123,451.234
123,451.23
123,451.2
123,451
12,345
1,234
123
12
1
0
1
1.
1.2
1.23
1.234
-1.234
-1.2340
Operater3 *
Operater2 /
Operater2 -
0.
0.1
0.10
Clear
0
1
10
Operater3 +
Operater2 -
Operater1 -=
0
Operater1 -=
-10
Operater1 -=
-20
Operater1 -=
-30

あとはユーザインタフェースをSwift UIでつくるか、ストーリーボードで作りつづけるか、というところが課題ですが微妙なところです。

 当面はユーザインタフェースは先送りにして、小数点以下の四捨五入だとか、小数点何桁で処理するだとか、消費税、%処理とかのエンジンの機能を優先していきたいと思います。

0 件のコメント: