I have a really long decimal number (say 17.9384693864596069567
) and I want to truncate the decimal to a few decimal places (so I want the output to be 17.9384
). I do not want to round the number to 17.9385
.
How can I do this?
I have a really long decimal number (say 17.9384693864596069567
) and I want to truncate the decimal to a few decimal places (so I want the output to be 17.9384
). I do not want to round the number to 17.9385
.
How can I do this?
You can tidy this up even more by making it an extension of Double
:
extension Double {
func truncate(places : Int)-> Double {
return Double(floor(pow(10.0, Double(places)) * self)/pow(10.0, Double(places)))
}
}
You use it like this:
var num = 1.23456789
// return the number truncated to 2 places
print(num.truncate(places: 2))
// return the number truncated to 6 places
print(num.truncate(places: 6))
0.23456789.truncate(2)
you'll get 0.23000000000000001
–
Regeniaregensburg You can keep it simple with:
String(format: "%.0f", ratio*100)
Where 0 is the amount of decimals you want to allow. In this case zero. Ratio is a double like: 0.5556633. Hope it helps.
String(format: "%.2f", 0.123
to generate a string like so: "0.12"
–
Truant I figured this one out.
Just floor (round down) the number, with some fancy tricks.
let x = 1.23556789
let y = Double(floor(10000*x)/10000) // leaves on first four decimal places
let z = Double(floor(1000*x)/1000) // leaves on first three decimal places
print(y) // 1.2355
print(z) // 1.235
So, multiply by 1 and the number of 0s being the decimal places you want, floor that, and divide it by what you multiplied it by. And voila.
extension Double {
/// Rounds the double to decimal places value
func roundToPlaces(_ places:Int) -> Double {
let divisor = pow(10.0, Double(places))
return (self * divisor).rounded() / divisor
}
func cutOffDecimalsAfter(_ places:Int) -> Double {
let divisor = pow(10.0, Double(places))
return (self*divisor).rounded(.towardZero) / divisor
}
}
let a:Double = 1.228923598
print(a.roundToPlaces(2)) // 1.23
print(a.cutOffDecimalsAfter(2)) // 1.22
The code for specific digits after decimals is:
let number = 17.9384693864596069567;
let merichle = Float(String(format: "%.1f", (number * 10000)).dropLast(2))!/10000
//merichle = 17.9384
And ultimately, your number gets truncate without round...
Double(String(format: "%.2f", b))
–
Marileemarilin let number = 1.99999999
and your code will return merichle = 2
. –
Alkahest In swift 5 truncation to decimal can also be done by creating extension to decimal
extension Decimal {
func truncation(by digit: Int) -> Decimal {
var initialDecimal = self
var roundedDecimal = Decimal()
NSDecimalRound(&roundedDecimal, &initialDecimal, digit, .plain)
return roundedDecimal
}
use case for decimal value
value = Decimal(2.56430).truncation(by:2)
value = 2.560000 (after truncation)
.plain
causes NSDecimalRound to round up or down. Replace it with .down
to always round down, which will give it the behavior of truncating. –
Brinkema Copy this code into your application...
import Foundation
func truncateDigitsAfterDecimal(number: Double, afterDecimalDigits: Int) -> Double {
if afterDecimalDigits < 1 || afterDecimalDigits > 512 {return 0.0}
return Double(String(format: "%.\(afterDecimalDigits)f", number))!
}
Then you can call this function like:
truncateDigitsAfterDecimal(number: 45.123456789, afterDecimalDigits: 3)
Will produce the following:
45.123
SwiftUI: If you are truncating to format output in a view, but not computation, SwiftUI contains a convenient way to use C format specifiers as part of the signature for Text().
import SwiftUI
let myDouble = 17.93846938645960695
Text("\(myDouble, specifier: "%.2f")")
///Device display: 17.94
Above code will output the contents of Double directly to the View, rounded correctly to the hundredth place, but preserve the value of the Double for further calculations.
If as a user of SwiftUI you are unfamiliar with the C language format specifiers, this link contains helpful information: https://en.wikipedia.org/wiki/Printf_format_string
Way 1: If you don't want to create any new function for this, you can do it this way for getting the rounded value directly.
var roundedValue = (decimalValue * pow(10.0, Double(numberOfPlaces))).rounded())/pow(10.0, Double(numberOfPlaces)
Example:
var numberOfPlaces = 2
var decimalValue = 13312.2423423523523
print("\(((decimalValue * pow(10.0, Double(numberOfPlaces))).rounded())/pow(10.0, Double(numberOfPlaces)))")
Result: 13312.24
Way 2: if you just want to print, you may use:
print(String(format: "%.\(numberOfPlaces)f",decimalValue))
Example
var numberOfPlaces = 4
var decimalValue = 13312.2423423523523
print(String(format: "%.\(numberOfPlaces)f",decimalValue))
Answer for Swift 5.2
I have looked a lot of answers and I always had conversion issues when truncating. According to my maths knowledge, by truncating I understand that if I have 3.1239 and I want 3 decimals then I will have 3.123 with no rounding (!= 3.1234).
Maybe, because of the nature of the process, I was always successful with Doubles but always had issues with Floats.
My approach is to create an extension of BinaryFloatingPoint so I can reuse it for Float, CGFLoat, Double ...
The following extension gets a BinaryFloatingPoint and can return the String or the BinaryFloatingPoint values with a numberOfDecimals given and it handles different type of cases:
extension Numeric where Self: BinaryFloatingPoint {
/// Retruns the string value of the BinaryFloatingPoint. The initiaiser
var toString: String {
return String(describing: self)
}
/// Returns the number of decimals. It will be always greater than 0
var numberOfDecimals: Int {
return toString.count - String(Int(self)).count - 1
}
/// Returns a Number with a certain number of decimals
/// - Parameters:
/// - Parameter numberOfDecimals: Number of decimals to return
/// - Returns: BinaryFloatingPoint with number of decimals especified
func with(numberOfDecimals: Int) -> Self {
let stringValue = string(numberOfDecimals: numberOfDecimals)
if self is Double {
return Double(stringValue) as! Self
} else {
return Float(stringValue) as! Self
}
}
/// Returns a string representation with a number of decimals
/// - Parameters:
/// - Parameter numberOfDecimals: Number of decimals to return
/// - Returns: String with number of decimals especified
func string(numberOfDecimals: Int) -> String {
let selfString = toString
let selfStringComponents = selfString.components(separatedBy: ".")
let selfStringIntegerPart = selfStringComponents[0]
let selfStringDecimalPart = selfStringComponents[1]
if numberOfDecimals == 0 {
return selfStringIntegerPart
} else {
if selfStringDecimalPart.count == numberOfDecimals {
return [selfStringIntegerPart,
selfStringDecimalPart].joined(separator: ".")
} else {
if selfStringDecimalPart.count > numberOfDecimals {
return [selfStringIntegerPart,
String(selfStringDecimalPart.prefix(numberOfDecimals))].joined(separator: ".")
} else {
let difference = numberOfDecimals - selfStringDecimalPart.count
let addedCharacters = [Character].init(repeating: "0", count: difference)
return [selfStringIntegerPart,
selfStringDecimalPart+addedCharacters].joined(separator: ".")
}
}
}
}
}
It might look old school but all my tests are passing:
func test_GivenADecimalNumber_ThenAssertNumberOfDecimalsWanted() {
//No decimals
XCTAssertEqual(Float(3).with(numberOfDecimals: 0), 3)
XCTAssertEqual(Float(3.09).with(numberOfDecimals: 0), 3)
XCTAssertEqual(Float(3.999).with(numberOfDecimals: 0), 3)
XCTAssertEqual(Double(3).with(numberOfDecimals: 0), 3)
XCTAssertEqual(Double(3.09).with(numberOfDecimals: 0), 3)
XCTAssertEqual(Double(3.999).with(numberOfDecimals: 0), 3)
//numberOfDecimals == totalNumberOfDecimals
XCTAssertEqual(Float(3.00).with(numberOfDecimals: 2), 3.00)
XCTAssertEqual(Float(3.09).with(numberOfDecimals: 2), 3.09)
XCTAssertEqual(Float(3.01).with(numberOfDecimals: 2), 3.01)
XCTAssertEqual(Float(3.999).with(numberOfDecimals: 3), 3.999)
XCTAssertEqual(Float(3.991).with(numberOfDecimals: 3), 3.991)
XCTAssertEqual(Double(3.00).with(numberOfDecimals: 2), 3.00)
XCTAssertEqual(Double(3.09).with(numberOfDecimals: 2), 3.09)
XCTAssertEqual(Double(3.01).with(numberOfDecimals: 2), 3.01)
XCTAssertEqual(Double(3.999).with(numberOfDecimals: 3), 3.999)
XCTAssertEqual(Double(3.991).with(numberOfDecimals: 3), 3.991)
//numberOfDecimals < totalNumberOfDecimals
XCTAssertEqual(Float(3.00).with(numberOfDecimals: 1), 3.0)
XCTAssertEqual(Float(3.09).with(numberOfDecimals: 1), 3.0)
XCTAssertEqual(Float(3.01).with(numberOfDecimals: 1), 3.0)
XCTAssertEqual(Float(3.999).with(numberOfDecimals: 2), 3.99)
XCTAssertEqual(Float(3.991).with(numberOfDecimals: 2), 3.99)
XCTAssertEqual(Double(3.00).with(numberOfDecimals: 1), 3.0)
XCTAssertEqual(Double(3.09).with(numberOfDecimals: 1), 3.0)
XCTAssertEqual(Double(3.01).with(numberOfDecimals: 1), 3.0)
XCTAssertEqual(Double(3.999).with(numberOfDecimals: 2), 3.99)
XCTAssertEqual(Double(3.991).with(numberOfDecimals: 2), 3.99)
//numberOfDecimals > totalNumberOfDecimals
XCTAssertEqual(Float(3.00).with(numberOfDecimals: 3), 3.000)
XCTAssertEqual(Float(3.09).with(numberOfDecimals: 3), 3.090)
XCTAssertEqual(Float(3.01).with(numberOfDecimals: 3), 3.010)
XCTAssertEqual(Float(3.999).with(numberOfDecimals: 4), 3.9990)
XCTAssertEqual(Float(3.991).with(numberOfDecimals: 4), 3.9910)
XCTAssertEqual(Double(3.00).with(numberOfDecimals: 3), 3.000)
XCTAssertEqual(Double(3.09).with(numberOfDecimals: 3), 3.090)
XCTAssertEqual(Double(3.01).with(numberOfDecimals: 3), 3.010)
XCTAssertEqual(Double(3.999).with(numberOfDecimals: 4), 3.9990)
XCTAssertEqual(Double(3.991).with(numberOfDecimals: 4), 3.9910)
}
func test_GivenADecimal_ThenAssertStringValueWithDecimalsWanted() {
//No decimals
XCTAssertEqual(Float(3).string(numberOfDecimals: 0), "3")
XCTAssertEqual(Float(3.09).string(numberOfDecimals: 0), "3")
XCTAssertEqual(Float(3.999).string(numberOfDecimals: 0), "3")
XCTAssertEqual(Double(3).string(numberOfDecimals: 0), "3")
XCTAssertEqual(Double(3.09).string(numberOfDecimals: 0), "3")
XCTAssertEqual(Double(3.999).string(numberOfDecimals: 0), "3")
//numberOfDecimals == totalNumberOfDecimals
XCTAssertEqual(Float(3.00).string(numberOfDecimals: 2), "3.00")
XCTAssertEqual(Float(3.09).string(numberOfDecimals: 2), "3.09")
XCTAssertEqual(Float(3.01).string(numberOfDecimals: 2), "3.01")
XCTAssertEqual(Float(3.999).string(numberOfDecimals: 3), "3.999")
XCTAssertEqual(Float(3.991).string(numberOfDecimals: 3), "3.991")
XCTAssertEqual(Double(3.00).string(numberOfDecimals: 2), "3.00")
XCTAssertEqual(Double(3.09).string(numberOfDecimals: 2), "3.09")
XCTAssertEqual(Double(3.01).string(numberOfDecimals: 2), "3.01")
XCTAssertEqual(Double(3.999).string(numberOfDecimals: 3), "3.999")
XCTAssertEqual(Double(3.991).string(numberOfDecimals: 3), "3.991")
//numberOfDecimals < totalNumberOfDecimals
XCTAssertEqual(Float(3.00).string(numberOfDecimals: 1), "3.0")
XCTAssertEqual(Float(3.09).string(numberOfDecimals: 1), "3.0")
XCTAssertEqual(Float(3.01).string(numberOfDecimals: 1), "3.0")
XCTAssertEqual(Float(3.999).string(numberOfDecimals: 2), "3.99")
XCTAssertEqual(Float(3.991).string(numberOfDecimals: 2), "3.99")
XCTAssertEqual(Double(3.00).string(numberOfDecimals: 1), "3.0")
XCTAssertEqual(Double(3.09).string(numberOfDecimals: 1), "3.0")
XCTAssertEqual(Double(3.01).string(numberOfDecimals: 1), "3.0")
XCTAssertEqual(Double(3.999).string(numberOfDecimals: 2), "3.99")
XCTAssertEqual(Double(3.991).string(numberOfDecimals: 2), "3.99")
//numberOfDecimals > totalNumberOfDecimals
XCTAssertEqual(Float(3.00).string(numberOfDecimals: 3), "3.000")
XCTAssertEqual(Float(3.09).string(numberOfDecimals: 3), "3.090")
XCTAssertEqual(Float(3.01).string(numberOfDecimals: 3), "3.010")
XCTAssertEqual(Float(3.999).string(numberOfDecimals: 4), "3.9990")
XCTAssertEqual(Float(3.991).string(numberOfDecimals: 4), "3.9910")
XCTAssertEqual(Double(3.00).string(numberOfDecimals: 3), "3.000")
XCTAssertEqual(Double(3.09).string(numberOfDecimals: 3), "3.090")
XCTAssertEqual(Double(3.01).string(numberOfDecimals: 3), "3.010")
XCTAssertEqual(Double(3.999).string(numberOfDecimals: 4), "3.9990")
XCTAssertEqual(Double(3.991).string(numberOfDecimals: 4), "3.9910")
}
Numeric
protocol and constraining it to BinaryFloatingPoint
is pointless –
Umbra Double(stringValue) as! Self
??? Btw if it is not Double
what guarantee do you have that it is a Float
. Try Float80(123.456789).with(numberOfDecimals: 2)
// BOOM –
Umbra Self
to LosslessStringConvertible
. Note that it will not cover CGFloat
because it does NOT conform to it. –
Umbra Self?
–
Umbra © 2022 - 2024 — McMap. All rights reserved.