I'm working on a calculator app in SwiftUI, and I'm trying to add some additional buttons to incorporate advanced mathematical functions. I've already implemented the basic calculator functionality, but I'm facing issues with making these new buttons work as expected.
The additional buttons I'm trying to implement are:
Trigonometric Functions: sin, cos, tan, arcsin, arccos, arctan
Exponential and Logarithmic Functions: e^x, ln, log
Power and Root Functions: x^2, x^3, √x, ³√x, x^y
Hyperbolic Functions: sinh, cosh, tanh, arcsinh, arccosh, arctanh Other Functions: abs, factorial, percent
Could someone please guide me on how to properly integrate these buttons into the calculator functionality? Any insights or suggestions would be greatly appreciated.
Here's the code I have so far, which includes the basic calculator functionality and the additional buttons I'm trying to incorporate:
struct ContentView: View {
@State private var input: String = ""
@State private var result: String = ""
var body: some View {
VStack {
Text(result)
.font(.largeTitle)
.padding()
HStack {
CalculatorButton(title: "sin", action: { appendToInput("sin(") })
CalculatorButton(title: "cos", action: { appendToInput("cos(") })
CalculatorButton(title: "tan", action: { appendToInput("tan(") })
CalculatorButton(title: "arcsin", action: { appendToInput("asin(") })
}
HStack {
CalculatorButton(title: "arccos", action: { appendToInput("acos(") })
CalculatorButton(title: "arctan", action: { appendToInput("atan(") })
CalculatorButton(title: "e^x", action: { appendToInput("exp(") })
CalculatorButton(title: "ln", action: { appendToInput("log(") })
}
HStack {
CalculatorButton(title: "log", action: { appendToInput("log10(") })
CalculatorButton(title: "x^2", action: { appendToInput("pow(") })
CalculatorButton(title: "x^3", action: { appendToInput("pow(") })
CalculatorButton(title: "√x", action: { appendToInput("sqrt(") })
}
HStack {
CalculatorButton(title: "³√x", action: { appendToInput("pow(") })
CalculatorButton(title: "x^y", action: { appendToInput("^") })
CalculatorButton(title: "sinh", action: { appendToInput("sinh(") })
CalculatorButton(title: "cosh", action: { appendToInput("cosh(") })
}
HStack {
CalculatorButton(title: "tanh", action: { appendToInput("tanh(") })
CalculatorButton(title: "arcsinh", action: { appendToInput("asinh(") })
CalculatorButton(title: "arccosh", action: { appendToInput("acosh(") })
CalculatorButton(title: "arctanh", action: { appendToInput("atanh(") })
}
HStack {
CalculatorButton(title: "π", action: { appendToInput("pi") })
CalculatorButton(title: "e", action: { appendToInput("exp(1)") })
CalculatorButton(title: "abs", action: { appendToInput("abs(") })
CalculatorButton(title: "factorial", action: { appendToInput("factorial(") })
}
HStack {
CalculatorButton(title: "%", action: { appendToInput("%") })
CalculatorButton(title: "+", action: { appendToInput("+") })
CalculatorButton(title: "-", action: { appendToInput("-") })
CalculatorButton(title: "*", action: { appendToInput("*") })
}
HStack {
CalculatorButton(title: "/", action: { appendToInput("/") })
CalculatorButton(title: ".", action: { appendToInput(".") })
CalculatorButton(title: "Clear", action: { clearInput() })
CalculatorButton(title: "=", action: { evaluateExpression() })
}
}
.padding()
}
private func appendToInput(_ value: String) {
input.append(value)
}
private func clearInput() {
input = ""
result = ""
}
private func evaluateExpression() {
let expression = NSExpression(format: input)
if let evaluatedValue = expression.expressionValue(with: nil, context: nil) as? NSNumber {
result = evaluatedValue.stringValue
} else {
result = "Invalid expression"
}
}
}
struct CalculatorButton: View {
let title: String
let action: () -> Void
var body: some View {
Button(action: action) {
Text(title)
.font(.title)
.frame(width: 80, height: 80)
.foregroundColor(.white)
.background(Color.blue)
.cornerRadius(40)
}
}
}
There is no way to enter digits ?
You have to change the evaluation, which depends on what you evaluate: constant, function, …
I have modified a few lines (marked with ###) to make pi, x^2 and x^3 work.
Use it as a template for other modifications.
struct ContentView: View {
@State private var input: String = ""
@State private var result: String = ""
var body: some View {
VStack {
Text(result)
.font(.largeTitle)
.padding()
HStack {
CalculatorButton(title: "sin", action: { appendToInput("sin(") })
CalculatorButton(title: "cos", action: { appendToInput("cos(") })
CalculatorButton(title: "tan", action: { appendToInput("tan(") })
CalculatorButton(title: "arcsin", action: { appendToInput("asin(") })
}
HStack {
CalculatorButton(title: "arccos", action: { appendToInput("acos(") })
CalculatorButton(title: "arctan", action: { appendToInput("atan(") })
CalculatorButton(title: "e^x", action: { appendToInput("exp(") })
CalculatorButton(title: "ln", action: { appendToInput("log(") })
}
HStack {
CalculatorButton(title: "log", action: { appendToInput("log10(") })
CalculatorButton(title: "x^2", action: { appendToInput("pow2") }) // ####
CalculatorButton(title: "x^3", action: { appendToInput("pow3") }) // ####
CalculatorButton(title: "√x", action: { appendToInput("sqrt(") })
}
HStack {
CalculatorButton(title: "³√x", action: { appendToInput("pow(") })
CalculatorButton(title: "x^y", action: { appendToInput("^") })
CalculatorButton(title: "sinh", action: { appendToInput("sinh(") })
CalculatorButton(title: "cosh", action: { appendToInput("cosh(") })
}
HStack {
CalculatorButton(title: "tanh", action: { appendToInput("tanh(") })
CalculatorButton(title: "arcsinh", action: { appendToInput("asinh(") })
CalculatorButton(title: "arccosh", action: { appendToInput("acosh(") })
CalculatorButton(title: "arctanh", action: { appendToInput("atanh(") })
}
HStack {
CalculatorButton(title: "π", action: { appendToInput("pi") })
CalculatorButton(title: "e", action: { appendToInput("exp(1)") })
CalculatorButton(title: "abs", action: { appendToInput("abs(") })
CalculatorButton(title: "factorial", action: { appendToInput("factorial(") })
}
HStack {
CalculatorButton(title: "%", action: { appendToInput("%") })
CalculatorButton(title: "+", action: { appendToInput("+") })
CalculatorButton(title: "-", action: { appendToInput("-") })
CalculatorButton(title: "*", action: { appendToInput("*") })
}
HStack {
CalculatorButton(title: "/", action: { appendToInput("/") })
CalculatorButton(title: ".", action: { appendToInput(".") })
CalculatorButton(title: "Clear", action: { clearInput() })
CalculatorButton(title: "=", action: { evaluateExpression() })
}
}
.padding()
}
private func appendToInput(_ value: String) {
input = value // #### input.append(value) // But we keep result
}
private func clearInput() {
input = ""
result = ""
}
private func evaluateExpression() { // ###
print(input) // ### To understand what's going on
switch input {
case "pi":
let myDouble = Double.pi
let myFormulaDouble = "myDouble"
let doubleElements = ["myDouble": myDouble]
let expression = NSExpression(format: myFormulaDouble)
if let evaluatedValue = expression.expressionValue(with: doubleElements, context: nil) as? NSNumber {
result = evaluatedValue.stringValue
} else {
result = "Invalid expression"
}
case "pow2", "pow3":
// data to elevate to power is result
guard let val = Double(result) else { return }
let myDouble = pow(val, input == "pow2" ? 2 : 3) // val * val
let myFormulaDouble = "myDouble"
let doubleElements = ["myDouble": myDouble]
let expression = NSExpression(format: myFormulaDouble)
if let evaluatedValue = expression.expressionValue(with: doubleElements, context: nil) as? NSNumber {
result = evaluatedValue.stringValue
} else {
result = "Invalid expression"
}
default:
print("default", input, result) // ### To understand what's going on
let expression = NSExpression(format: input)
if let evaluatedValue = expression.expressionValue(with: nil, context: nil) as? NSNumber {
result = evaluatedValue.stringValue
} else {
result = "Invalid expression"
}
}
}
}
struct CalculatorButton: View {
let title: String
let action: () -> Void
var body: some View {
Button(action: action) {
Text(title)
.font(.title)
.frame(width: 80, height: 80)
.foregroundColor(.white)
.background(Color.blue)
.cornerRadius(40)
}
}
}