Округление двойного значения до x числа десятичных знаков в swift
может ли кто-нибудь сказать мне, как округлить двойное значение до x числа десятичных знаков в Swift?
Я:
var totalWorkTimeInHours = (totalWorkTime/60/60)
С totalWorkTime
будучи NSTimeInterval (double) в секунду.
totalWorkTimeInHours
даст мне часы, но это дает мне количество времени в таком длинном точном числе, например, 1.543240952039......
как мне округлить это до, скажем, 1.543, когда я печатаю totalWorkTimeInHours
?
21 ответов
вы можете использовать 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
.
EDIT:
Что касается комментариев, которые иногда не работают, пожалуйста, прочитайте это:
что Каждый Компьютерщик Должен Знать Арифметику С Плавающей Запятой
расширение для Swift 2
более общим решением является следующее расширение, которое работает с 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
В 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
}
}
Пример, который возвращает двойное округление до 4 знаков после запятой:
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
использовать String
конструктор, который принимает format
строку:
print(String(format: "%.3f", totalWorkTimeInHours))
С Swift 4, в соответствии с вашими потребностями, вы можете выбрать один из 9 следующие стили для того, чтобы иметь округленный результат от Double
.
#1. Используя FloatingPoint
rounded()
метод
в простейшем случае, вы можете использовать Double
round()
метод.
let roundedValue1 = (0.6844 * 1000).rounded() / 1000
let roundedValue2 = (0.6849 * 1000).rounded() / 1000
print(roundedValue1) // returns 0.684
print(roundedValue2) // returns 0.685
#2. Используя FloatingPoint
rounded(_:)
метод
var roundedValue1 = (0.6844 * 1000).rounded(.toNearestOrEven) / 1000
var roundedValue2 = (0.6849 * 1000).rounded(.toNearestOrEven) / 1000
print(roundedValue1) // returns 0.684
print(roundedValue2) // returns 0.685
#3. Использование Дарвина round
функция
предлагает round
функция через Дарвина.
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
#4. С помощью 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
#5. Используя 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
#6. Используя 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
#7. Используя NSString
init(format:arguments:)
инициализатор
если вы хотите вернуть NSString
от вашей операции округления, используя 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
#8. Используя String
init(format:_:)
инициализатор
Swift String
тип соединен с NSString
класса (вы можете узнать больше об этом, читая Язык Программирования Swift). Поэтому вы можете использовать следующий код, чтобы вернуть String
от вашей операции округления:
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
#9. Используя 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")
основываясь на ответе йога, вот функция Swift, которая выполняет эту работу:
func roundToPlaces(value:Double, places:Int) -> Double {
let divisor = pow(10.0, Double(places))
return round(value * divisor) / divisor
}
это полностью отработанный код
Swift 3.0 / 4.0, Xcode 9.0 GM / 9.2
let doubleValue : Double = 123.32565254455
self.lblValue.text = String(format:"%.f", doubleValue)
print(self.lblValue.text)
выход - 123
self.lblValue_1.text = String(format:"%.1f", doubleValue)
print(self.lblValue_1.text)
выход - 123.3
self.lblValue_2.text = String(format:"%.2f", doubleValue)
print(self.lblValue_2.text)
выход - 123.33
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
код для определенных цифр после десятичных знаков:
var a = 1.543240952039
var roundedString = String(format: "%.3f", a)
сюда %.3f говорит swift сделать это число округленным до 3 десятичных знаков.и если вы хотите двойное число, вы можете использовать этот код:
// string в Double
var roundedString = Double(String(format: "%.3f", b))
удобный способ может быть использование расширение типа двойной
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
используйте встроенную библиотеку 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
это своего рода длинный обходной путь, который может пригодиться, если ваши потребности немного сложнее. Вы можете использовать форматер чисел в 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 упоминал печать (в этом случае строка не нежелательно), и потому что этот класс позволяет устанавливать несколько параметров.
Я хотел бы использовать
print(String(format: "%.3f", totalWorkTimeInHours))
и изменить .3f для любого количества десятичных чисел вам нужно
Не быстро, но я уверен, что вы поняли идею.
pow10np = pow(10,num_places);
val = round(val*pow10np) / pow10np;
Это более гибкий алгоритм округления до 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
округлить двойное значение до X числа decimal
НЕТ. цифр после запятой
var x = 1.5657676754
var y = (x*10000).rounded()/10000
print(y) // 1.5658
var x = 1.5657676754
var y = (x*100).rounded()/100
print(y) // 1.57
var x = 1.5657676754
var y = (x*10).rounded()/10
print(y) // 1.6
лучший способ отформатировать свойство double-использовать предопределенные методы Apple.
mutating func round(_ rule: FloatingPointRoundingRule)
FloatingPointRoundingRule-перечисление, которое имеет следующие возможности
Перечисление Случаях:
дело awayFromZero Округление до ближайшего допустимого значения, величина которого больше или равна величине источника.
дело Округление до ближайшего допустимого значения, которое меньше или равно к источнику.
дело toNearestOrAwayFromZero Округление до ближайшего допустимого значения; если два значения одинаково близки, выбирается значение с большей величиной.
дело toNearestOrEven Округление до ближайшего допустимого значения;если два значения одинаково близки, выбирается четное.
дело towardZero Округление до ближайшего допустимого значения, величина которого меньше или равна величине источник.
case up Округление до ближайшего допустимого значения, которое больше или равно источнику.
var aNumber : Double = 5.2
aNumber.rounded(.up) // 6.0
либо:
-
используя
String(format:)
:-
Typecast
Double
toString
С%.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 } }
-
если ты хочешь 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)
}
Я нашел это интересно, можно ли исправить ввод пользователя. То есть, если они вводят три десятичных знака вместо двух на сумму в доллар. Сказать 1.111 вместо 1.11 вы можете исправить это путем округления? Ответ по многим причинам-нет! С деньгами что-нибудь над т. е. 0.001 в конечном итоге вызовет проблемы в реальной чековой книжке.
вот функция для проверки ввода пользователями слишком много значений после периода. Но что позволит 1., 1.1 и 1.11.
Это предполагается, что значение уже проверено на успешное преобразование из строки в 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"