浮動小数点を使用せずに、最も近い整数に丸めるシンプルでPython的な方法はありますか?私は次のことをしたいのですが、整数演算を使用します:
skip = int(round(1.0 * total / surplus))
==============
@ジョン:浮動小数点はプラットフォーム間で再現できません。コードが異なるプラットフォーム間でテストをパスするようにしたい場合は、浮動小数点を回避する必要があります(またはテストにハッピーなエスピロンを追加して、それが機能することを願っています)。上記はほとんど/すべてのプラットフォームで同じになるほど簡単な場合がありますが、浮動小数点を完全に回避する方が簡単なので、そのような決定はしたくありません。 「Pythonの精神ではない」とはどういう意味ですか?
あなたはこれを非常に簡単に行うことができます:
(n + d // 2) // d
、ここでn
は被除数、d
は除数です。
(((n << 1) // d) + 1) >> 1
または同等の(((n * 2) // d) + 1) // 2
などの代替手段は、最近のCPythonではint
が古いlong
のように実装されているため、遅くなる可能性があります。
シンプルなメソッドは、3つの変数アクセス、1つの定数ロード、3つの整数演算を実行します。複雑なメソッドは、2つの変数アクセス、3つの定数ロード、4つの整数演算を実行します。整数演算は、関連する数値のサイズに応じて時間がかかる可能性があります。関数ローカルの変数アクセスには、「ルックアップ」は含まれません。
あなたが本当にスピードに夢中なら、ベンチマークをしてください。そうでなければ、KISS。
skip = (((total << 1) // surplus) + 1) >> 1
左に1ビットシフトすると、実質的に2倍になり、右に1ビットシフトすると、2で切り捨てられます。真ん中に1を追加すると、結果が小数部.5を超える場合、「切り捨て」が実際に切り上げられます。
基本的には書いたのと同じです...
skip = int((1.0*total/surplus) + 0.5)
すべてが2で乗算され、後で2で除算される場合を除いて、これは整数演算で実行できるものです(ビットシフトは浮動小数点を必要としないため)。
zhmyh's answer 回答に触発され、
q, r = divmod(total, surplus)
skip = q + int(bool(r)) # rounds to next greater integer (always ceiling)
、私は次の解決策を思いつきました:
q, r = divmod(total, surplus)
skip = q + int(2 * r >= surplus) # rounds to nearest integer (floor or ceiling)
OPがnearest整数への丸めを要求したため、zhmhsの解は実際にはわずかに正しくありません。常にnextに丸められるためです。より大きい整数、ただし私のソリューションは要求どおりに機能します。
(私の回答がzhmhの回答の編集またはコメントであるほうがよいと思われる場合は、提案された編集が拒否されたことを指摘しておきます。コメントするにはまだ十分な評判がありません!)
divmod
がどのように定義されているのか疑問に思う場合:その ドキュメント に従って
整数の場合、結果は
(a // b, a % b)
と同じです。
したがって、OPからの要求に応じて、整数演算を使用します。
さらに別の面白い方法:
q, r = divmod(total, surplus)
skip = q + int(bool(r))
分割する前に、単純に丸め規則に注意してください。最も単純な切り上げの場合:
if total % surplus < surplus / 2:
return total / surplus
else:
return (total / surplus) + 1
適切な四捨五入を行う必要がある場合は、少し調整してください。