Pythonで浮動小数点を整数に変換する最も安全な方法は?


215

Pythonの数学モジュールには、floor&などの便利な関数が含まれていますceil。これらの関数は、浮動小数点数を取り、その下または上にある最も近い整数を返します。ただし、これらの関数は答えを浮動小数点数として返します。例えば:

import math
f=math.floor(2.3)

今すぐf返します:

2.0

丸めエラーのリスクを冒すことなく(たとえば、フロートが1.99999に相当する場合)、このフロートから整数を取得する最も安全な方法は何ですか?


7
math.floor v2.6ではfloatを返しますが、v3では整数を返します。この時点(OPのほぼ6年後)では、この問題が発生することはほとんどありません。
sancho.s ReinstateMonicaCellio 2016

ただし、numpyは依然としてfloatを返すため、質問は有効です。
Vincenzooo

回答:


178

浮動小数点数で表すことができるすべての整数は、正確に表現されます。したがってint、結果を安全に使用できます。不正確な表現は、2の累乗ではない分母で有理数を表現しようとしている場合にのみ発生します。

これがうまくいくことは決して簡単ではありません!問題の数値の大きさが十分に小さい場合、int∘floor=⌊⋅⌋であるのはIEEE浮動小数点表現のプロパティですが、int(floor(2.3))が1の場合は、異なる表現が可能です。

から引用する ウィキペディア

絶対値が2 24以下の整数は単精度形式で正確に表現でき、絶対値が2 53以下の整数は正確に倍精度形式で表現できます。


8
少し深く行くための+1。また、理由について簡単な説明を加えることもできます。en.wikipedia.org / wiki / Floating_point:D
Gordon Gustafson

Python 2では、「int」はCの「int」と同じです。Python 3では、「int、stackoverflow.com/questions/13795758/…」のサイズに制限はないようです。「int」の意味は、オペレーティングシステムと基盤となるハードウェアにも依存します。en.wikipediaを参照してください。 ORG /ウィキ/ 64 bit_computing#64 bit_data_modelsを。あなたはC-APIでプログラミングしている場合は、Pythonの3あなたが長いとsize_tのの定義は、ご使用のプラットフォーム上にあるものには非常に注意する必要があります。docs.python.org/3 /c-api/long.html
フアン

112

使用int(your non integer number)はそれを釘付けになります。

print int(2.3) # "2"
print int(math.sqrt(5)) # "2"

4
これは、負の数のために動作しません。floor一方、ダウンラウンドint0に向けたラウンド
ヨッヘン・

1
@jochen私int(-2.3)はPythonディストリビューションのCanopy 2.7.6でテストし-2、期待通りに取得しました。整数値は、正式な数学の定義と同じように負の数にすることができます。
srodriguex 2014

5
私は、同意int(-2.3)できます-2あなたが言うように、それはの方に丸めので、0すなわち、この場合にアップ。対照的に、使用される元の質問はmath.floor常に切り捨てられmath.floor(-2.3)ます。-3.0ます。
jochen 2014

1
それは本当に問題ではありません。OPはの結果から整数を必要とするだけですmath.floor。この答えは、floatを整数に変換する方法を示しています。フロートを取り出しmath.floor、パイプで通しますintint(math.floor(2.3))
取り出し

4
あなたも質問を読みましたか?彼はint()関数を認識していますが、2.0ではなく1.9999で問題が発生する可能性があるかどうかを尋ねています。あなたの答えは、答えにさえ
まったく似てい

48

ラウンド関数を使用できます。2番目のパラメーター(有効桁数)を使用しない場合は、必要な動作が得られると思います。

IDLE出力。

>>> round(2.99999999999)
3
>>> round(2.6)
3
>>> round(2.5)
3
>>> round(2.4)
2

28
round少なくともPython 2.6では、浮動小数点数も返します。
フィリップ

8
Python 3.1.2では、roundはintを返します。
ロバート

2
実際、Python 3.x ではとの両方が整数roundfloor返します。だから私は質問がPython 2.xに関係していると思います。
フィリップ

4
たぶんint(round(2.65))
teewuane、2015年

1
なぜround(6.5)6を与えるのですか?それceil()以外の場合は、小数点以下の直後に5(または9まで)があると、フロートのようです。この場合、なぜこれが機能しないのですか?または、数値が6で終わり、小数点の直後に5がある場合
candh

43

前の2つの結果を組み合わせると、次のようになります。

int(round(some_float))

これにより、floatがかなり信頼できる整数に変換されます。


非常に長いフロートを丸めようとするとどうなりますか?これは少なくとも例外を発生させますか?
アゴスティーノ

@Agostino「非常に長い山車」とはどういう意味ですか?
kralyk 2016年

@kralykはfloat、通常intが保持できる数よりも大きい数を表すことを意味します。Python 2ではfloatlong(丸め後)を使用してのみ表すことができる値はありますか?
Agostino 2016年

@kralyk、つまりラウンド終了後?では、それらをintにキャストすると例外が発生するのでしょうか、それとも単に切り捨てられるのでしょうか?
Agostino

@Agostinoいいえ、int()関数は必要なものに基づいてan intまたはa longを生成します...
kralyk

18

これがうまくいくことは決して簡単ではありません!問題の数値の大きさが十分に小さい場合、int∘floor=⌊⋅⌋であるのはIEEE浮動小数点表現のプロパティですが、int(floor(2.3))が1の場合は、異なる表現が可能です。

この投稿はなぜそれがその範囲で機能するかを説明しています

doubleでは、32ビット整数を問題なく表すことができます。丸めの問題ありません。より正確には、doubleは2 53から-2 53までのすべての整数を表すことができます。

簡単な説明:doubleは、最大53桁の2進数を格納できます。さらに必要な場合は、右側にゼロが埋め込まれます。

したがって、53はパディングなしで格納できる最大数です。もちろん、必要な桁数が少ない(整数の)数値はすべて正確に保存できます。

111(省略)111に 1を加えると(53 1)は100 ... 000(53ゼロ)になります。ご存知のように、53桁を格納できます。これにより、右端にゼロが埋め込まれます。

これは2 53の由来です。


詳細: IEEE-754浮動小数点の動作を考慮する必要があります。

  1 bit    11 / 8     52 / 23      # bits double/single precision
[ sign |  exponent | mantissa ]

次に、数は次のように計算されます(ここでは関係のない特殊なケースは除きます)。

-1 符号 ×1仮数×2指数-バイアス

ここで、バイアス= 2指数1 - 1 -、すなわち1023及び二重/単精度127それぞれ。

掛けることを知っ2 Xと、すべてのビットXが単純にシフトすることがわかりますと、桁左になので、整数の仮数部のすべてのビットの小数点の右側がゼロになる必要があることは簡単にわかります。

ゼロ以外の整数は、バイナリで次の形式になります。

1x ... xここで、x -esはMSBの右側のビット(最上位ビット)を表します。

ゼロを除外したため、MSB は常に1になります。これが、MSBが格納されない理由です。整数を格納するには、それを前述の形式にする必要があります。-1 符号 ×1.仮数×2 指数-バイアス .。

これは、MSBの左側にMSBのみが存在するようになるまで、ビットを小数点以上にシフトすることと同じです。次に、小数点の右側のすべてのビットが仮数に格納されます。

これから、MSBとは別に最大で52桁の2進数を格納できることがわかります。

したがって、すべてのビットが明示的に格納される最大数は

111(omitted)111.   that's 53 ones (52 + implicit 1) in the case of doubles.

このためには、小数点を52桁シフトするように指数を設定する必要があります。指数を1増やした場合、小数点以下の左側の桁はわかりません。

111(omitted)111x.

慣例により、それは0です。仮数全体をゼロに設定すると、次の数を受け取ります。

100(omitted)00x. = 100(omitted)000.

これは、1の後に53のゼロが続き、52が格納され、指数のために1が追加されます。

これは2 53を表し、すべての整数を正確に表すことができる境界(負と正の両方)を示します。1を2 53に追加する場合、暗黙のゼロ(で示されるx)を1 に設定する必要がありますが、それは不可能です。


8

math.floor 常に整数を返すため、 int(math.floor(some_float))丸め誤差が発生することはありません。

math.floor(some_large_float)ただし、丸め誤差は、ですでに導入されている可能性があります。あるいは、最初にフロートに大量の数値を格納する場合でもそうです。(浮動小数点数に格納すると、大きな数は精度を失う可能性があります。)


7
From:docs.python.org/2/library/math.html-math.floor(x)-xの下限をfloatとして返します。これは、x以下の最大の整数値です。
Bill Rosmus 2013

intがすでに同じことをしているのに、なぜmath.floorを呼び出さなければならないのですか?
アレックス

1
@Alex:intそしてfloorもちろん、負の数に異なる値を返します。

8

文字列floatをintに変換する必要がある場合は、このメソッドを使用できます。

例:'38.0'38

これをintに変換するには、float型、次にint型としてキャストできます。これは、フロート文字列または整数文字列でも機能します。

>>> int(float('38.0'))
38
>>> int(float('38'))
38

:これにより、小数点以下の数値が取り除かれます。

>>> int(float('38.2'))
38

1

変数を使用して実数/浮動小数点数を整数に変換する別のコードサンプル。「vel」は実数/浮動小数点数であり、次に高い整数「newvel」に変換されます。

import arcpy.math, os, sys, arcpy.da
.
.
with arcpy.da.SearchCursor(densifybkp,[floseg,vel,Length]) as cursor:
 for row in cursor:
    curvel = float(row[1])
    newvel = int(math.ceil(curvel))

0

あなたが「最も安全な」方法を求めているので、私はトップの答え以外の別の答えを提供します。

精度を失わないようにする簡単な方法は、変換後に値が等しいかどうかを確認することです。

if int(some_value) == some_value:
     some_value = int(some_value)

たとえば、floatが1.0の場合、1.0は1と同じです。したがって、intへの変換が実行されます。また、浮動小数点数が1.1の場合、int(1.1)は1に等しく、1.1!= 1になります。したがって、値は浮動小数点数のままであり、精度を失うことはありません。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.