質問
浮動小数点を使用せずに、最も近い整数に丸めて、シンプルでピトニックな方法がありますか?以下をやりたいのですが、整数算術を使用してください。
skip = int(round(1.0 * total / surplus))
==============
@John:フローティングポイントは、プラットフォーム間で再現できません。コードをさまざまなプラットフォームに渡すことを望む場合は、浮遊点を避ける必要があります(または、テストにハッキーなEspilonのものを追加して、それが機能することを願っています)。上記は、ほとんど/すべてのプラットフォームで同じになるほど単純かもしれませんが、浮動点を完全に回避するのが簡単であるため、その決定をしたくありません。それは「Pythonの精神ではない」のはどうですか?
解決
これは非常に簡単に行うことができます:
(n + d // 2) // d
, 、 どこ n
配当です d
除数です。
のような代替案 (((n << 1) // d) + 1) >> 1
または同等のもの (((n * 2) // d) + 1) // 2
最近のcpythonsでは遅くなる可能性があります int
古いもののように実装されています long
.
単純な方法は、3つの変数アクセス、1つの一定の負荷、および3つの整数操作を行います。複雑な方法は、2つの可変アクセス、3つの一定の負荷、および4つの整数操作を実行します。整数操作には、関連する数値のサイズに依存する時間がかかる可能性があります。関数の可変アクセスローカルには「ルックアップ」が含まれません。
あなたが本当にスピードを求めて乾燥しているなら、ベンチマークをしてください。そうでなければ、キス。
他のヒント
skip = (((total << 1) // surplus) + 1) >> 1
残ったものを1つのビットでシフトすることは、効果的に2を増やし、2つの丸みを帯びた丸みを帯びたものを1つビット分割します。中央に1つを追加すると、結果が.5小数の部分を超えていれば、「丸め」が実際に丸められるようになります。
それは基本的にあなたが書いた場合と同じです...
skip = int((1.0*total/surplus) + 0.5)
すべてが2で増加し、その後2で分割されることを除いて、これは整数算術でできることです(ビットシフトは浮動点を必要としないため)。
に触発された Zhmyhの答え 答え、それはそうです
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が丸めを求めたので 最も近い 整数、ZHMHSの解決策は実際にはわずかに間違っています。 次に大きい 私のソリューションは要求どおりに機能しますが、整数。
(私の答えが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
適切なラウンドとネズミを行う必要がある場合は、少し調整します。
これも機能するはずです:
def rint(n):
return (int(n+.5) if n > 0 else int(n-.5))