谁能告诉我在Swift中如何将双精度值四舍五入到小数点后位数x?
我有:
var totalWorkTimeInHours = (totalWorkTime/60/60)
以totalWorkTime
秒为单位的NSTimeInterval(double)。
totalWorkTimeInHours
会给我时间,但是会给我这么长的时间,例如1.543240952039 ...
打印时如何将其四舍五入为1.543 totalWorkTimeInHours
?
谁能告诉我在Swift中如何将双精度值四舍五入到小数点后位数x?
我有:
var totalWorkTimeInHours = (totalWorkTime/60/60)
以totalWorkTime
秒为单位的NSTimeInterval(double)。
totalWorkTimeInHours
会给我时间,但是会给我这么长的时间,例如1.543240952039 ...
打印时如何将其四舍五入为1.543 totalWorkTimeInHours
?
Answers:
您可以使用Swift的 round
功能来完成此操作。
要Double
以3位数精度四舍五入,首先将其乘以1000,四舍五入,然后将四舍五入的结果除以1000:
let x = 1.23556789
let y = Double(round(1000*x)/1000)
print(y) // 1.236
除任何一种printf(...)
或String(format: ...)
解决方案外,此操作的结果仍为类型Double
。
编辑:
关于有时不起作用的评论,请阅读:
let rate = 9.94999999999; Double(round(rate * 100) / 100);
输出:9.94999999999, 9.949999999999999
仅适用于打印,但是如何将其分配给变量?
更通用的解决方案是以下扩展,可与Swift 2和iOS 9配合使用:
extension Double {
/// Rounds the double to decimal places value
func roundToPlaces(places:Int) -> Double {
let divisor = pow(10.0, Double(places))
return round(self * divisor) / divisor
}
}
在Swift 3中round
被替换为rounded
:
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
}
}
返回Double的示例四舍五入到小数点后四位:
let x = Double(0.123456789).roundToPlaces(4) // x becomes 0.1235 under Swift 2
let x = Double(0.123456789).rounded(toPlaces: 4) // Swift 3 version
round(8.46 * pow(10.0, 3.0)) / pow(10.0, 3.0)
返回8.460000000000001
。至少在这种情况下,对Float进行相同的操作实际上似乎确实有效:round(Float(8.46) * pow(10.0, 3.0)) / pow(10.0, 3.0)
yields 8.46
。只是一些值得注意的东西。
No '*' candidates produce the expected contextual result type 'FloatingPointRoundingRule'
打印时 如何将其四舍五入为1.543
totalWorkTimeInHours
?
要舍入totalWorkTimeInHours
到三位数以进行打印,请使用String
带有format
字符串的构造函数:
print(String(format: "%.3f", totalWorkTimeInHours))
String(format: "%.3f", 1.23489)
打印1.235
使用Swift 5时,您可以根据需要选择以下9种样式之一,以从中获得四舍五入的结果Double
。
FloatingPoint
rounded()
方法在最简单的情况下,您可以使用该Double
rounded()
方法。
let roundedValue1 = (0.6844 * 1000).rounded() / 1000
let roundedValue2 = (0.6849 * 1000).rounded() / 1000
print(roundedValue1) // returns 0.684
print(roundedValue2) // returns 0.685
FloatingPoint
rounded(_:)
方法let roundedValue1 = (0.6844 * 1000).rounded(.toNearestOrEven) / 1000
let roundedValue2 = (0.6849 * 1000).rounded(.toNearestOrEven) / 1000
print(roundedValue1) // returns 0.684
print(roundedValue2) // returns 0.685
round
功能Foundation round
通过Darwin 提供功能。
import Foundation
let roundedValue1 = round(0.6844 * 1000) / 1000
let roundedValue2 = round(0.6849 * 1000) / 1000
print(roundedValue1) // returns 0.684
print(roundedValue2) // returns 0.685
Double
Darwin round
和pow
函数构建的扩展自定义方法如果您想多次重复之前的操作,那么重构代码可能是一个好主意。
import Foundation
extension Double {
func roundToDecimal(_ fractionDigits: Int) -> Double {
let multiplier = pow(10, Double(fractionDigits))
return Darwin.round(self * multiplier) / multiplier
}
}
let roundedValue1 = 0.6844.roundToDecimal(3)
let roundedValue2 = 0.6849.roundToDecimal(3)
print(roundedValue1) // returns 0.684
print(roundedValue2) // returns 0.685
NSDecimalNumber
rounding(accordingToBehavior:)
方法如果需要,NSDecimalNumber
提供了一个详细但强大的解决方案,用于舍入十进制数字。
import Foundation
let scale: Int16 = 3
let behavior = NSDecimalNumberHandler(roundingMode: .plain, scale: scale, raiseOnExactness: false, raiseOnOverflow: false, raiseOnUnderflow: false, raiseOnDivideByZero: true)
let roundedValue1 = NSDecimalNumber(value: 0.6844).rounding(accordingToBehavior: behavior)
let roundedValue2 = NSDecimalNumber(value: 0.6849).rounding(accordingToBehavior: behavior)
print(roundedValue1) // returns 0.684
print(roundedValue2) // returns 0.685
NSDecimalRound(_:_:_:_:)
功能import Foundation
let scale = 3
var value1 = Decimal(0.6844)
var value2 = Decimal(0.6849)
var roundedValue1 = Decimal()
var roundedValue2 = Decimal()
NSDecimalRound(&roundedValue1, &value1, scale, NSDecimalNumber.RoundingMode.plain)
NSDecimalRound(&roundedValue2, &value2, scale, NSDecimalNumber.RoundingMode.plain)
print(roundedValue1) // returns 0.684
print(roundedValue2) // returns 0.685
NSString
init(format:arguments:)
初始化如果NSString
要从舍入操作返回a ,则使用NSString
初始化程序是一种简单但有效的解决方案。
import Foundation
let roundedValue1 = NSString(format: "%.3f", 0.6844)
let roundedValue2 = NSString(format: "%.3f", 0.6849)
print(roundedValue1) // prints 0.684
print(roundedValue2) // prints 0.685
String
init(format:_:)
初始化Swift的String
类型与Foundation的NSString
类联系在一起。因此,可以使用以下代码来String
从舍入操作返回a :
import Foundation
let roundedValue1 = String(format: "%.3f", 0.6844)
let roundedValue2 = String(format: "%.3f", 0.6849)
print(roundedValue1) // prints 0.684
print(roundedValue2) // prints 0.685
NumberFormatter
如果您希望String?
从四舍五入操作中获得收益,请NumberFormatter
提供高度可定制的解决方案。
import Foundation
let formatter = NumberFormatter()
formatter.numberStyle = NumberFormatter.Style.decimal
formatter.roundingMode = NumberFormatter.RoundingMode.halfUp
formatter.maximumFractionDigits = 3
let roundedValue1 = formatter.string(from: 0.6844)
let roundedValue2 = formatter.string(from: 0.6849)
print(String(describing: roundedValue1)) // prints Optional("0.684")
print(String(describing: roundedValue2)) // prints Optional("0.685")
Decimal
,这是免费电话桥接到NSDecimalNumber
。Decimal
是Swift的本机类型,并且为本机运算符+
(-
,等)提供了更优雅的支持
NSDecimalRound(_:_:_:_:)
功能更新了答案。谢谢。
NumberFormatter
是最后的选择,而它应该是向用户提供数字的第一个选择。没有其他方法可以生成正确的本地化数字。
这是一个完全有效的代码
Swift 3.0 / 4.0 / 5.0,Xcode 9.0 GM / 9.2及更高版本
let doubleValue : Double = 123.32565254455
self.lblValue.text = String(format:"%.f", doubleValue)
print(self.lblValue.text)
输出-123
let doubleValue : Double = 123.32565254455
self.lblValue_1.text = String(format:"%.1f", doubleValue)
print(self.lblValue_1.text)
输出-123.3
let doubleValue : Double = 123.32565254455
self.lblValue_2.text = String(format:"%.2f", doubleValue)
print(self.lblValue_2.text)
输出-123.33
let doubleValue : Double = 123.32565254455
self.lblValue_3.text = String(format:"%.3f", doubleValue)
print(self.lblValue_3.text)
输出-123.326
在Swift 3.0和Xcode 8.0中:
extension Double {
func roundTo(places: Int) -> Double {
let divisor = pow(10.0, Double(places))
return (self * divisor).rounded() / divisor
}
}
像这样使用此扩展名:
let doubleValue = 3.567
let roundedValue = doubleValue.roundTo(places: 2)
print(roundedValue) // prints 3.56
使用内置的Foundation Darwin库
SWIFT 3
extension Double {
func round(to places: Int) -> Double {
let divisor = pow(10.0, Double(places))
return Darwin.round(self * divisor) / divisor
}
}
用法:
let number:Double = 12.987654321
print(number.round(to: 3))
输出:12.988
一种方便的方法是使用Double类型的扩展名
extension Double {
var roundTo2f: Double {return Double(round(100 *self)/100) }
var roundTo3f: Double {return Double(round(1000*self)/1000) }
}
用法:
let regularPie: Double = 3.14159
var smallerPie: Double = regularPie.roundTo3f // results 3.142
var smallestPie: Double = regularPie.roundTo2f // results 3.14
如果要舍入Double
值,则可能要使用Swift,Decimal
这样就不会引入在尝试使用这些舍入值进行数学运算时会出现的任何错误。如果使用Decimal
,它可以准确表示该舍入浮点值的十进制值。
因此,您可以执行以下操作:
extension Double {
/// Convert `Double` to `Decimal`, rounding it to `scale` decimal places.
///
/// - Parameters:
/// - scale: How many decimal places to round to. Defaults to `0`.
/// - mode: The preferred rounding mode. Defaults to `.plain`.
/// - Returns: The rounded `Decimal` value.
func roundedDecimal(to scale: Int = 0, mode: NSDecimalNumber.RoundingMode = .plain) -> Decimal {
var decimalValue = Decimal(self)
var result = Decimal()
NSDecimalRound(&result, &decimalValue, scale, mode)
return result
}
}
然后,您可以Decimal
像这样获得舍入值:
let foo = 427.3000000002
let value = foo.roundedDecimal(to: 2) // results in 427.30
而且,如果要显示指定的小数位数(以及将字符串本地化为用户当前的语言环境),则可以使用NumberFormatter
:
let formatter = NumberFormatter()
formatter.maximumFractionDigits = 2
formatter.minimumFractionDigits = 2
if let string = formatter.string(for: value) {
print(string)
}
(4.81).roundedDecimal(to: 2, mode: .down)
将返回4.8而不是4.81,Decimal(string: self.description)!
用于精确decimalValue
Double
(变成4.8099999999999996
)。但是我建议您不要使用description
(因为它使用的舍入没有记录,并且可能会发生变化)。如果你真的想要做小数点精确的数学,你应该避免Double
完全,而是应该用Decimal
直接(如Decimal(sign: .plus, exponent: -2, significand: 481)
或Decimal(string: "4.81")
但不要用。description
。
description
方法的舍入行为既没有记录也没有保证。另外,它还没有本地化。恕我直言,将其description
用于日志记录以外的其他用途是错误的。我要么使用全文Decimal
,避免Double
完全使用,要么只是使用其他舍入模式。或者,如果需要,请使用自己的本地化方法,该方法使用Grisu风格的算法(但是,当您知道要舍入到小数点后几位时,这似乎是不必要的)。但我避免依赖于的这种辅助行为description
。
这是一个漫长的解决方法,如果您的需求稍微复杂一点,则可能会派上用场。您可以在Swift中使用数字格式器。
let numberFormatter: NSNumberFormatter = {
let nf = NSNumberFormatter()
nf.numberStyle = .DecimalStyle
nf.minimumFractionDigits = 0
nf.maximumFractionDigits = 1
return nf
}()
假设您要打印的变量是
var printVar = 3.567
这将确保以所需的格式返回它:
numberFormatter.StringFromNumber(printVar)
因此,这里的结果将为“ 3.6”(四舍五入)。尽管这不是最经济的解决方案,但我给出了它,因为OP提到了打印(在这种情况下String是不希望的),并且因为此类允许设置多个参数。
要么:
使用String(format:)
:
使用格式说明符输入Double
到String
,%.3f
然后返回Double
Double(String(format: "%.3f", 10.123546789))!
或扩展Double
以处理N小数位数:
extension Double {
func rounded(toDecimalPlaces n: Int) -> Double {
return Double(String(format: "%.\(n)f", self))!
}
}
通过计算
与10 ^ 3相乘,四舍五入,然后除以10 ^ 3 ...
(1000 * 10.123546789).rounded()/1000
或扩展Double
以处理N小数位数:
extension Double {
func rounded(toDecimalPlaces n: Int) -> Double {
let multiplier = pow(10, Double(n))
return (multiplier * self).rounded()/multiplier
}
}
这是一种更灵活的舍入到N个有效数字的算法
Swift 3解决方案
extension Double {
// Rounds the double to 'places' significant digits
func roundTo(places:Int) -> Double {
guard self != 0.0 else {
return 0
}
let divisor = pow(10.0, Double(places) - ceil(log10(fabs(self))))
return (self * divisor).rounded() / divisor
}
}
// Double(0.123456789).roundTo(places: 2) = 0.12
// Double(1.23456789).roundTo(places: 2) = 1.2
// Double(1234.56789).roundTo(places: 2) = 1200
格式化double属性的最佳方法是使用Apple预定义方法。
mutating func round(_ rule: FloatingPointRoundingRule)
FloatingPointRoundingRule是一个枚举,具有以下可能性
枚举案例:
case awayFromZero舍 入到最接近的允许值,其大小大于或等于源的大小。
向下 舍入到小于或等于源的最接近的允许值。
case toNearestOrAwayFromZero舍 入到最接近的允许值;如果两个值相等,则选择一个较大的值。
case toNearestOrEven舍 入到最接近的允许值;如果两个值相等接近,则选择偶数。
朝向“零”的情况将其舍入 到其大小小于或等于源的大小的最接近的允许值。
向上 舍入到大于或等于源的最接近的允许值。
var aNumber : Double = 5.2
aNumber.rounded(.up) // 6.0
这似乎在Swift 5中有效。
非常奇怪的是,目前还没有标准功能。
//从舍入到双精度小数到n个小数位
extension Double {
func truncate(to places: Int) -> Double {
return Double(Int((pow(10, Double(places)) * self).rounded())) / pow(10, Double(places))
}
}
您可以添加此扩展名:
extension Double {
var clean: String {
return self.truncatingRemainder(dividingBy: 1) == 0 ? String(format: "%.0f", self) : String(format: "%.2f", self)
}
}
并这样称呼它:
let ex: Double = 10.123546789
print(ex.clean) // 10.12
为了避免浮点缺陷,请使用十进制
extension Float {
func rounded(rule: NSDecimalNumber.RoundingMode, scale: Int) -> Float {
var result: Decimal = 0
var decimalSelf = NSNumber(value: self).decimalValue
NSDecimalRound(&result, &decimalSelf, scale, rule)
return (result as NSNumber).floatValue
}
}
例如
1075.58
使用小数位数为2和.down时四舍五入为1075.57如果使用小数位数为2和.down的1075.58四舍五入为1075.58
我想知道是否有可能纠正用户的输入。也就是说,如果他们输入三个小数而不是两个小数,则表示一个美元金额。说1.111而不是1.11可以四舍五入吗?出于多种原因,答案是否定的!用钱超过0.001即最终会在真正的支票簿中引起问题。
这是一个功能,用于检查用户输入的数字是否超过了句点。但这将允许1.,1.1和1.11。
假定已经检查过该值以成功从String转换为Double。
//func need to be where transactionAmount.text is in scope
func checkDoublesForOnlyTwoDecimalsOrLess()->Bool{
var theTransactionCharacterMinusThree: Character = "A"
var theTransactionCharacterMinusTwo: Character = "A"
var theTransactionCharacterMinusOne: Character = "A"
var result = false
var periodCharacter:Character = "."
var myCopyString = transactionAmount.text!
if myCopyString.containsString(".") {
if( myCopyString.characters.count >= 3){
theTransactionCharacterMinusThree = myCopyString[myCopyString.endIndex.advancedBy(-3)]
}
if( myCopyString.characters.count >= 2){
theTransactionCharacterMinusTwo = myCopyString[myCopyString.endIndex.advancedBy(-2)]
}
if( myCopyString.characters.count > 1){
theTransactionCharacterMinusOne = myCopyString[myCopyString.endIndex.advancedBy(-1)]
}
if theTransactionCharacterMinusThree == periodCharacter {
result = true
}
if theTransactionCharacterMinusTwo == periodCharacter {
result = true
}
if theTransactionCharacterMinusOne == periodCharacter {
result = true
}
}else {
//if there is no period and it is a valid double it is good
result = true
}
return result
}
//find the distance between two points
let coordinateSource = CLLocation(latitude: 30.7717625, longitude:76.5741449 )
let coordinateDestination = CLLocation(latitude: 29.9810859, longitude: 76.5663599)
let distanceInMeters = coordinateSource.distance(from: coordinateDestination)
let valueInKms = distanceInMeters/1000
let preciseValueUptoThreeDigit = Double(round(1000*valueInKms)/1000)
self.lblTotalDistance.text = "Distance is : \(preciseValueUptoThreeDigit) kms"
extension String{
var roundedValue:String {
return String(format: "%.3f", self)
}}
用法:
totalWorkTimeInHours.roundedValue
如果需要带数字值的Text元素,则这是SwiftUI的一个。
struct RoundedDigitText : View {
let digits : Int
let number : Double
var body : some View {
Text(String(format: "%.\(digits)f", number))
}
}
round(_:)
,Double
round()
,NSString
初始化,String
初始化,NumberFormatter
,双扩展名,甚至NSDecimalNumber
和Decimal
。