上へ 整数 → MegaLong 実数 → MegaLong 10進数 → MegaLong 文字列 → MegaLong 整数部分 小数部分 部分値 MegaLong → Long MegaLong → Double 文字列変換
| |
数値変換 |
整数 → MegaLong |
最終更新日:2006/11/29 改訂 |
●概要
整数とは、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 は、返す対象となるインスタンス
- 0 はZero とする。
- 符号を決定。絶対値 V(Long) とする。
- p = GetDecPower(V) で、10進指数を求める。(関数は下記)
10p ≦ V < 10p+1 → 指数は p とする
- e = p Mod 8 は、8桁区切りにしたときの端数。
n = (p \ 8) + 1 は、とりあえず必要な配列サイズ - 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
- 指数は、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
|