none
decimal除算の丸め処理について RRS feed

  • 質問

  • Console.WriteLine("{0}", 1m / 6m);
    Console.WriteLine("{0}", 1m / 7m);
    Console.WriteLine("{0}", 1m / 15m);
    Console.WriteLine("{0}", 1m / 18m);
    

    上記を実行すると以下が出力されます。

    0.1666666666666666666666666667
    0.1428571428571428571428571429
    0.0666666666666666666666666667
    0.0555555555555555555555555556

    これを以下のように計算する方法がありますか?

    0.1666666666666666666666666666
    0.1428571428571428571428571428
    0.0666666666666666666666666666
    0.0555555555555555555555555555

    pythonでは getcontext().rounding = ROUND_FLOOR で上記のような計算が可能ですが、同じようなことをC#で実現する良い方法があるかどうか、ご存じの方がいらっしゃいましたらご教授願います。

    2019年8月1日 17:10

回答

  • 丸めモードまで指定したいとなると、自分なら
    System.Decimal 構造体の代わりに
    Mol.BigDecimal クラスを使うかな。

    Mol.BigDecimal.MaxDigits = 28;
    Mol.BigDecimal.RoundMode = Mol.BigDecimal.ROUND_MODE.FLOOR;
    
    Mol.BigDecimal answer;
    foreach (var denom in new string[] { "6", "7", "15", "18" })
    {
        answer = Mol.BigDecimal.One / new Mol.BigDecimal(denom);
        Console.WriteLine(answer.ToString("_F").TrimStart());
    }
    Console.ReadLine();

    • 回答としてマーク Askie 2019年8月5日 10:35
    2019年8月2日 0:54
  • https://referencesource.microsoft.com/#mscorlib/system/decimal.cs,423

    どういう目的なのかはイマイチですが、ReferenceSourceを見る限り、そういう制御はできなさそうですね。
    有効数字が1つ減っちゃいますが、DecimalをToString()したあとの文字列の末尾1文字を削るとか?
    あるいは、除算を独自に実装してしまう、というのも手としてはあります。


    jzkey

    • 回答としてマーク Askie 2019年8月5日 10:35
    2019年8月1日 22:32

すべての返信

  • https://referencesource.microsoft.com/#mscorlib/system/decimal.cs,423

    どういう目的なのかはイマイチですが、ReferenceSourceを見る限り、そういう制御はできなさそうですね。
    有効数字が1つ減っちゃいますが、DecimalをToString()したあとの文字列の末尾1文字を削るとか?
    あるいは、除算を独自に実装してしまう、というのも手としてはあります。


    jzkey

    • 回答としてマーク Askie 2019年8月5日 10:35
    2019年8月1日 22:32
  • 丸めモードまで指定したいとなると、自分なら
    System.Decimal 構造体の代わりに
    Mol.BigDecimal クラスを使うかな。

    Mol.BigDecimal.MaxDigits = 28;
    Mol.BigDecimal.RoundMode = Mol.BigDecimal.ROUND_MODE.FLOOR;
    
    Mol.BigDecimal answer;
    foreach (var denom in new string[] { "6", "7", "15", "18" })
    {
        answer = Mol.BigDecimal.One / new Mol.BigDecimal(denom);
        Console.WriteLine(answer.ToString("_F").TrimStart());
    }
    Console.ReadLine();

    • 回答としてマーク Askie 2019年8月5日 10:35
    2019年8月2日 0:54
  • 回答いただき、ありがとうございました。

    標準ではそのような機能はなく、有償外部ライブラリを利用するか、除算を自作するかということですね。

    目的としては、法令上求められる計算を行うためというのが理由となります。数学的に誤差の少ない計算が求められているのではなく、法令が定めるところによる所轄庁の解釈によってこういった計算が必要となっています。

    時間があれば除算を自作するのが一番よさそうではあるのですが、.net以外の選択肢も含めて考えたいと思います。

    ありがとうございました。

    • 回答としてマーク Askie 2019年8月5日 10:35
    • 回答としてマークされていない Askie 2019年8月5日 10:35
    2019年8月5日 10:34
  • 法令ということであれば、具体的な条文例を提示いただいたほうが理解が進むと思います。

    jzkeyさんが提示されていますが、法令で求められている有効精度は何桁でしょうか? C#のdecimal型の結果に対して1桁捨てれば要求を満たす演算はできませんか?

    2019年8月5日 21:31