【VBA】特定の範囲内の任意の整数をインクリメント、デクリメントして次の値を求める
条件
- 任意の3つの整数において、以下の条件を満たす事(負の値があっても可)
- 最小値 <= 現在値 <= 最大値
- 範囲の最大値をインクリメントした場合、範囲の最小値を返す事。
- 範囲の最小値をデクリメントした場合、範囲の最大値を返す事。
求める式
インクリメント、デクリメントというからには、普通に考えれば増減値は1なので、以下のようになる。
要素数 = 最大値 - 最小値 + 1 'インクリメントする場合 次の値 = ( ( 現在値 + 1 - 最小値 ) Mod 要素数 ) + 最小値 'デクリメントする場合 次の値 = ( ( 現在値 + ( 要素数 - 1 ) - 最小値 ) Mod 要素数 ) + 最小値
補足
インクリメントの場合
現在値に1を加算し、要素数の剰余を利用する。
範囲の最小値が0でない場合、最小値を0に補正して剰余を求めた後、補正した分を戻す。
デクリメントの場合
インクリメントでは、要素数に1を加算したが、デクリメントの場合は、
(要素数 - 1 )を加算し、同様に計算する。
増減値が2以上の場合、前述の式の1の部分を変えれば良い。
要素数 = 最大値 - 最小値 + 1 'インクリメントする場合 次の値 = ( ( 現在値 + 加算する値 - 最小値 ) Mod 要素数 ) + 最小値 'デクリメントする場合 次の値 = ( ( 現在値 + ( 要素数 - 減算する値 ) - 最小値 ) Mod 要素数 ) + 最小値
ただし、以下の条件を満たす必要がある。
加算する値 >= 0
減算する値 >= 0 かつ 減算する値 <= 要素数
コード
Private Const ERROR_INVALID_PARAMETER As Long = 87 Public Function incrementBetweenNM(ByVal lCurrentValue As Long, _ ByVal lMinValue As Long, _ ByVal lMaxValue As Long, _ Optional ByVal lOffsetValue As Long = 1) As Long Dim lElements As Long If lMinValue > lMaxValue Then Err.Raise ERROR_INVALID_PARAMETER ElseIf lMaxValue < lCurrentValue Then Err.Raise ERROR_INVALID_PARAMETER ElseIf lMinValue > lCurrentValue Then Err.Raise ERROR_INVALID_PARAMETER End If If lOffsetValue < 0 Then Err.Raise ERROR_INVALID_PARAMETER ElseIf lOffsetValue > lMaxValue - lMinValue + 1 Then Err.Raise ERROR_INVALID_PARAMETER End If lElements = lMaxValue - lMinValue + 1 incrementBetweenNM = ((lCurrentValue + lOffsetValue - lMinValue) Mod lElements) + lMinValue End Function Public Function decrementBetweenNM(ByVal lCurrentValue As Long, _ ByVal lMinValue As Long, _ ByVal lMaxValue As Long, _ Optional ByVal lOffsetValue As Long = 1) As Long Dim lElements As Long If lMinValue > lMaxValue Then Err.Raise ERROR_INVALID_PARAMETER ElseIf lMaxValue < lCurrentValue Then Err.Raise ERROR_INVALID_PARAMETER ElseIf lMinValue > lCurrentValue Then Err.Raise ERROR_INVALID_PARAMETER End If If lOffsetValue < 0 Then Err.Raise ERROR_INVALID_PARAMETER ElseIf lOffsetValue > lMaxValue - lMinValue + 1 Then Err.Raise ERROR_INVALID_PARAMETER End If lElements = lMaxValue - lMinValue + 1 decrementBetweenNM = ((lCurrentValue + (lElements - lOffsetValue) - lMinValue) Mod lElements) + lMinValue End Function
実行例
テストコード
Public Sub getNext() Dim l As Long Dim u As Long Dim i As Long l = -3 u = 2 Debug.Print "最小値:" & l Debug.Print "最大値:" & u Debug.Print "" Debug.Print "現在値", "次の値", "前の値" For i = l To u Debug.Print i, incrementBetweenNM(i, l, u), decrementBetweenNM(i, l, u) Next End Sub
実行結果
call getNext 最小値:-3 最大値:2 現在値 次の値 前の値 -3 -2 2 -2 -1 -3 -1 0 -2 0 1 -1 1 2 0 2 -3 1
おまけのテスト その1
call getNext 最小値:1 最大値:1 現在値 次の値 前の値 1 1 1
最大値 = 最小値 だと、次の値も前の値も、みんな同じ・・・
あたりまえか。
おまけのテスト その2
Debug.Print i, incrementBetweenNM(i, l, u, 2), decrementBetweenNM(i, l, u, 3)
として、加算、減算する値を変えてみると
call getNext 最小値:-3 最大値:2 現在値 次の値 前の値 -3 -1 0 -2 0 1 -1 1 2 0 2 -3 1 -3 -2 2 -2 -1