How to limit decimal places to only four in iOS application [duplicate] - ios

This question already has an answer here:
Limit formatted Measurement to 2 digits
(1 answer)
Closed 4 years ago.
I'm making a temperature slider but the output keeps on displaying 15 or so digits after the decimal place. How do I resolve this and have it display only 4 numbers after the decimal place?
import UIKit
class TemperatureViewController : UIViewController {
#IBOutlet weak var fahrenheitLabel: UILabel!
#IBOutlet weak var celsiusLabel: UILabel!
#IBOutlet weak var kelvinLabel: UILabel!
#IBOutlet weak var temperatureSlider: temperatureSlider!
var temperature:Measurement<UnitTemperature> {
let fahrenheitValue = Measurement<UnitTemperature>(value: Double(temperatureSlider.value), unit: UnitTemperature.celsius)
return fahrenheitValue
}
#IBAction func sliderChange(_ sender: Any) {
updateTemperatureDisplay()
}
func updateTemperatureDisplay() {
celsiusLabel.text = temperature.description
fahrenheitLabel.text = temperature.converted(to: .fahrenheit).description
kelvinLabel.text = temperature.converted(to: .kelvin).description
}
override func viewDidLoad() {
updateTemperatureDisplay()
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}

In most cases, you should make use of the available formatters. The measurements API provides a MeasurementFormatter which is a good place to start
let celsius = Measurement<UnitTemperature>(value: 10.91235, unit: UnitTemperature.celsius)
let fahrenheit = celsius.converted(to: .fahrenheit)
let mf = MeasurementFormatter()
mf.unitOptions = .providedUnit
mf.string(from: celsius)
mf.string(from: fahrenheit)
So the above example basically outputs
10.91235 °C // original
51.64222999999585 °F // converted
10.912°C
51.642°F
If you need more control, you can supply your own NumberFormatter to MeasurementFormatter
let numberFormatter = NumberFormatter()
numberFormatter.maximumFractionDigits = 4
numberFormatter.minimumFractionDigits = 2
let mf = MeasurementFormatter()
mf.numberFormatter = numberFormatter
mf.unitOptions = .providedUnit

You could extend Double (and use it throughout your app if this is an operation you need done elsewhere):
extension Double {
func truncate(places: Int) -> Double {
return Double(floor(pow(10.0, Double(places)) * self)/pow(10.0, Double(places)))
}
}
let rawValue = 51.64222999999585
let formattedValue = rawValue.truncate(places: 4)
print(formattedValue) // 51.6422

Related

How can I combine all 3 gyroscope axis to produce 1 int? Xcode Swift Core Motion

I've followed a few things including Apple's documentation on the core motion. This is probably very simple to do, I just can't put my finger on it. Basically, I'm trying to get all of the X, Y, and Z data, combine it and make it constantly add to the "scoreValue" text. Basically, a constant counter that counts the total degrees rotated ever.
import UIKit
import CoreMotion
class ViewController: UIViewController {
#IBOutlet var scoreValue: UITextView!
#IBOutlet weak var Label: UILabel!
var motion = CMMotionManager()
override func viewDidLoad() {
super.viewDidLoad()
myGyroscope()
view.backgroundColor = .systemBlue
}
func myGyroscope() {
motion.gyroUpdateInterval = 0.1
motion.startGyroUpdates(to: OperationQueue.current!) { [self]
(data, error) in
print(data as Any)
if let trueData = data {
self.view.reloadInputViews()
let x = trueData.rotationRate.x
let y = trueData.rotationRate.y
let z = trueData.rotationRate.z
self.UNDEFINED.text = "\(Double(x).rounded(toPlaces :0))"
self.UNDEFINED.text = "\(Double(y).rounded(toPlaces :0))"
self.UNDEFINED.text = "\(Double(z).rounded(toPlaces :0))"
}
}
return
}
}
extension Double {
/// Rounds the double to decimal places value
func rounded(toPlaces places:Int) -> Double {
let divisor = pow(10.0, Double(places))
return (self * divisor).rounded() / divisor
}
}

New to coding and working an example in the book which was written for xcode 6.2 and I have the newest version.

I get the following error when I run the app and try and click any key on the keypad that opens on launch.
Here is the error I get in the attached photo
Below is my code and it highlights the first func at the bottom called func formatAsCurrancy... as the problem area. I have converted all the old code in the book as it prompted me to. Not sure what to do at this point. Thank you for any help.
import UIKit
class ViewController: UIViewController {
//properties for programmatically interacting with UI components
#IBOutlet weak var billAmountLabel: UILabel!
#IBOutlet weak var customTipPercentLabel1: UILabel!
#IBOutlet weak var customTipPercentageSlider: UISlider!
#IBOutlet weak var customTipPercentLabel2: UILabel!
#IBOutlet weak var tip15Label: UILabel!
#IBOutlet weak var total15Label: UILabel!
#IBOutlet weak var tipCustomLabel: UILabel!
#IBOutlet weak var totalCustomLabel: UILabel!
#IBOutlet weak var inputTextField: UITextField!
// NSDecimalNumber constants used in the calculateTip method
let decimal100 = NSDecimalNumber(string: "100.0")
let decimal15Percent = NSDecimalNumber(string: "0.15")
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// select inputTextField so keypad displays when the view loads
inputTextField.becomeFirstResponder()
}
#IBAction func calculateTip(_ sender: Any) {
let inputString = inputTextField.text //get user input
// convert slider value to an NSDecimalNumber
let sliderValue =
NSDecimalNumber(integerLiteral: Int(customTipPercentageSlider.value))
// divide sliderValue by decimal100 (100.0) to get tip %
let customPercent = sliderValue / decimal100
// did customTipPercentageSlider generate the event?
if sender is UISlider {
// thumb moved so update the Labels with new custom percent
customTipPercentLabel1.text =
NumberFormatter.localizedString(from: customPercent,
number: NumberFormatter.Style.percent)
customTipPercentLabel2.text = customTipPercentLabel1.text
}
// if there is a bill amount, calculate tips and totals
if !(inputString?.isEmpty)! {
// convert to NSDecimalNumber and insert decimal point
let billAmount =
NSDecimalNumber(string: inputString) / decimal100
// did inputTextField generate the event?
if sender is UITextField {
billAmountLabel.text = " " + formatAsCurrency(number: billAmount)
// calculate and display the 15% tip and total
let fifteenTip = billAmount * decimal15Percent
tip15Label.text = formatAsCurrency(number: fifteenTip)
total15Label.text =
formatAsCurrency(number: billAmount + fifteenTip)
}
// calculate custom tip and display custom tip and total
let customTip = billAmount * customPercent
tipCustomLabel.text = formatAsCurrency(number: customTip)
totalCustomLabel.text =
formatAsCurrency(number: billAmount + customTip)
}
else {// clear all Labels
billAmountLabel.text = ""
tip15Label.text = ""
total15Label.text = ""
tipCustomLabel.text = ""
totalCustomLabel.text = ""
}
}
}
// convert a numeric value to localized currency string
func formatAsCurrency(number: NSNumber) -> String {
return NumberFormatter.localizedString(
from: number, number: NumberFormatter.Style.currency)
}
// overloaded + operator to add NSDecimalNumbers
func +(left: NSDecimalNumber, right: NSDecimalNumber) -> NSDecimalNumber {
return left.adding(right)
}
// overloaded * operator to multiply NSDecimalNumbers
func *(left: NSDecimalNumber, right: NSDecimalNumber) -> NSDecimalNumber {
return left.multiplying(by: right)
}
// overloaded / operator to divide NSDecimalNumbers
func /(left: NSDecimalNumber, right: NSDecimalNumber) -> NSDecimalNumber {
return left.dividing(by: right)
}
The simulator is trying to find a numeric keyboard on your computer, but your computer shouldn't have one so that's why it's giving you the error.
If you go to the simulator and then Hardware -> Keyboard -> Uncheck use hardware keyboard, the issue will go away.

Textfield as input in average function

I recently wanted to code an Average-Calculator.
My plan was to build a UITextField in which you can type Numbers separated by commas... By pressing the 'Calculate' button the App should calculate the Average of the Numbers above and give them out by setting a labeltext to the average.
So I wrote my average function and received this error message:
Can not convert value of type 'UITextField' to expected element type 'Double'.
This is my Code:
#IBOutlet var Input: UITextField!
#IBOutlet var Output: UILabel!
#IBAction func Calculate(sender: AnyObject) {
var grades:[Double] = [Input]
func average(nums: [Double]) -> Double {
var total = 0.0
for grade in nums{
total += Double(grade)
}
let gradesTotal = Double(nums.count)
let average = total/gradesTotal
return average
}
let Average = average(grades)
Output.text = "Average: \(Average)"
}
Can you help me with my idea?
Is there a better way to get an input?
You need to separate numbers to get that array if you do that:
you can pass "doubles" array to your average function
code to copypaste :)
var str = "1,2,3,4,5,6"
let stringsWithNumbers = str.componentsSeparatedByString(",")
let doubles = stringsWithNumbers.map { Double($0)! }
Please use lower camel case for variables...
In this line:
var grades:[Double] = [Input]
Input is an instance of UITextField, so you are trying to assign a single-element Array<UITextField> to Array<Double>. You see you cannot do such sort of things.
If you want to accept a text which contains Numbers separated by commas, you need to explicitly convert the text to [Double].
To simplify, let's just ignore the nil or non-numeric values.
Then you need to change your code as:
#IBOutlet var input: UITextField!
#IBOutlet var output: UILabel!
#IBAction func calculate(sender: AnyObject) {
var grades: [Double] = (input.text ?? "").componentsSeparatedByString(",").flatMap{Double($0)}
func average(nums: [Double]) -> Double {
var total = 0.0
for grade in nums{
total += Double(grade)
}
let gradesTotal = Double(nums.count)
let average = total/gradesTotal
return average
}
let averageValue = average(grades)
output.text = "Average: \(averageValue)"
}
The basic idea of this line:
var grades: [Double] = (input.text ?? "").componentsSeparatedByString(",").flatMap{Double($0)}
is well-described in Lu_'s answer. Mine is just a little safer version.
(Addition)
Some explanation about safety:
UITextFields property text is of type String?, so you should think it can be nil. Giving a default value for nil with ?? operator.
And using Double($0)! may crash your app, as Double($0) will return nil for non-numeric strings.
Writing these reminded me one more crash case.
When gradesTotal == 0, the code above will crash with division by zero.
(The default value does not work well for "safety" in the code above...)
So, one more step ahead to safety:
#IBAction func calculate(sender: AnyObject) {
var grades: [Double] = (input.text ?? "").componentsSeparatedByString(",").flatMap{
Double($0.stringByTrimmingCharactersInSet(.whitespaceCharacterSet()))
}
func average(nums: [Double]) -> Double? {
var total = 0.0
for grade in nums{
total += Double(grade)
}
let gradesTotal = Double(nums.count)
if gradesTotal > 0 {
let average = total/gradesTotal
return average
} else {
return nil
}
}
if let averageValue = average(grades) {
output.text = "Average: \(averageValue)"
} else {
output.text = "Average not available"
}
}
What you have to do is using Double(Input.text) instead of [Input]. Right now, you were trying to convert a UITextField to a double, which causes the error.
let textInput = txtInputView.text;
let components = textInput.componentsSeparatedByString(",");
let sum = 0.0;
for txt in components
{
sum = sum + Double(txt);
}
let avg = sum / components.count;
print(avg)
Here is the complete code if someone is interested :)
#IBOutlet var input: UITextField!
#IBOutlet var output: UILabel!
#IBAction func calculate(sender: AnyObject) {
var grades: [Double] = (input.text ?? "").componentsSeparatedByString(",").flatMap{
Double($0.stringByTrimmingCharactersInSet(.whitespaceCharacterSet()))
}
func average(nums: [Double]) -> Double? {
var total = 0.0
for grade in nums{
total += Double(grade)
}
let gradesTotal = Double(nums.count)
if gradesTotal > 0 {
let average = total/gradesTotal
return average
} else {
return nil
}
}
if let averageValue = average(grades) {
output.text = "Average: \(averageValue)"
} else {
output.text = "Average not available"
}
}
#IBAction func userTappedCalculate(sender: AnyObject) { view.endEditing(true)
}
I added the line #IBAction func userTappedCalculate(sender: AnyObject) { view.endEditing(true)
} to close the input TextField when you tap calculate...

Show digits after calculation?

I created a small calculator for getting drip rates. Ive managed to get all the fields to multiply to each other, but it won't multiple digits making some calculations short. Im fairly new to coding and have been trying multiple different options. Can someone help me on this? Here is my code:
import UIKit
class DripCViewController: UIViewController {
//outlets/////////////////////////////////////////////////////////////////////////
#IBOutlet var result: UILabel!
#IBOutlet var volume: UITextField!
#IBOutlet var drip: UITextField!
#IBOutlet var time: UITextField!
#IBAction func solve(sender: UIButton) {
//////////////////////////////////////////////////////////////////////////////////
//math functions/////////////////////////////////////////////////////////////////
if let number1 = Int(volume.text!) {
if let number2 = Int(drip.text!) {
if let number3 = Int(time.text!) {
let firstnumber = number1/number3
let secondnumber = firstnumber*number2
result.text = "\(secondnumber) gtts/min"
}
}
}
//////////////////////////////////////////////////////////////////////////////////
//keyboard override feature///////////////////////////////////////////////////////
func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
volume .resignFirstResponder();
drip .resignFirstResponder() ;
time .resignFirstResponder();
}
}
}
You need to use Float or Double instead of Int.
Fixed code:
if let number1 = Double(volume.text!) {
if let number2 = Double(drip.text!) {
if let number3 = Double(time.text!) {
let firstnumber = number1/number3
let secondnumber = firstnumber*number2
result.text = "\(secondnumber) gtts/min"
}
}
}
You are casting the user input to integers. Those are whole numbers without additional precision (eg so only 1, 2 3 etc and not 1.5 and 2.3) You can use a number type that support numbers with more precision like a double.

Creating Random Number

I am new to the programming world and am trying my hand at a simple math app. Basically i want to app to create two random numbers and then add them together. I then put the answer in a text field where the app checks to see if the answer is right or wrong. I have created this and it works however I cannot get the numbers to regenerate after the answer is correct. Any direction you can give on this I would be much appreciative.
Here is the code.
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.guess(self)
}
#IBOutlet weak var addend1: UILabel!
#IBOutlet weak var addend2: UILabel!
#IBOutlet weak var answer: UITextField!
#IBOutlet weak var response: UILabel!
//create numbers
let newaddend1 = arc4random() % 11
let newaddend2 = arc4random() % 11
#IBAction func guess(sender: AnyObject) {
//Convert Random Numbers to String to be displayed in labels
var firstNumber = String(newaddend1)
var secondNumber = String(newaddend2)
//convert the answer in the text field to an integer
var integer = answer?.text.toInt()
//Convert Strings to Ints so they can be added
var newFirstNumber = firstNumber.toInt()
var newSecondNumber = secondNumber.toInt()
//Add Numbers
var correctAnswer = (newFirstNumber! + newSecondNumber!)
//Display the numbers
addend1.text = firstNumber
addend2.text = secondNumber
//Print correct number to log for test
println(correctAnswer)
println(integer)
//check your answer agains the correct answer
if (integer != nil) {
if (integer == correctAnswer) {
response.text = "Correct! The Answer is \(correctAnswer)!"
} else {
response.text = "Wrongo Bongo the correct answer is \(correctAnswer)!"
}
} else {
response.text = "Please put in a number for your guess"
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//remove keyboard
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
self.view.endEditing(true)
}
func textFieldShouldReturn(textField: UITextField!) -> Bool {
answer.resignFirstResponder()
return true
}
}
You can initialize the variables outside of the IBAction to get class level variable declaration. Then immediately calculate new random numbers once the correct answer is generated:
let newaddend1 = 0
let newaddend2 = 0
#IBAction func guess(sender: AnyObject) {
//Convert Random Numbers to String to be displayed in labels
var firstNumber = String(newaddend1)
var secondNumber = String(newaddend2)
//convert the answer in the text field to an integer
var integer = answer?.text.toInt()
//Convert Strings to Ints so they can be added
var newFirstNumber = firstNumber.toInt()
var newSecondNumber = secondNumber.toInt()
//Add Numbers
var correctAnswer = (newFirstNumber! + newSecondNumber!)
//Display the numbers
addend1.text = firstNumber
addend2.text = secondNumber
//Print correct number to log for test
println(correctAnswer)
println(integer)
//check your answer agains the correct answer
if (integer != nil) {
if (integer == correctAnswer) {
response.text = "Correct! The Answer is \(correctAnswer)!"
let newaddend1 = arc4random() % 11
let newaddend2 = arc4random() % 11
} else {
response.text = "Wrongo Bongo the correct answer is \(correctAnswer)!"
}
} else {
response.text = "Please put in a number for your guess"
}
}

Resources