ページ 1 / 1
64bit変数の計算結果がおかしい
Posted: 2006年12月01日(金) 13:34
by OverTaker
64bit変数において、次のような計算をすると、なぜか10^16あたりから正しく計算できなくなってしまいます。本来valueには10^16-1が入りますが、なぜかvalueに10^16が入ってしまいます。
ActiveBasic5.0で確認しました。
コード: 全て選択
Dim value As Int64
Dim i As Long
For i = 0 To 18
value = 10^i-1
debug
Next
Posted: 2006年12月01日(金) 16:59
by イグトランス
^演算子の実体は,basic/function.sbpにあるpow関数ではないでしょうか?
そうだとすれば,Double型で演算されて情報落ちになっているのだと思います。
Posted: 2006年12月02日(土) 00:00
by イグトランス
試しにOLEオートメーションのVARIANT型(内部形式:Decimal(十進小数)型)に変換し,VARIANT型の演算関数で行わせたところ正しい結果にさせることができました。
ただし,これはもはや64ビット演算ではありません。
[ここをクリックすると内容が表示されます] [ここをクリックすると非表示にします]コード: 全て選択
Class VARIANT
Public
vt As Word
wReserved1 As Word
wReserved2 As Word
wReserved3 As Word
llVal As Int64
Function bstrVal() As BSTR
Return GetDWord(VarPtr(llVal))
End Function
End Class
TypeDef VARTYPE = Word
Declare Function VarDiv Lib "oleaut32.dll" (ByRef lhs As VARIANT, ByRef rhs As VARIANT, ByRef result As VARIANT) As HRESULT
Declare Function VarCat Lib "oleaut32.dll" (ByRef lhs As VARIANT, ByRef rhs As VARIANT, ByRef result As VARIANT) As HRESULT
Declare Function VarInt Lib "oleaut32.dll" (ByRef in As VARIANT, ByRef result As VARIANT) As HRESULT
Declare Function VariantChangeType Lib "oleaut32.dll" (ByRef vargDest As VARIANT, ByRef varSrc As VARIANT, Flags As Word, vt As VARTYPE) As HRESULT
Declare Function VariantClear Lib "oleaut32.dll" (ByRef varg As VARIANT) As HRESULT
Declare Function MessageBoxW Lib "user32" (hWnd As HWND, pText As *WCHAR, pCaption As *WCHAR, uType As DWord) As Long
Declare Function wsprintfW CDECL Lib "user32" (pText As *WCHAR, pFormat As *WCHAR, ...) As Long
Const VT_EMPTY = 0
Const VT_BSTR = 8
Const VT_I8 = 20
Const VT_DECIMAL = 14
Dim n As VARIANT, d As VARIANT, result As VARIANT, empty As VARIANT, tmp As VARIANT
n.vt = VT_I8
n.llVal = 10 ^ 18 - 1
d.vt = VT_I8
d.llVal = 10
result.vt = VT_EMPTY
VariantChangeType(n, n, 0, VT_DECIMAL) ' n = CDec(n) CDecはVBの関数
VariantChangeType(d, d, 0, VT_DECIMAL) ' d = CDec(d)
Dim hr As HRESULT
hr = VarDiv(n, d, result) ' result = n / d
empty.vt = VT_EMPTY
tmp.vt = VT_EMPTY
VariantChangeType(n, n, 0, VT_BSTR) 'n = CStr(n) ABではn = Str$(n)に近い
VariantChangeType(d, d, 0, VT_BSTR)
VarInt(result, result) ' result = Int(result) 'ABのIntと同じ意味
VariantChangeType(result, result, 0, VT_BSTR)
Dim buf[1024] As WCHAR
Dim format[1024] As WCHAR, i As Long, p As *Byte, len As Long
p = "%s / %s = %s"
len = lstrlen(p)
For i = 0 To len
format = p ' ワイド文字へ変換
Next
wsprintfW(buf, format, n.bstrVal, d.bstrVal, result.bstrVal)
MessageBoxW(0, buf, 0, MB_OK)
VariantClear(n)
VariantClear(d)
VariantClear(result)
End
VARIANT型はメンバ変数vtに現在保持しているデータ型を格納し,llValの部分(実際には共用体)に実際のデータを格納すると言う形式です。
また十進型はVBA 6のリファレンスで次のように説明されている型です。
10 進型 (Decimal)
10 の累乗の指数によって算出される、10 進数を格納するデータ型。小数点以下の桁数が 0 の場合 (小数部分を持たない場合)、絶対値の最大値は 79,228,162,514,264,337,593,543,950,335 です。小数点以下 28 桁の場合、絶対値の最大値は 7.9228162514264337593543950335 です。10 進型 (Decimal) で表される絶対値の最小値は、0 を除いた場合、0.0000000000000000000000000001 です。
Posted: 2006年12月02日(土) 00:09
by OverTaker
わざわざコードまでありがとうございます。
これを使うかはまだわからないですが、参考にさせていただきます。こちらでもいい方法を模索したいと思います。
Posted: 2006年12月07日(木) 23:32
by イグトランス
今更気付いたのですが,これは単にキャストすれば良かっただけのような気がします。
コード: 全て選択
Dim value As Int64
Dim i As Long
For i = 0 To 18
value = (10 ^ i) As Int64 - 1
debug
Next