質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Xcode 7

Xcode 7は、ソフトウェア開発のためのアップルの統合開発環境であるXcodeのバージョン。UIを作成するために用いるグラフィカルツールです。iOS9/OS X El Capitan/watchOS2に対応。Swift 2コンパイラーが搭載されています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Swift 2

Swift 2は、Apple社が独自に開発を行っている言語「Swift」のアップグレード版です。iOSやOS X、さらにLinuxにも対応可能です。また、throws-catchベースのエラーハンドリングが追加されています。

Q&A

解決済

3回答

5308閲覧

swiftでDouble型の切り捨てを誤差なく行いたい

_utah

総合スコア20

Xcode 7

Xcode 7は、ソフトウェア開発のためのアップルの統合開発環境であるXcodeのバージョン。UIを作成するために用いるグラフィカルツールです。iOS9/OS X El Capitan/watchOS2に対応。Swift 2コンパイラーが搭載されています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Swift 2

Swift 2は、Apple社が独自に開発を行っている言語「Swift」のアップグレード版です。iOSやOS X、さらにLinuxにも対応可能です。また、throws-catchベースのエラーハンドリングが追加されています。

0グッド

1クリップ

投稿2017/02/14 00:57

編集2017/02/14 01:13

###前提・実現したいこと
swiftでDouble型の切り捨てがしたい。

現在、型変換と切り捨てを行う汎用的に使える関数を製作しております。
ソースコードに乗せているものは、Double型の数値を受け取り、小数点第二位で切り捨てを行った後、Double型で値を返しています。

###発生している問題・エラーメッセージ
1.50...という値に小数点第二位で切り捨てをかけると、1.4という値が出てきてしまいます。
浮動小数点で誤差が出てしまうことを修正したいです。

###該当のソースコード

swift

1 static func FloorDtoD(number : Double) -> Double{ 2 3 return Double(Int(number * Double(10.0))) / Double(10.0) 4 }

swift

1 static func FloorDtoD(number : Double) -> Double{ 2 3 var ansser : Double = number 4 ansser = ansser * Double(10.0) 5 ansser = floor(ansser) 6 return ansser / Double(10.0) 7 }

###試したこと
nsdecimalnumberを使用した方法も試しましたが、きちんと切り捨てられない(切り捨ててない)ことや、nsdecimalnumberをDouble型に変換し直さないといけないため、正しい値が得られませんでした。

nsdecimalnumberでStringを使用する方法は、まだ、試せていません。

###補足情報(言語/FW/ツール等のバージョンなど)
swift2.3
Xcode7.3.1

追記になります

swift

1 static func FloorDtoD(number : Double) -> Double{ 2 3 let str : String = String(number) 4 let ansser : NSDecimalNumber = NSDecimalNumber(string : str) 5 6 let behavior = NSDecimalNumberHandler( 7 roundingMode: .RoundDown, 8 scale: 2, 9 raiseOnExactness: false, 10 raiseOnOverflow: false, 11 raiseOnUnderflow: false, 12 raiseOnDivideByZero: false) 13 14 return Double(ansser.decimalNumberByRoundingAccordingToBehavior(behavior)) 15 }

こちらでも、1.5ではなく、1.4になってしまう場合があることを確認しました。
また、引数のnumberですが、こちらには1.5が入っていることを確認しました。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ozwk

2017/02/14 01:19

「1.50...という値」具体的にいくつですか?
_utah

2017/02/14 01:25

1.50000です。
ozwk

2017/02/14 01:32 編集

こちらでnumber = 1.50000として計算しても1.4になりませんでした。なんらかの計算式でnumberが計算されるならそれを教えてください。
_utah

2017/02/14 01:53

こちらでも、ベタ書きで確認しましたが、1.4になりませんでした。numberの計算式は、3000.0 * (1.0 - 0.9) * 0.01 / 2.0だったと思います。
guest

回答3

0

3000.0 * (1.0 - 0.9) * 0.01 / 2.0は確かに手計算では1.5ですが、
DoubleやFloatは桁数が有限な2進数であることに注意しましょう。
10進数だと単純な小数も2進数だと循環小数になることが多いです。

例えば
0.01は2進数で0 . 0000 0010 1000 1111 0101 1100 0010 1000 1111 0101 1100 0010 1000 1111 ...
0.9は2進数で0 . 1110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0110 0110...

なお、
2^-1 = 0.5
2^-2 = 0.25
2^-3 = 0.125
2^-4 = 0.0625
...
と、一桁ずれて末尾5と言うパターンなので、
10進数表記で5で終わらない小数は2進数だと循環小数になります。
終わっても循環小数になるものもあります。
なので10進表記の小数をFloat等に変換するとだいたい誤差が出ます。

投稿2017/02/14 02:07

編集2017/02/14 02:26
ozwk

総合スコア13521

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

_utah

2017/02/14 02:40

2^-1 = 0.5 2^-2 = 0.25 ... DoubleやFloatは桁数が有限な2進数 この説明で、なぜ、浮動小数点で誤差が出るのか納得がいきました。 今まで、安易に小数点以下で計算した方がいいと思い、Int型で1で良いところをわざわざDouble型で1.0と書いていましたが、控えるようにしようと思います。
guest

0

1.50000という値の確認方法に問題があるのではないでしょうか?
例えば、

swift

1let value = 1.4999999 2print(value) 3//=> 1.4999999 4print(String(format: "%f", value)) 5//=> 1.500000 6print(FloorDtoD(number: value)) 7//=> 1.4

とか

swift

1let value = 1.499999999999999 2print(value) 3//=> 1.5 4print(FloorDtoD(number: value)) 5//=> 1.4

とか。

参考URL
FloatingPoint / API Reference
IEEE 754 / Wikipedia

投稿2017/02/14 01:47

編集2017/02/14 02:14
fuzzball

総合スコア16731

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

自己解決

numberに送られている値を確認したところ、その値が1.5に丸め込みたい値ではなかったことを確認いたしました。
1.5に丸め込みたかった値は、きちんと丸め込まれており、表示する際に別の値(1.4に丸め込まれた値)を表示していました。

申し訳ありませんでした。

nsdecimalnumberでStringを使用する方法で切り捨てが動作しております。

投稿2017/02/14 02:12

_utah

総合スコア20

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問