web-dev-qa-db-ja.com

CGFloatをintに安全にフローリングまたはシーリングする方法は?

配列のインデックスを計算するために、CGFloatintにフロアまたはシーリングする必要があることがよくあります。

floorf(theCGFloat)またはceilf(theCGFloat)で永久に見られる問題は、浮動小数点の不正確さで問題が発生する可能性があることです。

つまり、CGFloat2.0fであるが、内部的には1.999999999999fまたはそのようなものとして表される場合はどうでしょうか。私はfloorfを実行し、再びfloatである1.0fを取得します。それでも私はこの獣をintにキャストしなければならず、別の問題を引き起こす可能性があります。

2.0のようなものが偶然に1にフロアリングされず、2.0のようなものが偶然に2にシーリングされないように、floatintにフロアリングまたはシーリングするベストプラクティスはありますか?

20
Proud Member

あなたの質問にはいくつかの誤解があります。

cGFloatが2.0fであるが、内部的には1.999999999999fと表されている場合

起こり得ない; 2.0は、すべての合理的に小さい整数と同様に、浮動小数点で正確に表現されます。 CGFloat2.0f、それは実際には2.0です。

2.0のようなものが誤って2に制限されることはありません

2.0の上限is 2;それはおそらく他に何でしょうか?


私があなたが本当に質問している質問は、「数学的にすべきが正確に2.0であるが、実際にはわずかに少ない不正確な結果を生成する計算を行うと仮定します。floorその値にすると、2.0ではなく1.0になります。これを防ぐにはどうすればよいですか?」

これは実際には、「正しい」答えが1つもないかなり微妙な質問です。入力値をどのように計算しましたか?結果をどうしますか?

20
Stephen Canon

迅速な補足回答

floorceilCGFloatと一緒に使用する方法を探してここに来た人のための補足的な回答としてこれを追加します(私がしたように)。

_var myCGFloat: CGFloat = 3.001
floor(myCGFloat) // 3.0
ceil(myCGFloat) // 4.0
_

Intが必要な場合は、1にキャストできます。

_var myCGFloat: CGFloat = 3.001
Int(floor(myCGFloat)) // 3
Int(ceil(myCGFloat)) // 4
_

更新

C floor関数とceil関数を使用する必要がなくなりました。 Swift round()丸め規則 を使用できます。

_var myCGFloat: CGFloat = 3.001
myCGFloat.round(.down) // 3.0
myCGFloat.round(.up) // 4.0
_

元の変数を変更したくない場合は、rounded()を使用します。

注意事項

  • 32ビットと64ビットの両方のアーキテクチャで動作します。

も参照してください

25
Suragch

編集-この答えが正しくない理由のコメントを読んでください:)

floatintにキャストすると、暗黙的にfloorfになります。つまり、_(int)5.9_は_5_になります。あなたがそれを気にしないなら、ただキャストしてください:)

切り上げたい場合はceilfの結果をキャストするだけです-丸め後にキャストしてもエラーは発生しません(または、必要に応じてエラーを追加してからキャストします(つまり、 `(int)(5.9+ 1) 'は' 6 'です-切り上げと同じです)。

最も近い値に丸めるには、0.5を追加します-_(int)(5.9+0.5)_は_6_ですが、_(int)(5.4+0.5)_は_5_です。私はroundf(5.9)を使用するだけですが:)

4
deanWombourne