在Swift中将双精度值舍入到x位小数

545

有人可以告诉我在Swift中如何将double值舍入到x位小数吗?

我有:

var totalWorkTimeInHours = (totalWorkTime/60/60)

使用 totalWorkTime 表示时间长度,数据类型为 NSTimeInterval (double)(以秒为单位)。

totalWorkTimeInHours 给出的是小时数,但它会给出一个非常长的精确数字,例如 1.543240952039......

当我打印 totalWorkTimeInHours 时,如何将其四舍五入到 1.543 这样的值?


2
请查看我的答案,以找到使用Darwin round(_:)Double round()NSString初始化器、String初始化器、NumberFormatter、Double扩展甚至NSDecimalNumberDecimal舍入双精度的多达9种不同的方法。 - Imanou Petit
@Rounded,一个Swift 5.1属性包装器:https://gist.github.com/abhijithpp/1cc41b41a5d1c8f007da90f20bc0c65f - Abhijith
36个回答

7

Swift 5

使用字符串方法

var yourDouble = 3.12345
//to round this to 2 decimal spaces i could turn it into string
let roundingString = String(format: "%.2f", myDouble)
let roundedDouble = Double(roundingString) //and than back to double
// result is 3.12 

但更被接受的是使用扩展名

extension Double {
    func round(to decimalPlaces: Int) -> Double {
        let precisionNumber = pow(10,Double(decimalPlaces))
        var n = self // self is a current value of the Double that you will round
        n = n * precisionNumber
        n.round()
        n = n / precisionNumber
        return n
    }
}

然后,您可以使用:

yourDouble.round(to:2)

6
不是Swift,但我相信你能理解这个想法。
pow10np = pow(10,num_places);
val = round(val*pow10np) / pow10np;

5

这似乎在Swift 5中可以工作。

相当惊讶地,还没有一个标准的函数可以实现这个。

//将Double截断到小数点后n位并进行四舍五入

extension Double {

    func truncate(to places: Int) -> Double {
    return Double(Int((pow(10, Double(places)) * self).rounded())) / pow(10, Double(places))
    }

}

5
在iOS 15 / macOS 12中,引入了新的内联数字格式化程序。
如果没有任何舍入规则,它会像在学校教授的那样进行四舍五入。语法如下:
let value = 1.543240
let rounded = value.formatted(.number.precision(.fractionLength(2))))

向下舍入至1.54

let value = 1.545240
let rounded = value.formatted(.number.precision(.fractionLength(2))))

向上舍入至1.55,fractionLength 指定小数位数。

要强制向下舍入,请添加一个舍入规则。

let rounded = value.formatted(.number.rounded(rule: .down).precision(.fractionLength(2))))

4

这个解决方案对我有用。XCode 13.3.1和Swift 5

extension Double {
    
    func rounded(decimalPoint: Int) -> Double {
        let power = pow(10, Double(decimalPoint))
       return (self * power).rounded() / power
    }
}

测试:

print(-87.7183123123.rounded(decimalPoint: 3))
print(-87.7188123123.rounded(decimalPoint: 3))
print(-87.7128123123.rounded(decimalPoint: 3))

结果:

-87.718
-87.719
-87.713

4
var n = 123.111222333
n = Double(Int(n * 10.0)) / 10.0

结果:n = 123.1

将10.0(1位小数)更改为任意数量的数字,例如100.0(2位小数)、1000.0(3位小数)等等,以获得所需的小数位数。


4
为避免浮点数问题,请使用 Decimal。
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
    }
}

举例:
使用精度为2和向下取整时,Float会将1075.58四舍五入为1075.57
使用精度为2和向下取整时,Decimal会将1075.58四舍五入为1075.58


2
我发现这篇文章是关于是否能够更正用户输入的问题,例如当他们在输入美元金额时输入了三个小数位数而不是两个。比如输入1.111而不是1.11,你能通过四舍五入来修复它吗?由于许多原因,答案是否定的!对于货币来说,任何超过0.001的金额都可能在真实的支票簿中导致问题。
以下是一个用于检查用户输入小数点后位数是否过多的函数。但是该函数将允许输入1.、1.1和1.11等格式的输入。
假设该值已经被检查并成功地从字符串转换为双精度浮点数。
//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


}

2
你可以添加这个扩展:

最初的回答。
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

这是将其表示为字符串的整洁实现。我想知道是否可能或合理编写小数点后数字表示的扩展,同时仍将其保持为Double。 - thinkswift

2

如果你需要一个带有数字值的文本元素,那么这里是SwiftUI的一个解决方案。

struct RoundedDigitText : View {
    let digits : Int
    let number : Double

    var body : some View {
        Text(String(format: "%.\(digits)f", number))
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接