How to apply bitwise formula to a range using VBA - vba

I am looking for a way to apply a bitwise AND on a value in excel and apply it on range. Here is a picture to illustrate :
I want to apply a bitwise AND on the Column "Status" with a fixed value, lets say (1001b).
If Status & 1001b = 1001b, then report the "Value" field in "Output". Else, put 0.
Both Excel and VBA can be used, but as the table can be huge, the solution may not use loops (Too slow, time efficient solution would be great). I am using excel 2010, and therefore the excel BITAND function is not available for me (only available since Excel 2013 version)
I search on SO and internet and didn't find a correct approach to a similar problem.
I try to optimize my initial solution which use recursivity, to be more time efficient, here is what I have done :
For cptDonnee_s32 = 0 To JeuDonnee_rs.RecordCount - 2 ' Loop through all my data
If (Value And 8) = 8) And (Value And 1) = 1) Then ' Compare bitfields one by one
Output = Value ' Replace output by value here
Else
Output = 0 ' put 0 in output there
End If
next

You could use a simple UDF:
Function BitAnd(dIn As Double, lMatch As Long) As Boolean
BitAnd = (dIn And lMatch) = lMatch
End Function
and enter:
=if(BitAnd(K2,9),L2,0)
and copy down.

Related

Excel Summing over Rows with for loop - Type mismatch error

so I am currently working on an Excel sheet where I have to calculate confidence intervals. Long story short, I think the only way I can do this automatically, is to write vba code. The first step would be to calculate the average of the cells in a column for several columns in the sheet. What I did:
Dim temp As Double
temp = 0
Dim it_row As Long
for it_row = 1 to 100
if IsBlank(Sheet.Cells(it_row,it_col)) then
temp = temp + 0
else
temp = temp + Sheet.Cells(it_row,it_col).Value
end if
next it_row
Dim Average As Double
Average = temp/100
'writing average in another cell
This code does not work, as the compiler returns Type missmatch, error code 13
in the line
temp = temp + Sheet.Cells(it_row,it_col).Value
I tried to do a CDouble(Sheet.Cells(it_row,it_col).Value) but that did not work.
Any help is appreciated, as I am quite desperate because googling did not really help me.
I should mention that I do have to use vba and this code because this is part of a bigger automated process and my supervisor said I must use vba for automation in the next step.
The Average and Sum Excel Functions ignore text, boolean, and empty values:
Average = Application.Average(Sheet.Cells(1, it_col).Resize(100))
Check
Sheet.Cells(it_row,it_col).Value
...with
if isnumeric(Sheet.Cells(it_row,it_col).Value)
...before adding it to a double type value. If that check fails, then you can chose to skip it or treat it as sth. else.
I would've added this as a comment, but I don't have enough rep. to add comments.

Excel VBA: Copy the Data up to the last column that has value

The spreadsheet has multiple values in a cell.
What I'm trying to do is get that value found in a cell and paste it to another sheet and copy the other fields(columns) that belong to that value. How do I set the range in order copy the other fields(columns) up to the last column that has value? Thanks in advance.
For iRowGetProdCode = 0 To UBound(sSplitProdCode)
Sheets("Output").Cells(iRowCountOutput, 1).Value = sSplitProdCode(iRowGetProdCode)
iRowCountOutput = iRowCountOutput + 1
Next iRowGetProdCode
here is an idea how to discover an un-empty columns in the same row,
maybe you will find it useful and manipulate it for your needs:
Function LoopUntilLastColumn(ByVal Row As Integer)
Dim i As Integer
i = 1
Do While Cells(Row, i) <> ""
' do somthing
MsgBox (" I AM ALIVE COLUMN!")
i = i + 1
Loop
' you can also use the return value of the function.
LoopUntilLastColumn = i
End Function
I'm not exactly sure about what you're asking, but here are my three best guesses.
1.) Splitting delimited data from a single cell to columns
Without VBA: Use the "Text to Columns" function (Excel Ribbon:
Data|Data Tools).
With VBA: Use the split function MSDN (Related Post), then assign array values to target cells. Or parse your string manually with a loop.
2.) Finding the end of a continuous range
Without VBA: Use ctrl + arrow key
With VBA: Use the Range.End Property
3.) Looping through columns and rows
Used a nested loop:
For c = 1 to 5
For r = 1 to 20
Cells(r,c) = "Row = " & r & ", Column = " & C
Next
Next
Editing Suggestions (I don't have enough reputation to directly comment or edit)
This question as worded may be too specific for StackOverflow. Consider re-wording so that the problem can be understood in a general context and your question can be more useful to others.
Also, the wording is a little confusing. For example, use of the term "value" seems to change from referring to delimited data to referring to cell content in VBA. Likewise, it can be confusing to use "fields" or "columns" to describe the data if it's actually delimited text, so clarity on the data's state of existence would help.
It also seems to me that you've parsed the string on it's delimiter to an array, and that you're looping through this array to write the data in rows. I still can't see how exactly your question about setting a range fits in.

#VALUE error with Excel VBA Function

In my Excel spreadsheet I have two columns.
A contains strings with the values 'Yes', 'No' or 'Maybe'.
B contains strings with a year in.
I need a function to determine the number of occurrences of a year in column B, where the equivalent value in column A is 'Yes'.
I currently have the following code:
Function CountIfYearAndValue(Rng As Range, YNM As String, Year As String) As Integer
Dim count As Integer
count = 0
For Each c In Rng.Cells
If (StrComp(Abs(c.Value), Year, vbTextCompare) = 0) And (StrComp(Cells(c.Row, A), YMN, vbTextCompare) = 0) Then count = count + 1
Next
CountIfYearAndValue = count
End Function
The idea of this code is that we iterate through every cell in the range given (a range on column B) and check if the year is equal to the Year parameter. And if the equivalent cell on column A is equal to the YNM parameter we increment the count variable.
For some reason this code does not work when I use the following parameter:
=CountIfYearAndValue('Years'!B1:B7,"Yes","Year 7")
It just does the #VALUE error and refuses to display any outcome.
Any help would be much appreciated.
Edit: All of the values in both cells are on of an unformatted datatype ('General') and no cells are blank.
It sounds like you are reinventing the wheel... There already is a built in function (advantage: being much faster than a UDF) that does exactly what you are after. It is called COUNTIFS()
All YESes for Year 7 in rows 1 to 10.
=COUNTIFS(B1:B10, "Year 7",A1:A10, "Yes")
I just had a quick look at your code and I think there are possibly a few reasons why your original code is not working as expected.
YNM is a valid column name therefore it should not be used as a variable name. You should avoid naming your variables like that - give it a more meaningful name
YNM != YMN as you had it in your code (see function definition and then the misspelled version in the StrComp() function)
Year is a valid VBA built in function, therefore once again you should avoid using it as a variable name as you're exposing yourself to a naming collision.
Add Option Explicit at the top of your module. This requires you to Dimension all you variables. It's always recommended for many many reasons.
rng variable is of Range type therefore you do not need to explicitly add the .Cells property to it. Even though it may help in some cases - at a bit more advanced level you may face some runtime type compatibility issues. ( runtime may convert your rng Range variable to a 2D array etc )
Added an explicit conversion in the second StrComp() function around the c.Offset(0, -1) as you don't want the runtime to (rare but still possible) convert your Yes to a Boolean data type. Explicit conversion to a String just gives you that extra protection ;p (lol)
therefore, something like this returns the correct value
Function CountIfYearAndValue(rng As Range, choice As String, myYear As String) As Long
Dim count As Long
count = 0
Dim c As Range
For Each c In rng
If (StrComp(c, myYear, vbTextCompare) = 0) And (StrComp(CStr(c.Offset(0, -1)), choice, vbTextCompare) = 0) Then
count = count + 1
End If
Next c
CountIfYearAndValue = count
End Function
Right, I hope this helps you understand bits and pieces :) any questions please leave a comment

VB not returning same value as MS Excel when doing calculations?

I'm doing some calculations on VB based on values returned from a database, I've compared the values to the results I'm already getting on MS Excel and they seem to a bit off. I also know all the data is being read succesfully from the database. I'm wondering if it could have something to do with the data types I'm using? I've tried with both double and decimal and still no luck. There are 24 values in each array. My formula is:
Σ[(forecast-historic)/historic*100]/24
This is my code, all the variables are doubles by the way:
Public Function Evaluate(ByVal historic() As Double, ByVal forecast() As Double) As Double
For z As Integer = 0 To 23
hourly(z) = ((forecast(z) - historic(z)) / historic(z)) * 100
daily+= Math.Abs(hourly(z))
Next
effectiveness= daily / 24
Return effectiveness
End Function
For example if:
historic() = {16,18,15,16,14,14,15,16,17,20,22,25,27,27,27,27,26,24,23,22,19,18,16,16}
forecast() = {17,17,16,16,16,16,16,15,15,18,21,24,26,27,29,29,28,28,26,24,22,21,19,18}
The result on MS Excel is 8.47643, while on VB it is 9.1245.
I've checked the values 1 by 1, and they differ since the first operations when I send the value to hourly.
Any suggestions on how to make this more exact? Thanks.
For the example value you provided, VB value 9.1245 seems correct. I tried in excel and got result as 9.12452077.
Check your excel spreadsheet formulas..
In row 5, for column A to X, I used the formula =ABS(((A2-A1)/A1)*100)
In Z5, =SUM(A5:X5)/24 being used

Macro to run through 3 conditions and provide value

This is my first time using VBA for Excel (I usually code Java and C++), and I was hoping to get some tips to start out.
I want to write a macro for a large data set that will proceed through the following list of conditions to provide a dollar result:
Collect unit size from column A (Possible values 0-8)
Determine whether single or family unit from Column B (Single- 1, Family- 0)
Collect utility code from Column C (code for type of product being assessed)
From this information, a new value will be placed in the row which determines utility costs by taking into account unit size, type of unit, and the product in question. I have thought about using nested Select Case or nested conditionals in a loop, but overall I am pretty lost.
It seems like a worksheet formula might do the trick, but it's hard to tell without knowing what the calculation is. Below is a user-defined function (UDF) that you would put in a standard module. You would call it from a cell like:
=computecosts(A2,B2,C2)
Obviously the code would change depending on how your data is laid out and what your calculation is.
Public Function ComputeCosts(rSize As Range, rFamily As Range, rCode As Range) As Double
Dim lSizeFactor As Long
Dim lFamilyFactor As Long
Dim dCodeFactor As Double
Dim rFound As Range
Const lFAMILY As Long = 0
'Size factor is a function of 0-8, namely adding 1
lSizeFactor = rSize.Value + 1
'Family factor is computed in code
If rFamily.Value = lFAMILY Then
lFamilyFactor = 3
Else
lFamilyFactor = 2
End If
'Code factor is looked up in a different sheet
Set rFound = Worksheets("Sheet2").Columns(1).Cells.Find(rCode.Value, , xlValues, xlWhole)
If Not rFound Is Nothing Then
dCodeFactor = rFound.Offset(0, 1).Value
End If
'do the math
ComputeCosts = lSizeFactor * lFamilyFactor * dCodeFactor
End Function
Thanks for the responses, they were helpful in understanding VBA for Excel. I just ended up putting possible values in a table and then using Match functions within an Index function to pick out the right value.