| 2017/12/06(Wed) 14:06:25 編集(投稿者)
■No85967 (たかじ さん) に返信 > Deveel.Math.BigDecimalを初めて知ったので、 BigDecimal の実装例は他にもあります(例: No75940 )が、 その中でも、Deveel は有名どころかと思います。
Microsoft 製ライブラリによる BigDecimal 実装が欲しければ、 C:\Windows\assembly\GAC_32\vjslib\2.0.0.0__b03f5f7f11d50a3a\vjslib.dll という手もありますが、今回の要件には合わないですね。 https://blogs.msdn.microsoft.com/dd_jpn/2007/06/26/visual
> ・BigDecimalの演算はAdd、Subtract、Multiply、Divideのメソッドを使用しないとだめなのでしょうか?
「x * y」と「y * x」では結果が変わりますよね?
x * y の右値(y)が何であれ、左値(x)の『精度』が優先されるためです。 これは乗算だけでなく、加算・減算・除算においても同じことです。
そして、このクラスにとっての x * y というのは、 x.Multiply(y, new MathContext(x.Precision)) の意味です。
//using Deveel.Math:
BigDecimal b1 = 300; // 300×10^0 BigDecimal b2 = 10000000 ; // 10000000×10^0 BigDecimal b3 = b1 * b2; // 300×10^-7 BigDecimal b4 = b2 * b1; // 30000000×10^-2 BigDecimal b5 = b1.Multiply(b2); // 3000000000 BigDecimal b6 = b1.Multiply(b2, new MathContext(b1.Precision)); BigDecimal b7 = b1.Multiply(b2, MathContext.Unlimited);
Console.WriteLine("{0}", b1); // 300 Console.WriteLine("{0}", b2); // 10000000 Console.WriteLine("{0}", b3); // 3.00E+9 Console.WriteLine("{0}", b4); // 3.0000000E+9 Console.WriteLine("{0}", b5); // 3000000000 Console.WriteLine("{0}", b6); // 3.00E+9 Console.WriteLine("{0}", b7); // 3000000000
> 下記の結果だと、Subtractを使用すると指数表記無しで、*だと指数表記なのも気になります。
指数表現を望まないのであれば、ToPlainString メソッドを使ってみてください。
> ・指数表記の値をToXXで変換するとエラーが発生するのですが、回避策などありますでしょか? > Console.WriteLine("{0}", (decimal)b3); // 3000000000 > Console.WriteLine("{0}", b3.ToDecimal()); // 例外が発生(Negative exponent)
これについては、キャストで事足りるかとは思ったのですが、 どうやら駄目そうですね。
まぁ、もともとは『3.4E+38』を変換するのが目的だったので、 そもそも decimal 化で良いのか、という懸念もありますが。
で、実装を見る限りは Hongliang さんが書かれているように、 単なる実装バグのようです。
原因については、端折って書くと No85853 で述べた 精度(あるいは有効桁数)の問題です。
今回の場合、b3.UnscaledValue は 300 なので、 仮数部だけ見れば、十分に decimal の範囲なのですが、 b3.Scale が -3 なので、decimal の指数部に収まらなかったという。
単に「3000000000」という数値を表すにしても、 decimal x1 = new Decimal(300000, 0, 0, false, 0); // x1 = 300000M; decimal x2 = new Decimal(3000000, 0, 0, false, 1); // x2 = 300000.0M; decimal x3 = new Decimal(30000000, 0, 0, false, 2);// x2 = 300000.00M; とは書けても、 decimal x4 = new Decimal(300, 0, 0, false, (byte)-3); とするわけにはいかないということで。
# 実際には、「BigInteger.ValueOf(10L).Pow(-3)」によるエラー |