ホーム ] PC技術/システム技術 ] VB.NETプログラミング ] なるほどナレッジ ] インフォメーション ]

上へ
整数 → MegaLong
実数 → MegaLong
10進数 → MegaLong
文字列 → MegaLong
整数部分
小数部分
部分値
MegaLong → Long
MegaLong → Double
文字列変換

数値変換

10進数 → MegaLong

最終更新日:2006/11/29 改訂

●概要

 10進数とは、Decimal を言う。Decimal の場合、小数もあり、値範囲も大きいので処理は少し複雑になる。以前は、文字列にしてから処理を行っていたが、やはり遅いので、高速化を図った。

●方針

 状況により、以下の処理とする。

  • 小数がなく、絶対値がBase*Base 未満であれば、通常の整数処理を行う。
  • 小数があり、絶対値がBase*Base 未満であれば、通常の整数処理 + 小数処理とする。
  • 絶対値がBase*Base 以上の場合は、基数変換し、仮数部にて処理を行う。

●Decimal構造体

 Decimal の内部構造は、実は多倍長になっている。下図参照。仮数部をInteger(2) 配列で表し、符号、10進小数点位置 d などをInteger で持っている。合計16バイト。つまり、基数を232 とする多倍長なのである。浮動小数点ではなく、固定小数点の一種で、2進小数ではないので、完全な10進数値を保有できる。値は、(-296 〜 296) / 10d  (d = 0 〜 28) となる。ちなみに、基数が232 とビット幅一杯なので、配列は、UInteger でないといけない。多分、UIntegerの一般サポート以前にできた形式なので、便宜的にInteger としているのだろう。この内部構造は、

 Decimal.GetBits   (As Integer())

なる共有メソッドでInteger配列として取り出せる。

●方法

今回は、この配列を取り出して、直接処理を行う。

  1. 配列を取り出し、符号と小数(マスクし16ビットシフトダウン)USを獲得する。値を絶対値とする。
  2. p = Fix(Log10(V)) を算出し、10進指数を求める。
  3. US > 0 でかつ (p + US) < 16 であれば、事前正規化可能なので、V = V * 10US とする。(小数部の整数化)
  4. (p + US) < 16 でかつ V < Base * Base であれば、事前正規化で変換する。
  5. でなければ、以下のよう基数変換し、できたBase基準配列を正規化する。

    Dim UI() As Long
    Dim Lm As Long = 4294967296                     '232 Decimal配列の基数
    Dim sgn As MegaSign = MegaSign.Positive
    Dim DB() As Integer = Decimal.GetBits(V)

    ReDim UI(2)
    For i = 0 To 2 '逆順にしたU32 配列に変換
       Dim IV, L As Long
       IV = DB(i)
       If DB(i) < 0 Then
          L = Lm + DB(i)           '負数を符号なしに変換(UIntegerを使わない方法)
       Else
          L = CLng(DB(i))
       End If
       UI(2 - i) = L
    Next
    Dim PM(), pp, R As Integer
    pp = 0
    Do                                 '基数変換 (B32 To D8)
       CIDivU32(UI, Base, R)     'B32ベースの多倍長整数除算関数(下記)
       ReDim Preserve PM(pp)
       PM(pp) = R
       pp = pp + 1
       If IsU32Zero(UI) Then Exit Do    '被除数が0 で終了
    Loop
    Array.Reverse(PM)
    Me.Mant = PM.Clone
    NormalizeMe()

    Private Sub CIDivU32(ByRef U32() As Long, ByVal D As Integer, ByRef R As Integer)
       Dim i As Integer
       Dim Q(), W, CD As Long
       CD = 0
       ReDim Q(2)
       For i = 0 To 2
          W = CD * Lm + U32(i)
          Q(i) = W \ D
          CD = W Mod D
       Next
       U32 = Q.Clone                  '被除数配列に整数商を格納
       R = CD
    End Sub
     
  6. Exp = Exp - US とする。