Skip to content

Commit a3c2ffd

Browse files
committed
Calculator: use NSDecimalNumber
Migrate more operations to `NSDecimalNumber` which simplifies the math handling. It also simplifies the localization of the values.
1 parent 92488c2 commit a3c2ffd

File tree

1 file changed

+25
-31
lines changed

1 file changed

+25
-31
lines changed

Examples/Calculator/Calculator.swift

Lines changed: 25 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -26,28 +26,23 @@ case division
2626
}
2727

2828
private struct CalculatorState {
29-
var lhs: String = ""
30-
var rhs: String = ""
31-
var operand: WritableKeyPath<Self, String> = \.lhs
29+
var lhs: NSDecimalNumber = .zero
30+
var rhs: NSDecimalNumber = .zero
31+
var operand: WritableKeyPath<Self, NSDecimalNumber> = \.lhs
3232
var operation: CalculatorOperation = .undefined {
3333
willSet { self.operand = (newValue == .undefined) ? \.lhs : \.rhs }
3434
}
3535

36-
mutating func evaluate() -> String {
37-
var f: ((Double, Double) -> Double)?
38-
36+
mutating func evaluate() -> NSDecimalNumber {
3937
switch self.operation {
4038
case .undefined: break
41-
case .addition: f = { $0 + $1 }
42-
case .substraction: f = { $0 - $1 }
43-
case .multiplication: f = { $0 * $1 }
44-
case .division: f = { $0 / $1 }
39+
case .addition: lhs = lhs.adding(rhs)
40+
case .substraction: lhs = lhs.subtracting(rhs)
41+
case .multiplication: lhs = lhs.multiplying(by: rhs)
42+
case .division: lhs = lhs.dividing(by: rhs)
4543
}
4644

47-
if let f = f {
48-
lhs = String(f(Double(lhs)!, Double(rhs)!))
49-
}
50-
rhs = ""
45+
rhs = .zero
5146
operation = .undefined
5247

5348
return lhs
@@ -101,6 +96,10 @@ private class Calculator {
10196
self.window.rootViewController?.title = "Calculator"
10297

10398
self.window.addSubview(self.txtResult)
99+
self.txtResult.font = Font(name: "Consolas", size: Font.systemFontSize)
100+
self.txtResult.textAlignment = .right
101+
self.txtResult.text =
102+
self.state.evaluate().description(withLocale: Locale.current)
104103

105104
self.window.addSubviews(self.btnDigits)
106105
self.btnDigits.forEach {
@@ -124,25 +123,21 @@ private class Calculator {
124123
fatalError("invalid target: \(self) for sender: \(sender)")
125124
}
126125

127-
self.state[keyPath: self.state.operand] += String(input)
126+
var operand = self.state[keyPath: self.state.operand] as Decimal
127+
operand *= 10
128+
operand += Decimal(input)
128129

129-
self.txtResult.text =
130-
(NSDecimalNumber(string: self.state[keyPath: self.state.operand])
131-
as Decimal).description
130+
self.txtResult.text = operand.description
132131
}
133132

134133
private func onOperationPress(_ sender: Button, _: Control.Event) {
135134
switch self.btnOperations.firstIndex(of: sender)! {
136135
case 0: /* AC */
137136
self.state = CalculatorState()
138-
self.txtResult.text = "0"
137+
self.txtResult.text = Decimal.zero.description
139138
case 1: /* +/- */
140-
var value: Decimal =
141-
NSDecimalNumber(string: self.state[keyPath: self.state.operand])
142-
as Decimal
143-
value.negate()
144-
self.state[keyPath: self.state.operand] = value.description
145-
self.txtResult.text = value.description
139+
var operand = self.state[keyPath: self.state.operand] as Decimal
140+
operand.negate()
146141
case 3: /* ÷ */
147142
self.state.operation = .division
148143
case 4: /* x */
@@ -152,22 +147,21 @@ private class Calculator {
152147
case 6: /* + */
153148
self.state.operation = .addition
154149
case 2: /* % */
155-
if Double(self.state.lhs) == 0.0 { break }
150+
if (self.state.lhs as Decimal).isZero { break }
156151
self.state.operation = .division
157-
self.state.rhs = "100"
152+
self.state.rhs = NSDecimalNumber(string: "100")
158153
fallthrough
159154
case 7: /* = */
160155
self.txtResult.text =
161-
(NSDecimalNumber(string: self.state.evaluate()) as Decimal)
162-
.description
156+
self.state.evaluate().description(withLocale: Locale.current)
163157
default:
164158
fatalError("unknown operation \(self.btnOperations.firstIndex(of: sender)!)")
165159
}
166160
}
167161

168162
private func onDecimalPress(_ sender: Button, _: Control.Event) {
169-
self.state[keyPath: self.state.operand] += "."
170-
self.txtResult.text = self.state[keyPath: self.state.operand]
163+
self.txtResult.text =
164+
(self.state[keyPath: self.state.operand] as Decimal).description
171165
}
172166
}
173167

0 commit comments

Comments
 (0)