上へ 整数 → 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配列として取り出せる。
●方法
今回は、この配列を取り出して、直接処理を行う。
- 配列を取り出し、符号と小数(マスクし16ビットシフトダウン)USを獲得する。値を絶対値とする。
- p = Fix(Log10(V)) を算出し、10進指数を求める。
- US > 0 でかつ (p + US) < 16 であれば、事前正規化可能なので、V = V * 10US
とする。(小数部の整数化)
- (p + US) < 16 でかつ V < Base * Base であれば、事前正規化で変換する。
- でなければ、以下のよう基数変換し、できた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
- Exp = Exp - US とする。
|