ホーム ] 多倍長語 MegaLong ] 基数変換 ] 数値変換 ] 定数システム ] 演算時間予測システム ]

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

数値変換

整数 → MegaLong

最終更新日:2007/04/26 改訂

●概要

 整数とは、Byte、SByte、Short、UShort、Integer、UInteger、Long、ULong を言う。

●方針

 整数は絶対値の大きさによって処理が異なる。

  • 基数の2乗(1億X1億) 未満であれば、Long またはULong にて、直接処理を行う。この処理では、事前正規化を行い、高速化が図られている。Byte、SByte、Short、UShort、Integer、UInteger の場合は、無条件でこの処理となる。
  • 基数の2乗(1億X1億) 以上の場合は、1億進数の仮数部配列に変換(基数変換)し、正規化を行う。Long、ULong の場合に、この処理になる可能性がある。以前は、Decimal で行っていたが、遅いのでこの方式に変更した。

●方法

○Base*Base 未満の処理

 Me は、返す対象となるインスタンス

  1. 0 はZero とする。
  2. 符号を決定。絶対値 V(Long) とする。
  3. p = GetDecPower(V) で、10進指数を求める。(関数は下記)

    10p ≦ V < 10p+1 → 指数は p とする
     
  4. e = p Mod 8 は、8桁区切りにしたときの端数。
    n = (p \ 8) + 1 は、とりあえず必要な配列サイズ
  5. p の値に従って以下の変換を行う。

    NormT() As Integer = {10000000, 1000000, 100000, 10000, 1000, 100, 10, 1}

    V = V * NormT(e)           '正規化を前もって行うための係数
    Dim CU As Long = V
    For i = n - 1 To 0 Step -1
       Me.Mant(i) = CU Mod Base
       CU = CU \ Base
    Next
     
  6. 指数は、p +1 となる。後ろの不要な 0 を除去して終了。

正規化を前もって行う とは、数値の10進桁数を 8 の倍数にしておくことを言う。例えば、

12345 → 12345000 1000倍する、 123456789 → 1234567890000000 1千万倍する。

など。

 整数の10進指数を求める関数。従来、Fix(Log10(V)) としていたが、これだと、Double の精度の問題で、9999999999999999 は、1*1016 となり、指数が16 となってしまい不都合であった。以下のように、10進テーブルをバイナリサーチする。

Friend Function GetDecPower(ByVal V As Long) As Integer
    Dim p As Integer = Array.BinarySearch(DecPow, V)
   'DecPow 1,10,100,1000,・・・・なるテーブル
    Select Case p
        Case -1
            Return -1
        Case Is >= 0
            Return p                             '一致(殆どありえないが)
        Case Else
            Return (-1 Xor p) - 1            '不一致の場合、BinarySearch の仕様による
      End Select
End Function

○Base*Base 以上の処理

 この値では、事前正規化ができないので、仮数部配列の正規化処理が伴う。

・特別処理:Long で、Long.MinValue の場合は、符号反転するとOverflow するので、定数として持っているMegaLong を返す。

以下の処理となる。ULong の場合もほぼ同じ(符号処理が不要、演算はULong が異なる)。

Dim sgn As MegaSign = MegaSign.Positive
Dim Q, R As Long
ReDim Me.Mant(2)               '値範囲が分っているので配列サイズは 3 となる
If V < 0 Then
   V = -V
   sgn = MegaSign.Negative
End If
Q = V
R = Base
For i As Integer = 2 To 0 Step -1
   Me.Mant(i) = Q Mod R
   Q = Q \ R
Next
NormalizeMe()               '正規化(以下の関数)
Me.Sign = sgn

Private Sub NormalizeMe()
   Dim Ix, p, e, Z As Integer
   p = Me.Mant.Length
   Ix = GetTopDigit(Me.Mant(0))     '先頭要素の先頭桁位置
   e = (p - 1) * 8 + 8 - Ix
   Me.Exp = e
   NumUp(Me.Mant, Ix)        '仮数部全体を、Ix 分シフトアップ   
   RemoveEndZeroElement(Me.Mant)   '末尾の 0 要素を除去
   Z = Me.Mant.Length
   Ix = GetLastDigit(Me.Mant(Z - 1))  '末尾桁数を検査
   Me.Length = (Z - 1) * 8 + Ix + 1
End Sub