[解決済み】整数の割り算が常に切り上げられるようにするにはどうしたらいいですか?
質問
整数の割り算で、必要な場合は必ず切り上げられるようにしたい。これより良い方法はないでしょうか?キャスティングが多いのです :-)
(int)Math.Ceiling((double)myInt1 / myInt2)
解決方法は?
UPDATE: この質問は 2013年1月のブログで取り上げた . 素晴らしい質問をありがとうございました
整数の演算を正しく行うのは難しい。これまで散々実証されてきたように、quot;cleft"なトリックをやろうとした瞬間に、間違いである確率が高いのです。 また、欠陥が見つかった場合、その欠陥を修正するためにコードを変更することもあります。 その修正が他の何かを壊すかどうかを考えずに は、良い問題解決手法とは言えません。 今のところ、この全く特別難しくない問題に対して、5種類の間違った整数演算の解決法が投稿されていると思います。
整数演算の問題に取り組む正しい方法、つまり最初から答えを出せる可能性を高める方法は、問題に慎重に取り組み、一歩ずつ解決し、その際に優れた工学的原則を用いることです。
まず、置き換えようとしているものの仕様書を読むことから始めましょう。 整数の割り算の仕様に明記されています。
-
除算は結果を0に丸める
-
2つのオペランドが同じ符号であれば結果は0または正、反対の符号であれば0または負となります。
-
左オペランドが表現可能な最小の int で、右オペランドが -1 の場合、オーバーフローが発生します。[ArithmeticException をスローするか、オーバーフローを報告せず、左オペランドの値を結果とするかは、実装によって決まります。
-
右オペランドの値が 0 の場合、System.DivideByZeroException がスローされます。
私たちが欲しいのは、商を計算し、結果を丸める整数の除算関数です。 常に上向き ではなく 常にゼロに向けて .
だから、その関数の仕様を書けよ。
私たちの関数
int DivRoundUp(int dividend, int divisor)
は、可能な限りの入力に対する振る舞いを定義しておく必要があります。その未定義の振る舞いは深く憂慮すべきものなので、それを排除しましょう。私たちの演算はこのような仕様になっていると言うことにしよう。
-
演算は、除数がゼロの場合にスローされます。
-
演算は、配当がint.minvalで除数が-1である場合に投げられます。
-
余りがない場合 -- 除算が「偶数」である場合 -- 戻り値は積分商となります。
-
それ以外の場合は 最小 である整数が より大きい は商より大きい、つまり常に四捨五入される。
これで仕様が決まったので、次のようなものが出てくることがわかりました。 テスト可能な設計 . さらに、「商をdoubleで計算するのではなく、整数演算のみで問題を解く」という設計基準を追加するとします。
では、何を計算すればよいのでしょうか。 整数演算だけを使いながら仕様を満たすには、明らかに3つの事実を知る必要があります。まず、整数の商が何であったか?2つ目は、余りのない除算であったか?3つ目は、そうでない場合、整数の商は切り上げまたは切り下げで計算されたか?
仕様と設計ができたので、コードを書き始めましょう。
public static int DivRoundUp(int dividend, int divisor)
{
if (divisor == 0 ) throw ...
if (divisor == -1 && dividend == Int32.MinValue) throw ...
int roundedTowardsZeroQuotient = dividend / divisor;
bool dividedEvenly = (dividend % divisor) == 0;
if (dividedEvenly)
return roundedTowardsZeroQuotient;
// At this point we know that divisor was not zero
// (because we would have thrown) and we know that
// dividend was not zero (because there would have been no remainder)
// Therefore both are non-zero. Either they are of the same sign,
// or opposite signs. If they're of opposite sign then we rounded
// UP towards zero so we're done. If they're of the same sign then
// we rounded DOWN towards zero, so we need to add one.
bool wasRoundedDown = ((divisor > 0) == (dividend > 0));
if (wasRoundedDown)
return roundedTowardsZeroQuotient + 1;
else
return roundedTowardsZeroQuotient;
}
これは賢いか?いいえ、美しいですか?いいえ、短いですか?いいえ、仕様に即しているか? そう思っていますが、十分に検証したわけではありません。 でも、かなり良さそうですね。
私たちはプロフェッショナルです。良いエンジニアリングプラクティスを使いましょう。ツールを研究し、望ましい動作を特定し、まずエラーケースを検討し、そして 明らかに正しいことを強調するようにコードを書いてください。 バグを見つけたら、比較の方向をランダムに入れ替えたり、すでに動作しているものを壊したりする前に、そもそもアルゴリズムに深い欠陥がないかどうかを検討しましょう。
関連
-
[解決済み】「The breakpoint will not currently be hit」を改善するには?このドキュメントにはシンボルが読み込まれていません。" という警告はどうすれば改善されますか?
-
[解決済み] intをenumにキャストするにはどうすればよいですか?
-
[解決済み] ディープクローンオブジェクト
-
[解決済み] 複数の例外を一度にキャッチする?
-
[解決済み] なぜList<T>を継承しないのですか?
-
[解決済み] 整数の平方根が整数であるかどうかを判断する最速の方法
-
[解決済み] NaN値をチェックするにはどうすればよいですか?
-
[解決済み] 特定のプロパティに対するLINQのDistinct()
-
[解決済み] 簡単な面接問題が難しくなった:1~100の数字が与えられたとき、ちょうどk個の数字が欠けていることを見つけなさい。
-
[解決済み] JavaScriptで整数の除算を行い、余りを別途取得する方法は?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】「未割り当てのローカル変数を使用」とはどういう意味ですか?
-
[解決済み】"出力タイプがクラスライブラリのプロジェクトは直接起動できない"
-
[解決済み】「namespace x already contains a definition for x」エラーの修正方法は?VS2010にコンバートした後に発生しました。
-
[解決済み】Unity3DでOnTriggerEnterが動作しない件
-
[解決済み】Swashbuckle/Swagger + ASP.Net Core: "Failed to load API definition" (API定義の読み込みに失敗しました
-
[解決済み】ファイルへの読み書きの際に共有違反のIOExceptionが発生する C#
-
[解決済み】パラメータ付きRedirectToAction
-
[解決済み】名前 'ViewBag' が現在のコンテキストに存在しない - Visual Studio 2015
-
[解決済み] 整数の割り算の結果を丸めるには?
-
[解決済み】C / C++で整数の除算を高速に天井する