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

StackOverflow https://stackoverflow.com/questions/299094

  •  08-07-2019
  •  | 
  •  

質問

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

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)
   );
役に立ちましたか?

解決

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

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

他のヒント

int height2 = (width2 * height1) / width1;

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

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

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

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

Math.round(myinteger * 0.75);

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

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

float width1 = 4;
float height1 = 3;

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

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

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

この質問にただつまずいた。アーロンの答えは私にはほとんど正しいようです。しかし、問題が「実世界」である場合は、midpointroundingを指定する必要があると確信しています。問題。アーロンのコードに基づく私の答えは

です
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();

詳細については、をご覧ください。この記事。

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つの可能性は、このトリックをdongilmoreとsupercatで言及されているアイデアと組み合わせて、指定または暗黙の2で除算する代わりに、分子と分母の両方を2で乗算することです。

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

これは、除数が奇数である場合、または奇数である場合に、より良い回答を提供します。

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

変換の変換は常に次のように丸められます:

int height2 = Convert.ToInt32(width2 * height1 / (double)width1);
int height2 = ((width2 * height1 * 10) + 5) / (width1 * 10);

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

最終的な除算が偶数で、結果が常に正である場合、合理的に効果的なアプローチは、その値の半分で除算し、1を加算し、2で除算することです。結果がマイナスになる可能性がある場合は、可能であれば、すべてがプラスになる量を追加し、計算を実行してから、対応する量を後で減算する必要があります。

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

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top