VBScript で高速にビットシフト演算する (unibon)

2002年02月17日: 新規作成。
VBScript で高速にビットシフト演算をします。
以前に VBScript でビットシフト演算する を作成したのですが、今回はループ処理をなくして、より高速なサブルーチンにしました。
(ちなみに、これらのサブルーチンは VBScript で MD5 を実装する に必要だったので作りました。)

左シフト用は sl という Function で、右シフト用は sr という Function です。右シフトは、算術ではなく論理シフトであり、上位ビットには 0 が入ります。
いずれの Function も引数 x がシフトの対象となる値を指定し、引数 n にはシフトするビット数を指定します。
引数の範囲としては、引数 x は Long 型(すなわち &H80000000(= -2147483648) <= x <= &H7FFFFFFF(= 2147483647))の値を指定してください。引数 n は 0 <= n < 32 までです。

おまけとして桁あふれを無視する加算のルーチン(add)も作成しました。
こちらも引数 a および b は Long 型の値を受け付け、a + b の結果を Function の戻り値として Long 型で返します。

いずれも短いプログラムですがオーバフローを回避するために、いろいろと苦心しました。
add のほうは、なまじ Long 型でビット演算をやるよりも一時変数として Currency 型(CCur 関数) を使った方が短いし速かったのですが、あえて Long の範囲内での演算にこだわってみました。
Currency 型(CCur 関数)を使ったバージョンもとりあえず掲載します。これは addCur という Function であり、引数や戻り値は add と同様に Long 型です。

これらの Function は VBScript だけでなく VB(Visual Basic) でも動きます。


Function sl(ByVal x, ByVal n) ' 左シフト
    If n = 0 Then
        sl = x
    Else
        Dim k
        k = CLng(2 ^ (32 - n - 1))
        Dim d
        d = x And (k - 1)
        Dim c
        c = d * CLng(2 ^ n)
        If x And k Then
            c = c Or &H80000000
        End If
        sl = c
    End If
End Function

Function sr(ByVal x, ByVal n) ' 右シフト(算術(>>)ではなく論理(>>>)シフトに相当)
    If n = 0 Then
        sr = x
    Else
        Dim y
        y = x And &H7FFFFFFF
        Dim z
        If n = 32 - 1 Then
            z = 0
        Else
            z = y \ CLng(2 ^ n)
        End If
        If y <> x Then
            z = z Or CLng(2 ^ (32 - n - 1))
        End If
        sr = z
    End If
End Function

Function add(ByVal a, ByVal b) ' オーバフローを無視して 32 ビットの加算をおこなう。
    If a >= 0 And b <= 0 Then
        add = a + b
    ElseIf a <= 0 And b >= 0 Then
        add = a + b
    Else
        Dim x
        x = a And &H3FFFFFFF
        Dim y
        y = b And &H3FFFFFFF
        Dim z
        z = x + y
        Dim f
        f = 0
        If z And &H40000000 Then
            f = f + 1
        End If
        z = z And &H3FFFFFFF
        If a And &H40000000 Then
            f = f + 1
        End If
        If a And &H80000000 Then
            f = f + 2
        End If
        If b And &H40000000 Then
            f = f + 1
        End If
        If b And &H80000000 Then
            f = f + 2
        End If
        If f And 1 Then
            z = z Or &H40000000
        End If
        If f And 2 Then
            z = z Or &H80000000
        End If
        add = z
    End If
End Function

Function addCur(ByVal a, ByVal b) ' オーバフローを無視して 32 ビットの加算をおこなう。
    Dim c
    c = CCur(a) + CCur(b)
    If c > &H7FFFFFFF Then
        c = c - CCur(2 ^ 32)
    ElseIf c < &H80000000 Then
        c = c + CCur(2 ^ 32)
    End If
    addCur = CLng(c)
End Function

ASP の目次
ホーム
(このページ自身の絶対的な URL)