DOBON.NET DOBON.NETプログラミング掲示板過去ログ

VBScript にて Long 型の最大値以上の数でビット演算を行いたい

分類:[その他]

2011/02/06(Sun) 17:08:28 編集(投稿者)

言語:VBScript

^ はべき乗の演算子です。
(2 ^ 49) - 1 の数でビット演算 And、Or、Xor を行いたいのですが
Long 型の最大値 (2 ^ 31) - 1 を超える数で演算を行うとオーバーフローします。

CCur 関数で演算結果を Currency 型に変換するよう以下を試してみましたが
オーバーフローしました。

Dim i
i = CCur((2 ^ 49) - 1) And 1
i = CCur(CCur((2 ^ 49) - 1) And 1)

Currency 型 (2 ^ 49) - 1 の数で And、Or、Xor のビット演算を行う方法を教えてください。
■No28108に返信(もりおさんの記事)
> (2 ^ 49) - 1 の数でビット演算 And、Or、Xor を行いたいのですが
ビット演算は、整数型にしか使えませんからね。

VB6 なら、整数型配列なユーザー定義型に LSet するという手も使えますが、
VBScript ではそういうわけにも行きませんし。

> CCur 関数で演算結果を Currency 型に変換するよう以下を試してみましたが
> オーバーフローしました。
Currency だと小数部の関係で、計算がややこしいことになってしまうかも?

確かに Currency は内部的には 8 バイト整数型で値を管理していますが、
データとしては 1 / 10000 された固定小数点数であり、メモリ上は
以下のような形式となっています。
 -116708809143653.4766 → &H1234567890ABCDEF
               +6.5536 → &H0000010000000000
               +1.0000 → &H1027000000000000
               +0.0001 → &H0100000000000000 整数最小精度
                0.0000 → &H0000000000000000 ゼロ
               -0.0001 → &HFFFFFFFFFFFFFFFF 負数最小精度
 +922337203685477.5806 → &HFEFFFFFFFFFFFF7F @リテラルが使える最大値
 +922337203685477.5807 → &HFFFFFFFFFFFFFF7F 最大値
 -915131444281684.7873 → &HFFFFFFFFFFFFFF80
 +915131444281684.7872 → &H000000000000007F
 -922337203685477.5808 → &H0000000000000080 最小値
 -922337203685477.5807 → &H0100000000000080 @リテラルが使える最小値


> Currency 型 (2 ^ 49) - 1 の数で And、Or、Xor のビット演算を行う方法を教えてください。
Hex は使えないですしね…。
 (2 ^ 49) - 1            → 562949953421311 (Double型)
 CCur("&H1FFFFFFFFFFFF") → 562949953421311 (Currency型)
 Hex(562949953421311)    → オーバーフロー


とりあえず、ビット演算可能な整数単位に千切って処理してみては如何でしょう。

562949953421311 を Array(&H0001, &HFFFF, &HFFFF, &HFFFF) に
自前で変換すれば、ビット演算も可能になるかと思います。
■No28109に返信(魔界の仮面弁士さんの記事)
> 562949953421311 を Array(&H0001, &HFFFF, &HFFFF, &HFFFF) に
> 自前で変換すれば、ビット演算も可能になるかと思います。

変換してみました。

a = CCur( (2 ^ 49) - 1 )                '0001 FFFF FFFF FFFF (Currency: 562949953421311)

U4 = Fix(a / CCur("&H100000000"))       '0001 FFFF (Double: 131071)
L4 = a - U4 * CCur("&H100000000")       'FFFF FFFF (Currency: 4294967295)

UU2 = CLng(Fix(U4 / CCur("&H10000")))   '0001 (Long: 1)
UL2 = CLng(U4 - UU2 * CCur("&H10000"))  'FFFF (Long: 65535)
LU2 = CLng(Fix(L4 / CCur("&H10000")))   'FFFF (Long: 65535)
LL2 = CLng(L4 - LU2 * CCur("&H10000"))  'FFFF (Long: 65535)


>  +922337203685477.5806 → &HFEFFFFFFFFFFFF7F @リテラルが使える最大値
>  -922337203685477.5807 → &H0100000000000080 @リテラルが使える最小値
済みません、VBScript なので型宣言文字 @ は使えないですね…。
上記は、VBA や VB6 における下記の動作について述べた物です。
 V = CCur("-922337203685477.5807")   'OK
 V = CCur("-922337203685477.5808")   'OK
 V = -922337203685477.5807@          'OK
 V = -922337203685477.5808@          'NG
■No28113に返信(魔界の仮面弁士さんの記事)
ご返信ありがとうございます。

> メモリ上は以下のような形式となっています。

ぐ...ぐぇ。私は思い違いをしていたかもしれません。
0 から (2 ^ 49) - 1 までの間は桁数の多い Long 型みたいなものと想像していました。
演算がメモリ上の形式に依存するようなこともあるのですかね。要確認ですね。

> CCur("&H1FFFFFFFFFFFF") → 562949953421311 (Currency型)

以下の記述でいずれも構文エラーとなったので16進表記から Currency 型への変換は
できないものと思っていました。
文字列として評価するとよいわけですか。

CCur(&H1FFFFFFFFFFFF)
CCur(&H1FFFFFFFFFFFF&)
CCur(&H1FFFFFFFFFFFF@)

> とりあえず、ビット演算可能な整数単位に千切って処理してみては如何でしょう。

そんな手がありましたか。
\、Mod の再定義もかねて実装してみます。

> U4 = Fix(a / CCur("&H100000000"))       '0001 FFFF (Double: 131071)
> L4 = a - U4 * CCur("&H100000000")       'FFFF FFFF (Currency: 4294967295)

\ が Long 型までしか計算できないのは知っていたのですが、
Mod もなのですね。
■No28114に返信(もりおさんの記事)
> 演算がメモリ上の形式に依存するようなこともあるのですかね。要確認ですね。
VBScript で演算する分には問題無いと思います。
影響があるのは、VBA などにおいて生バイナリのまま扱う場合ぐらいでしょうか。
# Currency をバイナリファイルに出力し、それを 2 つの Long として読む場合や
# 先述した「ユーザー定義型への強制的LSet」など。


>>CCur("&H1FFFFFFFFFFFF") → 562949953421311 (Currency型)
> 文字列として評価するとよいわけですか。
文字列だけでは無く、数値でも評価できますよ。
CCur((2^49)-1) のように。


> CCur(&H1FFFFFFFFFFFF)
これは CCur が駄目なのでは無く、&H1FFFFFFFFFFFF が駄目という事ですね。

16進リテラルの範囲は &HFFFFFFFF までですし、
 8進リテラルの範囲は &37777777777 までです。


ちなみに 10進リテラルの場合、小数点が無い場合は
            〜-2147483647 …  Double 扱い
 -2147483647〜     -32768 …    Long 扱い
      -32767〜      32767 … Integer 扱い
       32768〜 2147483647 …    Long 扱い
  2147483648〜            …  Double 扱い
として解釈されます。
(Byte、Single、Currency が必要な場合は、明示的な変換が必要です)

上記は、Integer や Long の有効範囲とは異なる点に注意してください。
Integer の最低値は      -32768 ですが、TypeName(-32768)      は Long   です。
   Long の最低値は -2147483648 ですが、TypeName(-2147483648) は Double です。


> \ が Long 型までしか計算できないのは知っていたのですが、
> Mod もなのですね。
ちなみに VB.NET の Mod 演算子は、整数同士だけではなく
小数同士の剰余演算にも対応するようになっています。蛇足ですが。
■No28114に返信(もりおさんの記事)
>>メモリ上は以下のような形式となっています。
済みません! 前回の回答ではメモリ順を誤って書いてしまいました。m(_ _;)m

バイトの並びが「CD,AB,78,56」なら、表記上は「&HCDAB7856」ではなく
「&H5678ABCD」と記載しなければならないんですよね…。リトルエンディアンなので。
(逆に言えば、&H5678ABCD& のバイナリ表現が「CD,AB,78,56」であるということ)


なので、先の
>> +922337203685477.5807 → &HFFFFFFFFFFFFFF7F 最大値
>> -922337203685477.5807 → &H0100000000000080 @リテラルが使える最小値
という記述は間違いで、それぞれ
   +922337203685477.5807 → FF,FF,FF,FF,FF,FF,FF,7F (&H7FFFFFFFFFFFFFFF) 最大値
   -922337203685477.5807 → 01,00,00,00,00,00,00,80 (&H8000000000000001) @リテラルが使える最小値
のように読み替えてくださいませ。
ただし実際には、VBScript や VB6 で &H0123456789ABCDEF という表記は使えません(VB.NET では使えますが)。

# VBA7 はどうなのだろう? LongLong型が出来たので、64bit表記も使えるようになったのかな?



> ぐ...ぐぇ。私は思い違いをしていたかもしれません。
> 0 から (2 ^ 49) - 1 までの間は桁数の多い Long 型みたいなものと想像していました。
その認識で概ね正しいですが、小数部も含めた上で管理されています。


Long       1234567890    ->   D2,02,96,49             (&H499602D2)
Currency  123456.7890    ->   D2,02,96,49,00,00,00,00 (&H00000000499602D2)
Currency   1234567890    ->   20,2B,CE,73,3A,0B,00,00 (&H00000B3A73CEBD20)

Long       1450748877    ->   CD,AB,78,56             (&H5678ABCD)
Currency  145074.8877    ->   CD,AB,78,56,00,00,00,00 (&H000000005678ABCD)
Currency   1450748877    ->   D0,F7,B6,C9,31,0D,00,00 (&H00000D31C9B6F7D0)

Long        -19088744    ->   98,BA,DC,FE             (&HFEDCBA98)
Currency   -1908.8744    ->   98,BA,DC,FE,FF,FF,FF,FF (&HFFFFFFFFFEDCBA98)
Currency    -19088744    ->   60,F1,38,8E,FB,FF,FF,FF (&HFFFFFFFB8E38F160)
■No28117に返信(魔界の仮面弁士さんの記事)
全力で実装してみました、変なところがありましたらお教えいただけるとありがたいです。

Option Explicit

Call Main()

Sub Main()
  Dim number1 : number1 = (2 ^ 49) - 1
  Dim number2 : number2 = 1
  Dim array1 : array1 = NumberToArray(number1)
  Dim array2 : array2 = NumberToArray(number2)
  Dim resultArray : resultArray = ArrayAnd(array1, array2)
  Dim resultNumber : resultNumber = ArrayToNumber(resultArray)
  Call ArrayWriteLine(array1)
  Call ArrayWriteLine(array2)
  Call ArrayWriteLine(resultArray)
  Call WriteLine(resultNumber)
End Sub

Function ArrayWriteLine(array1)
  Dim s : s = ""
  Dim i : For Each i In array1
    s = s & HexPad(i, 4)
  Next
  Call WriteLine(s)
End Function

Function ArrayAnd(array1, array2)
  Dim result : ReDim result(3)
  Dim i : For i = 0 To 3
    result(i) = array1(i) And array2(i)
  Next
  ArrayAnd = result
End Function

Function NumberToArray(number)
  Dim cut4 : cut4 = CCur(2 ^ 32)
  Dim u4 : u4 = CurIntDiv(number, cut4)
  Dim l4 : l4 = CurMod(number, cut4)
  Dim cut2 : cut2 = CCur(2 ^ 16)
  Dim uu2 : uu2 = CurIntDiv(u4, cut2)
  Dim ul2 : ul2 = CurMod(u4, cut2)
  Dim lu2 : lu2 = CurIntDiv(l4, cut2)
  Dim ll2 : ll2 = CurMod(l4, cut2)
  NumberToArray = Array(uu2, ul2, lu2, ll2)
End Function

Function ArrayToNumber(array1)
  Dim sum : sum = CCur(0)
  dim base : base = 1
  Dim i : For Each i In array1
    sum = sum + (base * i)
    base = base * base
  Next
  ArrayToNumber = sum
End Function

Function HexPad(number, length)
  HexPad = PadLeft(Hex(number), length, "0") 
End Function

Function PadLeft(text, length, char)
  Dim diff : diff = length - Len(text)
  If (diff < 1) Then
    PadLeft = text
  Else
    PadLeft = String(diff, char) & text
  End If
End Function

Function CurIntDiv(number1, number2)
  CurIntDiv = Fix(number1 / number2)
End Function

Function CurMod(number1, number2)
  CurMod = number1 - (Fix(number1 / number2) * number2)
End Function

Sub WriteLine(s)
  Call WScript.StdOut.WriteLine(s)
End Sub

ArrayToNumber は最初16進文字列を評価する作戦で実装してみました。
しかし、16進文字列 hexString が &HFFFFFFFF の場合、期待する値は 4294967295 なの
ですが、-1 となります。回避方法がありましたらお教えいただけないでしょうか。

Function ArrayToNumber(array1)
  Dim hexString : hexString = "&H"
  Dim i : For Each i In array1
    hexString = hexString & HexPad(i, 4)
  Next
  ArrayToNumber = CCur(hexString)
End Function

> # Currency をバイナリファイルに出力し、それを 2 つの Long として読む場合や
> # 先述した「ユーザー定義型への強制的LSet」など。

LSet を使ったことがなかったので調べてみました。
LSet はメモリの内容を丸っとコピーして異なるデータ型への変換を行う
ステートメントですか。

> Integer の最低値は      -32768 ですが、TypeName(-32768)      は Long   です。
>    Long の最低値は -2147483648 ですが、TypeName(-2147483648) は Double です。

データ型で扱える範囲と、データ型を決定する閾値との間にずれがあるわけですか。
知りませんでした。

> Long       1234567890    ->   D2,02,96,49             (&H499602D2)
> Currency  123456.7890    ->   D2,02,96,49,00,00,00,00 (&H00000000499602D2)
> Currency   1234567890    ->   20,2B,CE,73,3A,0B,00,00 (&H00000B3A73CEBD20)

前回お教えいただきました 1 / 10000 された固定小数点数の意味をようやく理解
することができました。
&H00000B3A73CEBD20 ÷ 10000 = &H499602D2
メモリ上はこういうことになるわけですね。
■No28118に返信(もりおさんの記事)
> しかし、16進文字列 hexString が &HFFFFFFFF の場合、
> 期待する値は 4294967295 なのですが、-1 となります。

VBScript において unsigned な整数型は Byte 型だけです。
それ以外の整数型では、最上位ビットは符号を意味します。

もし仮に、VBScript で signed / unsigned を自由に使い分けられるなら、
 [32bit整数型]
  &HFFFFFFFF は 4294967295 または -1
  &H80000000 は 2147483648 または -2147483648
  &H7FFFFFFF は 2147483647
  &H00000000 は 0
 [16bit整数型]
  &HFFFF は 65535 または -1
  &H8000 は 32768 または -32768
  &H7FFF は 32767
  &H0000 は 0
となるのでしょうけれど、残念ながら VBScript では UInteger 型を扱う事が
できないので、&H80000000〜&HFFFFFFFF は負数として扱われることになります。


だからこそ、先の私の例では
> 562949953421311 を Array(&H0001, &HFFFF, &HFFFF, &HFFFF) に
のように、0000〜FFFF という単位ごとに分割しているのですけれどね。

CInt("&HFFFF") は signed 16bit integer なので「-1」ですが、
CLng("&HFFFF") は signed 32bit integer なので「65535」です。

unsigned が使えない以上、ビット演算するにはこの方が都合が良いかな、と。



> 回避方法がありましたらお教えいただけないでしょうか。
Long 値として扱いたいなら、そもそも 4294967295 は範囲外です。
Currency で良いなら、&HFFFF と &HFFFF に分けて算出すれば良いかと。

v = CCur("&HFFFF") * CCur("&H10000") + CCur("&HFFFF")



ところで、『Chr関数』はご存知ですか?
指定した文字コードに対応する文字を返す関数です。

日本語環境下では、Chr 関数には &H0000〜&HFFFF の範囲の値を渡せるのですが、
この場合「最上位ビットを符号として扱うかどうか」という問題があるため、
この関数は 0〜65535 でも -32768〜32767 でもなく、「-32768〜 65535」という
範囲の値をとるようにできています。
■No28122に返信(魔界の仮面弁士さんの記事)
> VBScript において unsigned な整数型は Byte 型だけです。
> それ以外の整数型では、最上位ビットは符号を意味します。

CCur 関数を呼ぶことで最上位ビットは Currency のものになるのかと
思っていたのですが、違うみたいですね。

> だからこそ、先の私の例では
> > 562949953421311 を Array(&H0001, &HFFFF, &HFFFF, &HFFFF) に
> のように、0000〜FFFF という単位ごとに分割しているのですけれどね。

あう、分割単位にもつながっているのですか。

> ところで、『Chr関数』はご存知ですか?

はい、知っています。
ASCII の範囲 0 - 127 の変換を行うものと思っていました。全然違っていました。


お教えいただいた情報をもとに考えを整理してみたいと思います。
取り急ぎお返事申し上げます。
■No28127に返信(もりおさんの記事)

ビット演算ということは49ビットの整数を特に考えなくてもよい
気がするのですがどうでしょう?16ビット毎にわけた情報だけで
考えれば変換しなくて済みそうな気がします。
■No28140に返信(shuさんの記事)
> ビット演算ということは49ビットの整数を特に考えなくてもよい
> 気がするのですがどうでしょう?16ビット毎にわけた情報だけで
> 考えれば変換しなくて済みそうな気がします。

ですね。
49bit 以下であれば、「Currency の整数部」だけで収まる範囲の数になるので、
先の方法で 16bit 単位に分割してやることで、And、Or、XOr 演算を
行う事ができるかと思います。50bit 以上だと有効桁数が不足しますが。

 49bit 整数 の上限 →  562949953421311
 50bit 整数 の上限 → 1125899906842623
Currency整数部上限 →  922337203685477


Dim mask, n
mask = Array(&H0002&, &H0000&, &H0000&, &H0000&)

Dim a, b
a    = Array(&H0001&, &HFFFF&, &HFFFF&, &HFFFF&)
b    = Array(&H0000&, &H1000&, &H0000&, &H0000&)

'x = (a And mask)
Dim x(3)
For n = 0 To 3
  x(n) = a(n) And mask(n)
Next

'y = (b Or mask)
Dim y(3)
For n = 0 To 3
  y(n) = b(n) Or mask(n)
Next

'a, b, x, y を Currency に変換
Dim ret1, ret2, ret3, ret4
ret1 = CCur(0)
ret2 = CCur(0)
ret3 = CCur(0)
ret4 = CCur(0)
For n = 0 To 3
  ret1 = ret1 * CCur("&H10000") + CCur(a(n))
  ret2 = ret2 * CCur("&H10000") + CCur(b(n))
  ret3 = ret3 * CCur("&H10000") + CCur(x(n))
  ret4 = ret4 * CCur("&H10000") + CCur(y(n))
Next
MsgBox FormatNumber(ret1, 0, True, False, True)  ' "562,949,953,421,311"
MsgBox FormatNumber(ret2, 0, True, False, True)  '  "17,592,186,044,416"
MsgBox FormatNumber(ret3, 0, True, False, True)  '                   "0"
MsgBox FormatNumber(ret4, 0, True, False, True)  ' "580,542,139,465,728"


'a, b, x, y を 16進数表現に変換
Dim hex1, hex2, hex3, hex4
hex1 = ""
hex2 = ""
hex3 = ""
hex4 = ""
For n = 0 To 3
  hex1 = hex1 & Right("0000" & Hex(a(n)), 4)
  hex2 = hex2 & Right("0000" & Hex(b(n)), 4)
  hex3 = hex3 & Right("0000" & Hex(x(n)), 4)
  hex4 = hex4 & Right("0000" & Hex(y(n)), 4)
Next
MsgBox hex1   ' "0001FFFFFFFFFFFF"
MsgBox hex2   ' "0000100000000000"
MsgBox hex3   ' "0000000000000000"
MsgBox hex4   ' "0002100000000000"



--- 以下、役に立たない情報 ---

VBScript や VB6 で扱える整数型(および、その Variant 型データ)は、
 1 バイト符号なし(Byte)
 2 バイト符号付き(Integer)
 4 バイト符号付き(Long)
の 3 種類だけですが、COM(ActiveX) の世界では、これ以外にも
64bit(8バイト)の整数や、4 バイト符号なし整数などを利用可能です。


たとえば、下記の DLL を VB2005〜2010 で作っておくと、

  'コンパイルオプションで、[COM 相互運用機能の登録]を有効にしておく
  Public Class IntConverter
    Public Function ToUI8(ByVal s As String) As ULong
      Return ULong.Parse(s)  'VT_UI8
    End Function
    Public Function ToI8(ByVal s As String) As Long
      Return Long.Parse(s)   'VT_I8
    End Function
  End Class

VBScript からは、それを
 Set obj = CreateObject("ClassLibrary1.IntConverter")
 a = obj.ToI8("562949953421311")
で呼び出して、64bit整数型の値を得ることができます。


ただし 64bit 整数型を持つ Variant が使えるのは XP 以降に限られており、
Windows 2000 や Windows ME およびそれ未満のバージョンでは使えません。

また、VBScript 側の対応としては、

・算術演算子、比較演算子、ビット演算子は利用できない。
・型変換関数は利用可能(CStr、CCur、CDbl 等)。
・VarType 関数は利用可能。
・TypeName 関数は利用できない。

という状態であり、サポートされていない機能を呼び出した場合には、
実行時エラー 458「VBScript でサポートされていないオートメーションが
変数で使用されています。」が発生します。

 MsgBox a                '○ (562949953421311と表示される)
 'b = a + 1              '×
 c = CStr(a)             '○
 d = CCur(a)             '○
 'If a = 0 Then          '×
 If CStr(a) = "0" Then   '○
 MsgBox VarType(a)       '○ (signed なら 20、unsigned は 21 が返される)
 'MsgBox TypeName(a)     '×
■No28142に返信(魔界の仮面弁士さんの記事)
まずは前回への返信です。

あっていますでしょうか。
CCur(16進文字列) によるデータ変換に関しまして
16進文字列のバイト数が8以下である場合、Integer、Long の評価が行われて
Currency へデータ型の変換が行われる。
16進文字列のバイト数が9以上である場合 Currency と評価される。
Long 型で表現できる最大数は 2147483647 で、
2147483648 から 4294967296 間は CCur(16進文字列) のみでは表現できない。

> 日本語環境下では、Chr 関数には &H0000〜&HFFFF の範囲の値を渡せるのですが、
> この場合「最上位ビットを符号として扱うかどうか」という問題があるため、
> この関数は 0〜65535 でも -32768〜32767 でもなく、「-32768〜 65535」という
> 範囲の値をとるようにできています。

FFFF:Integer -1     Long 65535
8000:Integer -32768 Long 32768
数値が異なってもバイト表現が同じであれば Chr 関数は同一の文字を返すわけですね。

「指定された ANSI コードまたはシフト JIS コードに対応する文字を返します。」
MSDN 、Chr 関数の説明文にある文章なのですが ANSI コードと ASCII コードの違いが
気になって仕方がなかったので調べてみました。
ANSI コードは別名 Windows-1252、ISO-8859-1 の文字を一部他のものに置き換えた
もので、文字の範囲は 0 - 255 でした。ASCII コードはその一部でした。

日本語環境の指定といいますか、Chr 関数が返す文字エンコードは SetLocale 関数で
指定することができて
SetLocale(1033) で ANSI コード。
SetLocale(1041) で Shift_JIS コードになりました。

■No28142に返信(魔界の仮面弁士さんの記事)
> ■No28140に返信(shuさんの記事)
>>ビット演算ということは49ビットの整数を特に考えなくてもよい
>>気がするのですがどうでしょう?16ビット毎にわけた情報だけで
>>考えれば変換しなくて済みそうな気がします。
> 
> ですね。

ちょ、ちょっとまってください、shu さんと魔界の仮面弁士さんは
なにからなにへの変換が必要ないとお考えなのか私にもお教えいただけない
でしょうか。
■No28143に返信(もりおさんの記事)
> CCur(16進文字列) によるデータ変換に関しまして
> 16進文字列のバイト数が8以下である場合、Integer、Long の評価が行われて
> Currency へデータ型の変換が行われる。

『16進文字列』というのは、下記の a の事であっていますか?

 a = "&H12345678"   '16進表記の文字列リテラル
 b = &H12345678     '16進表記の整数リテラル


> Integer、Long の評価が行われて
バイト数というのが、"&H" の後の文字数を指しているのなら、
 CCur("&H0")                          → 0
 CCur("&HFFFF")                       → 65535
 CCur("&H12345678")                   → 305419896
 CCur("&HFFFFFFFF")                   → -1
 CCur("&H7FFFFFFF")                   → 2147483647
 CCur("&H80000000")                   → -2147483648
 CCur("&H346DC5D638865")              → 922337203685477
 CCur("&H00000000000000000000000001") → 1
のように動作することになります。Integer として評価される事は無いかと。


> Long 型で表現できる最大数は 2147483647 で、
> 2147483648 から 4294967296 間は CCur(16進文字列) のみでは表現できない。
 2147483648 から 4294967295 ではありませんか?

4294967296 であれば CCur("&H100000000") で表現できます(要 WinXP 以降)。


> 数値が異なってもバイト表現が同じであれば Chr 関数は同一の文字を返すわけですね。
ですます。8FFF〜FFFF の範囲は、「-32768 〜 -1」でも 「32768〜65535」でも同じ結果です。

ちなみに、VBScript が直接サポートしていない、
 「符号付き 1 バイト整数型」
 「符号なし 2 バイト整数型」
 「符号なし 4 バイト整数型」
 「符号なし 8 バイト整数型」
 「符号付き 8 バイト整数型」
を渡した場合も、とにかく「-32768〜 65535」の範囲であれば受け付けるようです。


> SetLocale(1033) で ANSI コード。
> SetLocale(1041) で Shift_JIS コードになりました。
おぉ、そういえば GetLocale / SetLocale 関数なんてものがありましたね。
その存在自体を完全に忘れていました。ありがとうございます。


> ちょ、ちょっとまってください、shu さんと魔界の仮面弁士さんは
> なにからなにへの変換が必要ないとお考えなのか私にもお教えいただけない
> でしょうか。
不要なのは、私の脱線気味の蛇足情報でしょうかね。

もともとやりたいことは、
>> ビット演算 And、Or、Xor を行いたいのですが
だったのですよね。
そのために書かれたもりおさんの No28118 の処理と、私の No28142 の処理では
考え方は同じように思えますので、特にブレは無いと思いますよ。
■No28143に返信(もりおさんの記事)

> ちょ、ちょっとまってください、shu さんと魔界の仮面弁士さんは
> なにからなにへの変換が必要ないとお考えなのか私にもお教えいただけない
> でしょうか。

No28142の魔界の仮面弁士の内容にある

Dim mask, n
mask = Array(&H0002&, &H0000&, &H0000&, &H0000&)

Dim a, b
a = Array(&H0001&, &HFFFF&, &HFFFF&, &HFFFF&)
b = Array(&H0000&, &H1000&, &H0000&, &H0000&)

'x = (a And mask)
Dim x(3)
For n = 0 To 3
x(n) = a(n) And mask(n)
Next

'y = (b Or mask)
Dim y(3)
For n = 0 To 3
y(n) = b(n) Or mask(n)
Next


この部分だけでデータを扱えばいいのではないかなと思った次第です。
ビット演算を対象にする場合(2^49-1) AND 1を計算するというよりは
1111111111・・・1(2進) と 0000・・・・0001(2進)の計算をするという事の方が
近いのではないかなと思うのです。だから入力自体を配列にしてしまい、
結果も配列まででいいのかなと思ったんです。そうすればビット数が増えても
同じ考え方で計算が出来ます。
■No28145に返信(魔界の仮面弁士さんの記事)
> 『16進文字列』というのは、下記の a の事であっていますか?
>  a = "&H12345678"   '16進表記の文字列リテラル
>  b = &H12345678     '16進表記の整数リテラル
はい、あっています。

> > Integer、Long の評価が行われて
> バイト数というのが、"&H" の後の文字数を指しているのなら、
> のように動作することになります。Integer として評価される事は無いかと。
あ、そうですね、なるほど Integer と評価されることは確認できないですね。
Long と評価されるわけですか。

>> Long 型で表現できる最大数は 2147483647 で、
>> 2147483648 から 4294967296 間は CCur(16進文字列) のみでは表現できない。
> 2147483648 から 4294967295 ではありませんか?
> 4294967296 であれば CCur("&H100000000") で表現できます(要 WinXP 以降)。
4294967295 でした。4294967295 といいたかったのです。
間違いました。ありがとうございます。

> 不要なのは、私の脱線気味の蛇足情報でしょうかね。
知識がつながっていくので不要とは思いません。
勉強になります。

■No28146に返信(shuさんの記事)
> だから入力自体を配列にしてしまい、
> 結果も配列まででいいのかなと思ったんです。そうすればビット数が増えても
> 同じ考え方で計算が出来ます。

Currency から Array への変換と、Array から Currency への変換をなくして
(2 ^ 49) - 1 を最初から Array で扱うとよいということですか。
ビット演算を複数回行うような場合には変換にかかるコストも削減できるわけですね。


魔界の仮面弁士さん、shu さんおかげさまで 2 ^ 31 以上の数でビット演算を行うことができました。
付随する知識を得ることもできました。ありがとうございました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板