# Visual Basic > Visual Basic 6 and Earlier >  Help With Algorithm

## mms_

I need help with coding for an algorithm, two algorithms actually.

I have solutions that work, but as I have a penchant for doing things the most complicated way possible,
I am asking others to look at my solutions.

The first is to find the next *multiple of 16* for a given value
ie
if val = 39, the next highest multiple of 16 would be 48

This is *my* solution.


```
Option Explicit

Private Sub Command1_Click()

    Dim val As Long
    val = 39
    
    MsgBox NextMultiple16(val)

End Sub

Private Function NextMultiple16(val As Long) As Long
    
    Dim m As Long
    m = 0
    
    Do Until m >= val
        m = m + 16
    Loop
    
    NextMultiple16 = m
    
End Function
```

The other function I would need is similar but, find the next number in this sequence.
{2, 4, 8, 16, 32, 64, 128, 256, ...}      Is there a *formal name* for this sequence?
ie
if val = 39, the next highest number in sequence would be 64

This is *my* solution.


```
Option Explicit

Private Sub Command2_Click()

    Dim val As Long
    val = 39
    
    MsgBox NextNumberInSequence(val)

End Sub

Private Function NextNumberInSequence(val As Long) As Long
    
    Dim m As Long
    m = 0
    
    Dim x As Long
    x = 0
    
    Do Until m >= val
        x = x + 1
        m = 2 ^ x
    Loop
    
    NextNumberInSequence = m
    
End Function
```

----------


## baka

first one is easy (value \ 16 + 1) * 16
the other one I need to think a bit first

----------


## baka

well the second Im not sure, but u can make it a bit smaller.



```
Function NextNumberInSequence(Value As Long) As Long
    NextNumberInSequence = 1
    While Value >= NextNumberInSequence
        NextNumberInSequence = NextNumberInSequence * 2
    Wend
End Function
```

edit: hold on.  0&1 will not be the same result. but everything above that is the same.
edit:
wait here. theres something wrong with your code.
if u type 2048 it will give u the same, not 4096
adding >= will fix 1 at least. 0 will show 1

----------


## mms_

Thanks *baka*  :Smilie: 

Not sure what you mean by 


> hold on. 0&1 will not be the same result. but everything above that is the same.

----------


## baka

mms_ 
I forgot to add >= so 1 would show wrong number. but its fixed now.

comparing to yours, using value:
0 will result 1, while yours 0
1 will result 2, and so yours as well
2 will result 4, while yours 2

thats the difference.

----------


## wqweto

Try this:



```
Private Function NextMultiple16(ByVal val As Long) As Long
    NextMultiple16 = (val + 15) And Not 15
End Function
```

Works for negative numbers too.

Edit: You need clz instruction for the second one or at least _BitScanForward intrinsic in VC to become a one-liner (not in VB6).

Here is an iterative solution which iterates on val set bits i.e. for numbers with only 3 bits set in binary (rest are clear) it iterates exactly 3 times



```
Private Function NextPowerOf2(ByVal val As Long) As Long
    Do While val <> 0
        NextPowerOf2 = val
        val = val And (val - 1)
    Loop
    NextPowerOf2 = NextPowerOf2 * 2
End Function
```

Does *not* work for negative numbers though.

cheers,
</wqw>

----------


## mms_

Thanks again *baka*

Thanks *wqweto*
I cannot grasp the concept of your NextPowerOf2 function, but can see it works  :Smilie: 
Also, I now know the *formal name* of the sequence of numbers I described  :Smilie: 
Thanks again.

----------


## OptionBase1

The "loopless" mathematical solution for the next power of 2 given n is just:

2 ^ [log(n)/log(2)]

Where [n] denotes the "ceiling" or the nearest integer greater than n if n is not an exact integer, so [5.1] = 6, [5] = 5, [0.316] = 1, etc.

Edit:  that is assuming that an exact power of 2 should return itself, and not 2*itself.

----------


## mms_

*OptionBase1*
I must be doing something wrong or misunderstand you because result with that formula is always the input value.


```
Private Sub Command4_Click()

    Dim val As Long
    val = 39
    
    MsgBox 2 ^ (Log(val) / Log(2))

End Sub
```

----------


## Schmidt

> *OptionBase1*
> I must be doing something wrong or misunderstand you because result with that formula is always the input value.


What he meant, was more like this:


```
Function NextPow2(n) As Long
  If n Then NextPow2 = 2 ^ Int(Log(n) / Log(2) + 1 + 1E-22)
End Function
```

HTH

Olaf

----------


## mms_

OK thanks *Olaf*  :Smilie: 

2 questions arise 
What is + 1 + 1E-22 you added to end of formula?
What does If n Then do at beginning?

Edit
Actually 3  :Smilie: 
Why Int(...   )?
Will the result not always be a whole number?

----------


## wqweto

Int(X + 1) is like Ceil(X) i.e. rounds X upwards to an integer.

1E-22 is a nice const for an EPSILON in math i.e. a small value which you can add to/remove from a calculation if in need not to miss a boundary out of rounding errors. In this case probably "rounding" integer input to next integer i.e. 2->3 the way 2.1 goes to 3. 

cheers,
</wqw>

----------


## mms_

Thank you again

----------


## Schmidt

> Why Int(...   )?


To supply the Base 2 with "integer-arguments"

I usually play around in the Immediate-Window first (for stuff like that):
n=2.5: e = Log(n) / Log(2): ? e, Int(e), 2^e, 2^Int(e)




> What is + 1 + 1E-22 you added to end of formula?


To make the Int-Function behave more like "ceil" (wqweto explained that already)




> What does If n Then do at beginning?


It's an "Input-sanitation" attempt (to return a 0, when n=0 (throwing "invalid Argument" only for negative values).

If I'd have written:
If n > 0 Then ...

The behaviour would be the same, but now there'd be no Error raised in case of a negative n.

BTW, more "formally correct" (regarding the interval-borders) would probably be:


```
Function NextPow2(n) As Long
  If n Then NextPow2 = 2 ^ Int(Log(n) / Log(2) + 1 - 1E-22)
End Function
```

... which would - for an input of n=128 - give a result of 128  - and not 256 ...
but that would then give 2^0 = 1 for an input of 1 
(although you wanted to have 2 as a minimum-output-value).

Olaf

----------


## georgekar

For finding next multiple of 16. Works with AND at 64 bits.
? multiple16(cdec("132312312312312"))
? multiple16(cdec("-132312312312312"))
if current decimal point character is the point "."
? multiple16(cdec("132312312312312.23234"))

You can use a number without conversion to decimal. 
? multiple16(132312312312312)

The vartype is 20, it is a long long


Also if you want only the last 32 bits write this as last statement in the function
PutMem1 VarPtr(multiple16), vbLong



```
Private Declare Sub PutMem1 Lib "msvbvm60" (ByVal Addr As Long, ByVal NewVal As Byte)
Function multiple16(a)
    Dim p
    PutMem1 VarPtr(p), 20
    PutMem1 VarPtr(p) + 8, 16
    multiple16 = (-p And a) + p
End Function
```

----------


## georgekar

This is the final best solution for the two algorithms.
for 39 multiple return 64, for 64 return 128,   for -39 return -32, for -32 return -16

Updated, using the faster AND for loop in multiple.
Also for 0 return 2



```
Private Declare Sub PutMem1 Lib "msvbvm60" (ByVal Addr As Long, ByVal NewVal As Byte)
Function multiple16(a)
    Dim p
    PutMem1 VarPtr(p), 20
    PutMem1 VarPtr(p) + 8, 16
    multiple16 = (-p And a) + p
End Function
Function multiple(ByVal a)
    Dim p, sgn1 As Integer
    sgn1 = Sgn(a)
    PutMem1 VarPtr(p), 20
    PutMem1 VarPtr(p) + 8, 1
    p = -p
    a = a And p
    p = -p
    a = Abs(a)
    If sgn1 = 0 Then multiple = 2: Exit Function
    If sgn1 = -1 Then a = a - 1
    While a <> 0
         multiple = a
         a = a And (a - p)
    Wend
    If sgn1 = 1 Then
        multiple = multiple * 2
    Else
        multiple = -multiple
    End If
End Function
```

----------


## georgekar

This is wqweto algorithm fixed for negative values too


```
Function NextPowerOf2(ByVal val As Long) As Long
    Dim sg1 As Integer
    sg1 = Sgn(val)
    val = Abs(val)
    If sg1 < 0 Then val = val - 1
    Do While val <> 0
        NextPowerOf2 = val
        val = val And (val - 1)
    Loop
    If sg1 = 1 Then
        NextPowerOf2 = NextPowerOf2 * 2
    Else
        NextPowerOf2 = -NextPowerOf2
    End If
End Function
```

----------


## georgekar

For Long Long utilities
The a=a and p  is an int() function to long long, because p is a long long, so the variable a change to long long or raise error.

? hex64$(int64("&HFFFFFFFFFFFFF123"))
FFFFFFFFFFFFF123
? hex64$(int64(1121232133123232321))
0F8F6AAF3D905280

******I change the code so now when compiled (Windows 10) run as expected**************


****** I found a problem with Currency type and the And operator *****
So I fix it too.




```
Private Declare Sub PutMem1 Lib "msvbvm60" (ByVal Addr As Long, ByVal NewVal As Byte)
Private Declare Sub GetMem4 Lib "msvbvm60" (ByVal Addr As Long, retval As Long)


Function HighLong(ByVal a)
    Dim p, p1
    PutMem1 VarPtr(p), 20
    p1 = p
    PutMem1 VarPtr(p) + 8, 1
    a = -p And a
    PutMem1 VarPtr(p1) + 12, 1
    HighLong = a \ p1
    PutMem1 VarPtr(HighLong), vbLong
End Function
Function LowLong(ByVal a)
    Dim p, p1
    PutMem1 VarPtr(p), 20
    PutMem1 VarPtr(p) + 8, 1
    LowLong = a And -p
    PutMem1 VarPtr(LowLong), vbLong
End Function
Function cUlng(ByVal a As Currency) As Long
    On Error GoTo cu1
    Dim ret As Long
    a = Abs(a)
    a = a / 10000@
    GetMem4 VarPtr(a), ret
    cUlng = ret
    Exit Function
cu1:
cUlng = 0
End Function
Function Hex64$(ByVal a)
    Dim p, p1, sg As Integer
    If VarType(a) = vbCurrency Then a = cUlng(a)
    sg = Sgn(a)
    PutMem1 VarPtr(p), 20
    p1 = p:
    PutMem1 VarPtr(p) + 8, 1
    p = a And -p
    PutMem1 VarPtr(p1) + 12, 1
    p1 = p \ p1
    PutMem1 VarPtr(p1), vbLong
    PutMem1 VarPtr(p), vbLong
    If p1 = 0 And sg = -1 Then
        Hex64$ = "FFFFFFFF" + Right$("0000000" + Hex$(p), 8)
    Else
        Hex64$ = Right$("0000000" + Hex$(p1), 8) + Right$("0000000" + Hex$(p), 8)
    End If
End Function
Function Int64(ByVal a)
    Dim p
    If VarType(a) = vbCurrency Then
        a = CDec(a)
    End If
    PutMem1 VarPtr(p), 20
    PutMem1 VarPtr(p) + 8, 1
    Int64 = -p And a
End Function
```

----------

