double値をxの小数点以下の桁数に丸める


395

誰かがSwiftで倍精度値をxの小数点以下の桁数に丸める方法を教えてもらえますか?

私が持っています:

var totalWorkTimeInHours = (totalWorkTime/60/60)

totalWorkTime第二にNSTimeInterval(ダブル)であること。

totalWorkTimeInHours 時間は私に与えられますが、それは私にそのような非常に正確な数の時間量を与えます。例えば1.543240952039 ......

印刷するときに、たとえば1.543に切り捨てるにはどうすればよいtotalWorkTimeInHoursですか。


1
参照してください私の答えを 9種類のダーウィンを用いた二重を丸めるための方法までを見つけるためにround(_:)Double round()NSString初期化子、String初期化子、NumberFormatterでも、ダブル延長やNSDecimalNumberDecimal
Imanou Petit 2018

@Rounded、迅速な5.1プロパティラッパー:gist.github.com/abhijithpp/1cc41b41a5d1c8f007da90f20bc0c65f
Abhijith

回答:


389

Swiftのround関数を使用してこれを実現できます。

a Doubleを3桁の精度で丸めるには、まず1000を掛け、丸め、丸めた結果を1000で割ります。

let x = 1.23556789
let y = Double(round(1000*x)/1000)
print(y)  // 1.236

あらゆる種類printf(...)またはString(format: ...)解決策を除いて、この操作の結果はまだタイプDoubleです。

編集:
それが時々機能しないというコメントについては、これを読んでください:

すべてのプログラマが浮動小数点演算について知っておくべきこと


いくつかの理由でそれは役に立ちません..私はこれを次のケースで使用していますTransformOf <Double、String>(fromJSON:{Double(round(($ 0!as NSString).doubleValue * 100)/ 100)}、toJSON: {"($ 0)"})
フォークス、2015

29
プレイグラウンドでは機能しません:let rate = 9.94999999999; Double(round(rate * 100) / 100);出力:9.94999999999, 9.949999999999999印刷のみで機能しますが、変数に割り当てるにはどうすればよいですか?
アレクサンダーヤコブレフ2016

これには、単純なDoubleではなく、Decimalを使用する必要があります。
csotiriou

13
「すべてのコンピュータ科学者が浮動小数点演算について知っておくべきこと」は73ページです。その上のTL; DRとは何ですか?:)
JaredH 2018

1
@HardikDG覚えていません、すみません:-)
Alexander Yakovlev

431

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桁に丸められた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

17
例えば、: -スウィフトのダブルの性質は、それが不正確できることのように見える小数点第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。注目に値する何か。
Ben Saufley 2016

2
残念ながら、これはSwift 3では機能しなくなりました。このエラーが発生しますNo '*' candidates produce the expected contextual result type 'FloatingPointRoundingRule'
koen

2
私は解決策を更新し、スウィフト3の拡張子を追加
セバスチャン

2
より迅速に3にするには、func丸めに変更する必要があります(toPlaces場所:Int)-> Double
FouZ

2
@BenSaufleyしかし、98.68と入力しても機能しません。この場合、98.6800003が返されます
Alexander Khitev

340

印刷するときに 、たとえば1.543に切り捨てるにはどうすればよいtotalWorkTimeInHoursですか。

totalWorkTimeInHours印刷用に3桁に丸めるにStringは、format文字列を取るコンストラクタを使用します。

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

24
それは切り捨てであり、丸めではありません
Eyeball

33
@眼球:実際には、それはラウンドします。これは、要求された桁に丸めるCのprintf機能と同じ動作です。そのため、String(format: "%.3f", 1.23489)印刷1.235
zisoft 2014

6
元の投稿者は、表示する文字列ではなく、使用する数値を探しています。
pr1001 2016

17
@ pr1001、たぶんそうかもしれませんが、それは当時ははっきりしていませんでした、そして46人が私の答えが有用であると感じました。スタックオーバーフローは、単にOPを支援するだけのものではありません。
vacawama

3
奇妙なことに、これは毎回0.00を返します。
エリックH

254

Swift 5では、必要に応じて、9つのスタイルのいずれかを選択して、から丸められた結果を得ることができますDouble


#1。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

#2。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

#3。Darwin round関数の使用

FoundationはroundDarwinを介して機能を提供します。

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。DoubleDarwin 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:)メソッドの使用

必要に応じて、NSDecimalNumber10進数を丸めるための詳細ですが強力なソリューションを提供します。

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:_:)初期化子する

スウィフトのStringタイプは財団の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は、高度にカスタマイズ可能なソリューションを提供します。

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、への無料のブリッジであるの使用を検討することをお勧めしますNSDecimalNumberDecimalスウィフトのネイティブ型と申し出などのネイティブ事業者のためのよりエレガントなサポートである+-など、
ロブ・

@Rob NSDecimalRound(_:_:_:_:)関数で答えを更新しました。ありがとう。
Imanou Petit 2018

#9の選択を使用すると、固定小数(精度の桁数)を期待できることが保証され、10進数43.12345および小数= 6とすると、43.123450
Almas Adilbek

1
@ImanouPetitこれを投稿していただきありがとうございます。いくつかの拡張機能を追加できます。
エイドリアン

NumberFormatter最後の選択肢は悲しいですが、ユーザーに数字を提示するための最初の選択肢になるはずです。他の方法では、適切にローカライズされた数値は生成されません。
スルタン


50

これは完全に機能するコードです

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


1
1行ですか?、3行のように見えます;)
ペッターフリバーグ'27

文字列を使って計算することはできません。表示するだけなので、正解だとは思いません。
JBarros35

25

ヨギの答えに基づいて、これが仕事をするSwift関数です:

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

20

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

19

Swift 4、Xcode 10

yourLabel.text =  String(format:"%.2f", yourDecimalValue)

1
私は反対票を投じなかったが、理由はおそらく、これは数値ではなく数値の文字列表現を返すためであると思う。これで十分な場合は問題ありませんが、後で使用するために数値自体を四捨五入したい場合があります。OPは「印刷するとき」と言っていたので、この場合、これは許容可能で、簡単で、クリーンなソリューションだと思います。
Ben Stahl

1
完璧です。1行のソリューション。ラベルに10進値を文字列として表示する必要があるだけです。
zeeshan

18

小数の後の特定の桁のコードは次のとおりです。

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

ここで%.3fは、この数値を小数点以下3桁に丸めるように迅速に指示します。2桁の数値が必要な場合は、次のコードを使用できます。

// StringからDouble

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


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


9

便利な方法は、タイプ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

9

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)
}

2
これまでのベストアンサー。
Codetard 2018

(4.81).roundedDecimal(to: 2, mode: .down)4.81ではなく4.8を返します。Decimal(string: self.description)!正確に使用してくださいdecimalValue
vk.edward.li '22年

1
@ vk.edward.li-はい、4.81のような値は単にで正確に表すことができないDouble(それがになる4.8099999999999996)ため、小数の四捨五入には注意が必要です。ただし、使用しないことをお勧めしますdescription(使用する丸めは文書化されておらず、変更される可能性があるため)。あなたが本当に小数精度の数学をやっているしたい場合は、避けなければならないDouble完全にし、代わりに使用する必要がありDecimal、直接(例えばDecimal(sign: .plus, exponent: -2, significand: 481)またはDecimal(string: "4.81")しかし、使用しないでください。description
ロブ

@Robは通常、「4.81」の文字列値をDoubleとして保存すると取得できません。そのため、self.description(変更されたGrisu2アルゴリズム)を使用して、すでに失われている精度を修正する必要があります
vk.edward.li

要点を理解しました。私はあなたの解決策に同意しません。descriptionメソッドの丸め動作は文書化も保証もされていません。さらに、ローカライズされていません。私見、descriptionロギング以外の目的で使用するのは間違いです。私はDecimal全体を使用するか、Double完全に使用しないか、または単に異なる丸めモードを使用します。または、必要に応じて、Grisuスタイルのアルゴリズムを使用する独自のローカライズされたメソッドを使用します(ただし、小数点以下の桁数を知る必要がある場合は不要と思われます)。ただし、このの補助的な動作に依存することは避けdescriptionます。
Rob

8

これは一種の長い回避策であり、ニーズがもう少し複雑な場合に役立ちます。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は望ましくない)について言及しているため、およびこのクラスでは複数のパラメーターを設定できるため、この方法を使用しています。


1
フォーマッタはプログラム的にはかなり高価であり、迅速にまたは繰り返し実行する必要があるタスクには不適切です。
ジョナサンソーントン

7

私は使うだろう

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

.3fを必要な10進数の任意の数に変更します


彼はNSTimeIntervalでそれを取得するのではなく、3桁で印刷したかった
Mohsen Hossein

7

どちらか:

  1. 使用String(format:)

    • 書式指定子DoubleString付けて型キャストし%.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

これは、有効桁数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

doubleプロパティをフォーマットする最良の方法は、Appleの定義済みメソッドを使用することです。

mutating func round(_ rule: FloatingPointRoundingRule)

FloatingPointRoundingRuleは、次の可能性がある列挙型です。

列挙ケース:

case awayFromZero 大きさがソースの大きさ以上である最も近い許容値に丸めます。

ケースダウン ソース以下の最も近い許容値に丸めます。

case toNearestOrAwayFromZero 最も近い許容値に丸めます。2つの値が等しく近い場合は、大きさが大きい方の値が選択されます。

case toNearestOrEven 最も近い許容値に丸めます。2つの値が等しく近い場合は、偶数の値が選択されます。

ケースに向けてゼロ 大きさがソースの大きさ以下である最も近い許容値に丸めます。

ケースアップ ソース以上の最も近い許容値に丸めます。

var aNumber : Double = 5.2
aNumber.rounded(.up) // 6.0

6

double値を10進数のx数に丸め
ます。10進数の後の数字

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

このコードはどうなっていますか?3つの例は何を示していますか?
ルネ2017

コードのみの回答は役に立ちません。これらの例のそれぞれが何をするかを説明してみてください。
萌え

5

Swiftではありませんが、きっとあなたはそのアイデアを理解するでしょう。

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

4

これはSwift 5で機能するようです。

このための標準関数がまだないことにかなり驚いています。

//四捨五入によるDoubleからn-decimalへの切り捨て

extension Double {

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

}

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

これは文字列として表現するためのきちんとした実装です。桁数表現の拡張をピリオドの後にダブルとして維持することは可能か合理的かと思います。
thinkswift

2

Floatの欠陥を回避するには、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
    }
}

例:
1075.58は、スケール付きのFloatを使用する場合は1075.57に丸めます:2および.down
10進数をスケール付きで使用する場合は1075.58は1075.58に丸めます:.down


1

これは、ユーザーの入力を修正できるかどうか疑問に思いました。これは、金額が2桁ではなく3桁になる場合です。1.11ではなく1.111と言って、丸めによって修正できますか?多くの理由で答えはノーです!金額が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


}

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

数値を持つテキスト要素が必要な場合のSwiftUIのコードを次に示します。

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

    var body : some View {
        Text(String(format: "%.\(digits)f", number))
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.