web-dev-qa-db-ja.com

C#:整数に対して、丸めを使用して簡単な計算を行うにはどうすればよいですか?

最も近い整数に丸められた方程式の結果が必要です。例えば.

137 * (3/4) = 103

次の誤ったコードを検討してください。

int width1 = 4;
int height1 = 3;

int width2 = 137;
int height2 = width2 * (height1 / width1);

C#で「整数」演算を実行する適切な方法は何ですか?

私は本当にしなければなりませんか:

int height2 = (int)Math.Round(
      (float)width2 * ((float)height1 / (float)width1)
   );
19
Ian Boyd

上で述べたように、除算の前に乗算を行う必要があります。とにかく、除数だけをキャストして式を書くことができます。

int height2 = (int)Math.Round(width2 * (height1 / (float)width1));
16
Aaron
int height2 = (width2 * height1) / width1;
3

最初に乗算を実行し(オーバーフローする可能性が低い限り)、次に除算を実行します。

3/4 == 0整数演算(整数演算は除算で丸めず、切り捨てます)。

本当に丸めが必要な場合は、固定小数点または浮動小数点で作業するか、モジュラスを試してみる必要があります。

3
plinth

これが最もエレガントな方法だと思います。

Math.round(myinteger * 0.75);

3/4の代わりに0.75を使用すると、暗黙的に倍精度/浮動小数点にキャストされます。これに提供されているデフォルトの関数を使用しないのはなぜですか?

2
Ruben

ちょうどこの質問に出くわしました。アーロンの答えは私にはほとんど正しいようです。しかし、問題が「現実の世界」の問題である場合は、中間点の丸めを指定する必要があると確信しています。アーロンのコードに基づく私の答えは

int height2 = (int)Math.Round(width2 * (height1 / (float)width1),MidpointRounding.AwayFromZero);

違いを確認するには、コンソールでそのコードを実行します

    Console.WriteLine((int)Math.Round(0.5));
    Console.WriteLine((int)Math.Round(1.5));
    Console.WriteLine((int)Math.Round(2.5));
    Console.WriteLine((int)Math.Round(3.5));
    Console.WriteLine((int)Math.Round(0.5, MidpointRounding.AwayFromZero));
    Console.WriteLine((int)Math.Round(1.5, MidpointRounding.AwayFromZero));
    Console.WriteLine((int)Math.Round(2.5, MidpointRounding.AwayFromZero));
    Console.WriteLine((int)Math.Round(3.5, MidpointRounding.AwayFromZero));
    Console.ReadLine();

詳細は this の記事をご覧ください。

1
Pianoman

コードのゼロ行を追加することにより、間違ったコードを修正します。

float width1 = 4;
float height1 = 3;

float width2 = 137;
float height2 = width2 * (height1 / width1);

小数を含む可能性のある変数には、浮動小数点数を使用する必要があります。これには、比率から計算された高さが含まれます。それが問題である場合は、いつでも後でintにキャストできます。

1
andrewrk

Floatにキャストしないでください。32ビット整数よりも精度が低くなります。浮動小数点を使用する場合は、常にfloatではなくdoubleを使用してください。

1
rwallace

6年後(四捨五入)、これが私の貢献です-私がずっと前に学んだ小さなトリックですが、他の誰もここで言及していないことに驚いています。

除算を行う前に、分子に除数の半分を追加して丸めを行うという考え方です。

    int height2 = (width2 * height1 + width1 / 2) / width1;

実際には、OPのように除数が変数である場合に、これを行うことを必ずしもお勧めしません。代わりに、Math.Round()を使用する方がはるかに理解しやすいので、より良いかもしれません。

しかし、除数が定数である場合、私はこのトリックを使用します。だから代わりに

    int height2 = width2 * height1 / 4;  // No rounding

私は使用します

    int height2 = (width2 * height1 + 2) / 4;

より典型的な例を次に示します

  private static Size ResizeWithPercentage(Size oldSize, int resizePercentage)
  {
     return new Size((oldSize.Width * resizePercentage + 50) / 100, 
                     (oldSize.Height * resizePercentage + 50) / 100);
  }

もう1つの可能性は、このトリックを、ドンギルモアとスーパーキャットが述べた、指定または暗黙の2で除算する代わりに、分子と分母の両方に2を掛けることができるというアイデアと組み合わせることです。

    int height2 = (width2 * height1 * 2 + width1) / (width1 * 2);

これにより、除数が奇数であるか、奇数である可能性がある場合に、より適切な回答が得られます。

1
RenniePet
int height2 = ((width2 * height1 * 10) + 5) / (width1 * 10);

整数除算の前に、除数がゼロでないことを確認してください。また、これは正の商を想定していることに注意してください。負の場合、丸めは+5ではなく-5である必要があります。

0
dongilmore

Convertの変換は常に丸められます。

int height2 = Convert.ToInt32(width2 * height1 / (double)width1);
0
Tod

最終的な除算が偶数であり、結果が常に正である場合の合理的に効果的なアプローチは、その値の半分で除算し、1を加算し、2で除算することです。結果が負になる可能性がある場合は、可能であれば、すべてが正になる量を追加し、計算を行ってから、対応する量を差し引きます。

最終的な除算が奇数になる場合は、分子と分母の両方に2を掛けてから、上記のように進めます。たとえば、丸められたa * 5/7を計算するには、(a*10+1)>>1を計算します。注意すべき点の1つは、オーバーフローを回避するために値をより大きな数値タイプに拡張する必要がある場合があることです。それが不可能な場合は、分割を細かく分割する必要があります。たとえば、a * 14/15を計算するには、((a * 4/3 * 7)/ 5 + 1)/ 2を計算します。 aが大きすぎると、その計算はオーバーフローする可能性がありますが、許容範囲は、他の除算の前に3で除算せずに評価された場合の3倍になります。操作を細分化すると、丸めの精度が少し低下しますが、多くの目的には十分に近いことに注意してください。

0
supercat

ジェフリーのメッセージについて詳しく説明します。通常、32ビット整数をオーバーフローするよりも必要な小数を切り捨てる可能性が高いため(乗算と除算は可換であるため)、通常、除算の前に乗算を行う必要があります。

0
James Curran