Округление двойного значения до x количества знаков после запятой в быстром

302

Может ли кто-нибудь сказать мне, как округлить двойное значение до x числа десятичных знаков в Swift?

У меня есть:

var totalWorkTimeInHours = (totalWorkTime/60/60)

С totalWorkTime является NSTimeInterval (double) во втором.

totalWorkTimeInHours даст мне часы, но это дает мне количество времени в таком длинном точном числе, например. 1,543240952039......

Как мне обходить это до, скажем, 1.543, когда я печатаю totalWorkTimeInHours?

  • 0
    См. Мой ответ, чтобы найти до 9 различных способов округлить двойное число, используя round(_:) Дарвина round(_:) , Double round() , инициализатор NSString инициализатор String , NumberFormatter , расширение Double или даже NSDecimalNumber и Decimal .
Теги:
double
nstimeinterval

24 ответа

328
Лучший ответ

Вы можете использовать функцию 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:
Что касается комментариев, которые он иногда не работает, прочитайте следующее:

Что каждый компьютерный ученый должен знать о арифметике с плавающей точкой

  • 0
    По некоторым причинам это не помогает. Я использую это в следующем случае TransformOf <Double, String> (fromJSON: {Double (round (($ 0! As NSString) .doubleValue * 100) / 100)}, toJSON: { "($ 0)"})
  • 26
    У меня не работает на детской площадке: let rate = 9.94999999999; Double(round(rate * 100) / 100); Вывод: 9.94999999999, 9.949999999999999 только для печати, но как я могу присвоить его переменной?
Показать ещё 4 комментария
365

Расширение для 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
  • 0
    Добавил этот код в мой репо, спасибо! github.com/goktugyil/EZSwiftExtensions/blob/master/Sources/...
  • 14
    Природа двойного Swift, похоже, заключается в том, что он может быть неточным - из-за способа хранения / доступа к нему в двоичном формате, даже при использовании этой функции округления не будет возвращено число, округленное до 3 десятичных знаков: например, 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) дает 8.46 . Просто кое-что стоит отметить.
Показать ещё 7 комментариев
257

Как мне округлить это до, скажем, 1.543, когда я печатаю totalWorkTimeInHours?

Чтобы округлить totalWorkTimeInHours до 3 цифр для печати, используйте конструктор String который принимает строку format:

print(String(format: "%.3f", totalWorkTimeInHours))
  • 20
    Это усечение, а не округление
  • 20
    @Eyeball: На самом деле, это происходит. Это то же самое поведение, что и функциональность C printf, которая округляет до запрошенных цифр. So String(format: "%.3f", 1.23489) печатает 1.235
Показать ещё 10 комментариев
175

В Swift 4.2, в соответствии с вашими потребностями, вы можете выбрать один из 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 extension, созданного с помощью функций Дарвина 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. Использование rounding(accordingToBehavior:) NSDecimalNumber rounding(accordingToBehavior:) методу 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:_:) инициализатор

Тип Swifts String соединяется с классом Foundations NSString. Поэтому вы можете использовать следующий код для возврата 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, 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")
  • 1
    Отличный ответ. Я мог бы предложить на # 5, что вы могли бы рассмотреть возможность использования Decimal , который бесплатный для NSDecimalNumber . Decimal тип является собственным типом Swift и предлагает более элегантную поддержку для собственных операторов, таких как + , - и т. Д.
  • 0
    @Rob Я обновил свой ответ с помощью функции NSDecimalRound(_:_:_:_:) . Благодарю.
Показать ещё 4 комментария
85

В Swift 2.0 и Xcode 7.2:

let pi: Double = 3.14159265358979
String(format:"%.2f", pi)

Пример:

Изображение 1679

26

Основываясь на ответе Йоги, вот функция Swift, которая выполняет задание:

func roundToPlaces(value:Double, places:Int) -> Double {
    let divisor = pow(10.0, Double(places))
    return round(value * divisor) / divisor
}
18

Это полностью обработанный код

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

  • 0
    одна строка ?, похоже на 3 строки;)
  • 0
    Хахаха Это правильно @petter, ты можешь понять, что я хочу сказать ...
16

Код для определенных цифр после десятичных знаков:

var a = 1.543240952039
var roundedString = String(format: "%.3f", a)

Здесь%.3f сообщает, что это число округляется до трех знаков после запятой. Если вам нужен двойной номер, вы можете использовать этот код:

//String to Double

var roundedString = Double(String(format: "%.3f", b))

  • 0
    Вы только повторяете то, что уже сказал @ imanou-petit.
  • 2
    @ dr0i Я не прочитал все ответы ...
15

В 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
14

Swift 4, Xcode 10

yourLabel.text =  String(format:"%.2f", yourDecimalValue)
  • 1
    Понятия не имею, почему это рабочее решение было отклонено
  • 0
    Я не понизил голос, но я думаю, что причина может быть в том, что это возвращает строковое представление числа, а не числа. Это хорошо, если это все, что вам нужно, но вы можете захотеть, чтобы само число было округлено для дальнейшего использования. ОП сказал «когда я печатаю», поэтому я считаю, что это приемлемое, простое и чистое решение в этом случае.
Показать ещё 2 комментария
9

Использовать встроенную библиотеку 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

9

Удобным способом может быть использование расширения типа Двойной

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
7

Я бы использовал

print(String(format: "%.3f", totalWorkTimeInHours))

и измените .3f на любое количество десятичных чисел, которое вам нужно

  • 0
    Он хотел напечатать с 3 цифрами, чтобы не получить это в NSTimeInterval
  • 0
    он просто пытается дать логику !!!
7

Это своего рода длинный обходной путь, который может пригодиться, если ваши потребности немного сложнее. Вы можете использовать форматирование чисел в 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 упомянул печать (в этом случае строка не является нежелательной), и потому что этот класс позволяет установить несколько параметров.

  • 0
    Небольшое замечание, что любой форматтер довольно дорого обходится программно, что делает его необоснованным для задач, которые должны выполняться быстро или многократно.
6

Или:

  1. Использование String(format:):

    • Typecast Double to String с %.3f формата %.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))!
          }
      }
      
  2. По расчетам

    • умножьте на 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
          }
      }
      
6

Если вы хотите округлить значения 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
    Лучший ответ на данный момент.
  • 0
    (4.81).roundedDecimal(to: 2, mode: .down) вернет 4.8 вместо 4.81, используйте Decimal(string: self.description)! для точного decimalValue
Показать ещё 3 комментария
6

Это более гибкий алгоритм округления до 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
6

Не быстро, но я уверен, что вы поняли.

pow10np = pow(10,num_places);
val = round(val*pow10np) / pow10np;
5

округлить двойное значение до x число десятичных
NO. цифр после десятичной

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
  • 0
    Что происходит с этим кодом? Что демонстрируют три примера?
  • 0
    Ответы только на код не помогают, пожалуйста, попробуйте объяснить, что делает каждый из этих примеров.
5

Лучший способ форматирования двойного свойства - использовать предопределенные методы Apple.

mutating func round(_ rule: FloatingPointRoundingRule)

FloatingPointRoundingRule - это перечисление, которое имеет следующие возможности

Перечисления:

case awayFromZero Раунд до ближайшего допустимого значения, величина которого больше или равна значению источника.

case down Раунд до ближайшего допустимого значения, которое меньше или равно источнику.

case toNearestOrAwayFromZero Раунд до ближайшего допустимого значения; если два значения одинаково близки, выбирается единица с большей величиной.

case toNearestOrEven Раунд до ближайшего допустимого значения; если два значения одинаково близки, выбирается четный.

case toZero Раунд до ближайшего допустимого значения, величина которого меньше или равна значению источника.

case up Раунд до ближайшего допустимого значения, которое больше или равно источнику.

var aNumber : Double = 5.2
aNumber.rounded(.up) // 6.0
1
//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"
1

Мне было интересно узнать, можно ли исправить пользовательский ввод. То есть, если они вводят три десятичных знака вместо двух для суммы в долларах. Скажем, 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


}
0
extension String{
  var roundedValue:String {
     return String(format: "%.3f", self)
}}

Использование:

totalWorkTimeInHours.roundedValue
-3

Задача:

double d=3.0;

d/100= 0.0299999999

Мне нужно 0.03

Решение:

NSNumber *doubleNSNumber=[[NSNumber alloc] initWithDouble:d/100.0];
double roundedNumber=[doubleNSNumber doubleValue];

roundedNumber=0.03

Ещё вопросы

Сообщество Overcoder
Наверх
Меню