C# と VB.NET の質問掲示板

わんくま同盟

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

■85971 / 5階層)  指数表記された文字列の数値変換方法について
□投稿者/ 魔界の仮面弁士 (1495回)-(2017/12/06(Wed) 13:31:14)
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)」によるエラー
編集キー/

前の記事(元になった記事) 次の記事(この記事の返信)
←Re[4]: 指数表記された文字列の数値変換方法について /たかじ 返信無し
 
上記関連ツリー

指数表記された文字列の数値変換方法について / たかじ (17/11/28(Tue) 17:28) #85832
Re[1]: 指数表記された文字列の数値変換方法について / WebSurfer (17/11/28(Tue) 18:07) #85833
Re[1]: 指数表記された文字列の数値変換方法について / 魔界の仮面弁士 (17/11/29(Wed) 09:42) #85853
  └ Re[2]: 指数表記された文字列の数値変換方法について / たかじ (17/11/30(Thu) 16:33) #85904 解決済み
    └ Re[3]: 指数表記された文字列の数値変換方法について / 魔界の仮面弁士 (17/12/01(Fri) 11:13) #85915 解決済み
      └ Re[4]: 指数表記された文字列の数値変換方法について / たかじ (17/12/06(Wed) 10:14) #85967
        ├ 指数表記された文字列の数値変換方法について / 魔界の仮面弁士 (17/12/06(Wed) 13:31) #85971 ←Now
        └ Re[5]: 指数表記された文字列の数値変換方法について / Hongliang (17/12/06(Wed) 11:59) #85970
          └ Re[6]: 指数表記された文字列の数値変換方法について / 魔界の仮面弁士 (17/12/06(Wed) 14:16) #85972
            └ Re[7]: 指数表記された文字列の数値変換方法について / たかじ (17/12/07(Thu) 19:00) #85999 解決済み

上記ツリーを一括表示 / 上記ツリーをトピック表示
 
上記の記事へ返信