【发布时间】:2016-06-27 01:39:13
【问题描述】:
我有一个非常长的十进制数(比如17.9384693864596069567),我想将小数截断到几个小数位(所以我希望输出为17.9384)。我确实不想将数字四舍五入为17.9385。
我该怎么做?
【问题讨论】:
-
以下任一解决方案均完全有效。
-
当然,只是给你看另一个 :)
我有一个非常长的十进制数(比如17.9384693864596069567),我想将小数截断到几个小数位(所以我希望输出为17.9384)。我确实不想将数字四舍五入为17.9385。
我该怎么做?
【问题讨论】:
我想出了这个。
用一些花哨的技巧将数字取整(向下取整)。
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
因此,乘以 1,0 的数量是您想要的小数位数,将其取底,然后除以您乘以的数。瞧。
【讨论】:
您可以通过将其扩展为Double 来进一步整理:
extension Double {
func truncate(places : Int)-> Double {
return Double(floor(pow(10.0, Double(places)) * self)/pow(10.0, Double(places)))
}
}
你可以这样使用它:
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) 你会得到0.23000000000000001
小数点后具体数字的代码为:
let number = 17.9384693864596069567;
let merichle = Float(String(format: "%.1f", (number * 10000)).dropLast(2))!/10000
//merichle = 17.9384
最终,您的号码会被截断而不用四舍五入...
【讨论】:
Double(String(format: "%.2f", b))
将此代码复制到您的应用程序中...
import Foundation
func truncateDigitsAfterDecimal(number: Double, afterDecimalDigits: Int) -> Double {
if afterDecimalDigits < 1 || afterDecimalDigits > 512 {return 0.0}
return Double(String(format: "%.\(afterDecimalDigits)f", number))!
}
然后你可以像这样调用这个函数:
truncateDigitsAfterDecimal(number: 45.123456789, afterDecimalDigits: 3)
将产生以下内容:
45.123
【讨论】:
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
【讨论】:
Swift 用户界面: 如果您在视图中截断以格式化输出,而不是计算,则 SwiftUI 包含一种使用 C 格式说明符作为 Text() 签名的一部分的便捷方法。
import SwiftUI
let myDouble = 17.93846938645960695
Text("\(myDouble, specifier: "%.2f")")
///Device display: 17.94
以上代码会将Double的内容直接输出到View,正确舍入到百位,但保留Double的值以供进一步计算。
如果您作为 SwiftUI 用户不熟悉 C 语言格式说明符,此链接包含有用信息:https://en.wikipedia.org/wiki/Printf_format_string
【讨论】:
你可以保持简单:
String(format: "%.0f", ratio*100)
其中 0 是您希望允许的小数位数。在这种情况下为零。比率是双倍的:0.5556633。 希望能帮助到你。
【讨论】:
在 swift 5 中,也可以通过创建小数的扩展来完成对小数的截断
extension Decimal {
func truncation(by digit: Int) -> Decimal {
var initialDecimal = self
var roundedDecimal = Decimal()
NSDecimalRound(&roundedDecimal, &initialDecimal, digit, .plain)
return roundedDecimal
}
十进制值的用例
value = Decimal(2.56430).truncation(by:2)
值 = 2.560000(截断后)
【讨论】:
.plain 导致 NSDecimalRound 向上或向下舍入。将其替换为 .down 以始终向下舍入,这将使其具有截断的行为。
Swift 5.2 的答案
我查看了很多答案,但在截断时总是遇到转换问题。根据我的数学知识,通过截断,我知道如果我有 3.1239 并且我想要 3 位小数,那么我将有 3.123 没有四舍五入 (!= 3.1234)。
也许,由于过程的性质,我在 Doubles 上总是很成功,但在 Floats 上总是遇到问题。
我的方法是创建 BinaryFloatingPoint 的扩展,这样我就可以将它重用于 Float、CGFLoat、Double ...
以下扩展获取一个 BinaryFloatingPoint 并可以返回带有 numberOfDecimals 的 String 或 BinaryFloatingPoint 值,并处理不同类型的情况:
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: ".")
}
}
}
}
}
它可能看起来很老套,但我所有的测试都通过了:
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 协议并将其限制为BinaryFloatingPoint 是没有意义的
Double(stringValue) as! Self ???顺便说一句,如果不是Double,你有什么保证它是Float。试试Float80(123.456789).with(numberOfDecimals: 2) // 繁荣
Self 限制为 LosslessStringConvertible。请注意,它不会覆盖CGFloat,因为它不符合它。
方式一:如果你不想为此创建任何新的函数,你可以这样做,直接获取四舍五入的值。
var roundedValue = (decimalValue * pow(10.0, Double(numberOfPlaces))).rounded())/pow(10.0, Double(numberOfPlaces)
例子:
var numberOfPlaces = 2
var decimalValue = 13312.2423423523523
print("\(((decimalValue * pow(10.0, Double(numberOfPlaces))).rounded())/pow(10.0, Double(numberOfPlaces)))")
结果:13312.24
方式2:如果你只是想打印,你可以使用:
print(String(format: "%.\(numberOfPlaces)f",decimalValue))
例子
var numberOfPlaces = 4
var decimalValue = 13312.2423423523523
print(String(format: "%.\(numberOfPlaces)f",decimalValue))
【讨论】: