I'm almost certain the answer is 'no', but I thought I'd ask the people here just in case there is some magic formula I haven't yet found...
So lets say I have a table of values;
I've also got another cell somewhere (lets just say that this cell is A1 for my example), which has another number in it. This number is actually a percentage (lets call it 20% in this example)
So I have a table that looks like this
A B C D E
1 | 20
2 |
3 | Number
4 | 23
5 | 68
6 | 145
7 | 8
The simplest way to explain it is to say I'm going to reduce each number by the percentage given in cell A1 (20% in my example). I'm then going to repeat (so reduce the new values by another 20%) until the answer is zero (rounded to 2dp in this example, though I may need more or less rounding later).
I'm trying to work out how many times the formula must run to get the values to 0
Like I said, I'm almost certain this cannot be done outside of scripting (VBA etc.), since to my knowledge excel formulas can't loop and count??
I'm also sure that this is actually quite an easy script (though I don't know VBA at all, so it wouldn't so easy for me to do). I'm certain I could do this in other languages. But then that won't really help, as I'm trying to do this entirely in excel.
I've done it very inelegantly using a formula on another sheet copied down (A1 takes the percentage off the original value, A2 takes the percentage from the value of A1 etc.), and I can then just see which row number the value hits 0, but I was just curious to know if there was a more efficient solution;
a) without using VBA
b) using VBA to do so properly (not important, but I'd like to see how its done if anyone can)
Thanks
My solution would be directly calculate the answer directly.
You are looking for something that gets to 0 rounded to 2 decimals so <0.0049 your formula then becomes
0.0049 = A4 *(1-A1)^n
ln(0.0049) = ln(A4)+ n*ln(1-A1)
n = (ln(0.0049)-ln(a4))/ln(1-A1)
Since you want a whole number of loops you would take the next number higher so final equation is
=ceiling((ln(0.0049)-ln(a4))/ln(1-A1),1)
(1-A1) refers to how much is left after once iteration.
You said A1 is a percentage. If you put in 20% in excel it is treated as 0.2.
The original formula should be
0.0049 = A4*(0.8)^n
Excel uses some kind of "linear calculation model" in which a formula in a cell determines the value of the cell based on the value of other cells, using functions and references. Excel maintains a dependency graph and whenever a cell changes value, it recalculates all dependents, recursively (so dependents of dependents get recalculated too).
The only iteration Excel provides in this model is within functions of the formula.
I believe it is possible in Excel to define a user function that you can use in formulas in your cells.Any iterations you need can be performed by this function (in VBA).
(P.s.: the other iteration Excel provides is in the circular reference, when the dependents of a cell after zero or more steps comes back to the cell as a dependent of itself. Excel will flag this but I believe it is possibe to allow this and instruct Excel how many iterations to perform.)
Related
I am new to Excel/Google Sheets. I have a difficulty of writing a formula to compare columns as a pair-wise since the formula would be
so big as the day goes.
For example, there're 2 main columns Foo and Bar. I want to find the total number of days that Foo
and Bar are equal so the current formula is =IF(A3 = G3, 1, 0)+IF(B3 = H3, 1, 0)+IF(C3 = I3, 1, 0)+...
But this is kind of tedious because there're ~40 days to compare with. Are there any other alternatives
to write a formula in efficient way? Either Google-App-Scripts or Excel Formula is appreciated.
Cheers!
Give a try on below google-sheet formula. Adjust ranges as you need.
=ArrayFormula(SUM(IF(A3:E3=G3:K3,1,0)))
Assuming that you're needing to get such a total for each row and not merely a single row, try this:
=ArrayFormula(IF(A3:A="",,MMULT(IF(A3:F=G3:L,1,0),SEQUENCE(COLUMNS(A:F),1,1,0))))
Of course you will need to adjust the three ranges to match your own FOO and BAR ranges.
This one formula will produce all results for all rows.
The MMULT function is tricky to explain to those as yet unfamiliar with it. But it's a powerful tool. I'll add a picture I created that may best explain what it does:
By making the second matrix a simple SEQUENCE of 1s as long as the other matrix is wide, we wind up multiplying everything by 1 before adding together. And since anything multiplied by 1 is itself, this combination serves only to do a row-by-row add.
Things to keep in mind with MMULT:
1.) Every cell in every matrix must be a number or it will produce an error.
2.) As in the above formula, there are ways to use either/or conditions to turn every cell in a matrix into a number.
I am proficient Excel User, but I do not want to use VBA or Data Table to solve the below problem.
Preferably, I want to use Goal Seek or Solver or any other simple method that does not require macros (loops) and not require large data table spanning many rows.
Here is the problem: In Cell B1, the Solution is 15,621 (there are other solutions over this number too)
However I want to start the search from 1, and adding 1 each time, or adding 5 each time (if possible, 1, 6, 11, etc.), until Cell D17 equals 1. It will eventually equal 1 say many times under a million.
I may want to change starting point from 20,000 onwards, etc.
Is this possible? Goal Seek doesn't find it as the formulas use Mod, Min, Max.. thus doesn't linearly converge.
Is there any other way to rewrite this problem that can be made of Goal Seek or Excel Solver.
This is a famous math problem (http://mathcentral.uregina.ca/QQ/database/QQ.02.06/meadow4.html), but I want to use Excel.
I know that I can solve using vba loops and data tables. But, I want a simpler solution that uses goal seek or solver or other unknown.
Excel's "Iterative Calculation" might do the trick.
As seen here: ablebits.com: "Circular reference in Excel - how to check, find, enable, or remove"
Iterative calculation allows circular dependencies of your formulae. In Excel 2010 you find it in "Excel Options" -> "Formulars" -> "Calculation options" -> "Enable iterative calculation".
Note: 32767 is the maximum number of iterations in Excel 2010
In your example you could have a variable in (let's say) B2 initially set to your minimum. B1 is then set to to be like B2 as long as the solution is not found. If the solution is found, it is set to B2 minus the increment.
Now, if you change B2 to be B1 plus increment, the Excel's iterative calulation should stop at your solution.
example:
B2 = 1
B1 = =IF(D17<>1, B2, B2-1)
B2 = =B1+1
Update (based on the comment by #ihightower):
The iterative calculation stops when the values change less than the defined threshold "Maximum Change" (default: 0.001) or when the "Maximum Iterations" have been executed.
At the end of each run, B2 already contains the initial value for the next one. To invoke the next iterative calculation, go to the result's cell D17, press [F2] and then [Ctrl]+[Enter].
To jump to a new initial value, set B2 to the new minimum value and to =B1+1 afterwards.
Without VBA, I am trying to refer a range that starts at A2 and never ends. For example, if I want row 2 till row 5 i'd do
$A$2:$A$5
But what if I want the end to be open?
$A$2:??
Is this possible?
Depending on what's in A1 and what formula you're putting the reference into, you could simply use A:A. For example, if you wanted to sum all of the values in column A, but A1 contained a column title rather than a number, you could still write =SUM(A:A) and the title in A1 would just be ignored.
A2:A works in many formulas
hope that helps
If you want to refer to a range starting from A2 until max row (1048576 or 65536 for Excel prior to 2007), you can use this volatile formula... =OFFSET(A2,0,0,(COUNTBLANK(A:A)+COUNTA(A:A)-1),1) . Use formula as a defined range name or inside other formula which takes range as an argument (for eq SUM)...
Another option (in case your formula is in A1, so accessing A:A would create a circular reference) is:
OFFSET(A2, 0, 0, ROWS(A:A)-1)
This uses ROWS to count the total number of rows (without actually accessing the rows!), subtracts 1 (because we're starting with the second row), and uses this result as the height of a range created with OFFSET.
This is another option based on a formula, using the example locations in the OP's question:
=A2:INDEX(A:A,MAX(FILTER(ROW(A:A),IF(ISBLANK(A:A),0,1)=1)))
The components are the following:
=MAX(FILTER(ROW(A:A),IF(ISBLANK(A:A),0,1)=1))
which finds the number of the deepest row that is not blank, and
A2:INDEX(A:A,<expression 1 above>)
which relies on the expression above to make a bigger formula, which obtains a range starting from any location and ending at a location in the given column at the position obtained by this expression, 1.
This is an alternative to the others listed, and may be of interest as it differs from them in potentially substantial ways.
I can note the following characteristics:
It is not necessarily fast.
It seems to NOT be a volatile formula. This is important, as it means it won't necessarily be recalculated every time a calculation is made. However, I am not sure about the frequency of calculation, and don't fully understand its volatility status.
The uncertainty is related the use of the INDEX function (and, apparently, specifically after the : in a range). There are some resources that describe it.
INDIRECT and OFFSET functions are definitely volatile. There are a number of resources that describe performance implications of volatile functions, some of them mentioned in other SO answers. For example:
https://learn.microsoft.com/en-us/office/client-developer/excel/excel-recalculation
https://www.sumproduct.com/thought/volatile-functions-talk-dirty-to-me
http://www.decisionmodels.com/calcsecretsi.htm
https://chandoo.org/wp/handle-volatile-functions-like-they-are-dynamite/
It allows the user to not have to think about the data in certain cells (for example, A1, which may be meant to have a header, and not numbers).
It returns a range between the cell specified before the : and the last cell in the column that is non-blank. I think it should include non-numeric values in its consideration as well.
It shares some commonality in terms of the range it aims to identify with the answer by Kresimir L.: =OFFSET(A2,0,0,(COUNTBLANK(A:A)+COUNTA(A:A)-1),1).
To note: This answer applies to the version of Excel available as of the time of writing as part of Office 365 (and continually updated). However, the answer is based only on my own verification of its apparent correctness of my installation. I am not sure that all installations of Office 365 have the same software exactly; and I have the sense that some features may differ among different installations (even) of Office 365. I am not sure that this answer applies to everyone. Please test. I would appreciate feedback on your success with this approach.
This well covered in VBA as code below:
Range("A2", Range("A2").End(xlDown))
And if you want reach that in formula, it depends on the version number of your MS-Excel.
According to this reference number of all rows are in a sheet from Excel 2007 onwards are 1048576 that you can use bellow:
$A$2:$A$1048576
Because this range in formula is depended on Excels version, this may be different in future versions.
Finally, I suggest you use VBA.
I'm trying to create a formula that takes C2-B2 and uses the result to determine which cells to add together. So if the result is 2 it takes AA2 and AB2, adds them together, and displays the result. In other words, it counts cells stemming from a point and adds them, with the amount counted determined by the result of two other cells.
This doesnt sound recursive the way you describe it.
Put this formula somewhere on the sheet and see if this is what you want:
=SUM($AA$2:INDEX($AA$2:$XFD$2, 1, SUM($B$2:$C$2)))
(Alternate title: Why on earth doesn't Excel support user-defined formulas with parameters without resorting to VB and the problems that entails?).
[ Updated to clarify my question ]
In excel when you define a table it will tend to automatically replicate a formula in a column. This is very much like "fill down".
But ... what if you need exceptions to the rule?
In the tables I'm building to do some calculations the first row tends to be "special" in some way. So, I want the auto-fill down, but just not on the first row, or not on cells marked as custom. The Excel docs mention exceptions in computed columns but only in reference to finding them and eliminating them.
For example, first row is computing the initial value
The all the remaining rows compute some incremental change.
A trivial example - a table of 1 column and 4 rows:
A
1 Number
2 =42
3 =A2+1
4 =A3+1
The first formula must be different than the rest.
This creates a simple numbered list with A2=42, A3=43, A4=44.
But now, say I'd like to change it to be incremented by 2 instead of 1.
If I edit A3 to be "A2+2", Excel changes the table to be:
A
1 Number
2 =A1+2
3 =A2+2
4 =A3+2
Which of course is busted -- it should allow A2 to continue to be a special case.
Isn't this (exceptions - particularly in the first row of a table) an incredibly common requirement?
If you have the data formatted as a table you can use table formulas (eg [#ABC]) instead of A1 format (eg A1, $C2 etc). But there are 2 tricks to account for.
Firstly there is no table formula syntax for the previous row, instead excel will default back to A1 format, but you can use the offset formula to move you current cell to the previous row as shown below. However in this case it will return an # value error since I cant +1 to "ABC".
ABC
1 =OFFSET([#ABC],-1,0)+1
2 =OFFSET([#ABC],-1,0)+1
3 =OFFSET([#ABC],-1,0)+1
4 ....
So the second trick is to use a if statement to intialise the value, buy checking if the previous row value = heading value. If the same use the initial value else add the increment. Note assumes table is named Table1
ABC
1 =IF(OFFSET([#ABC],-1,0)=Table1[[#Headers],[ABC]],42,OFFSET([#ABC],-1,0)+1)
2 =IF(OFFSET([#ABC],-1,0)=Table1[[#Headers],[ABC]],42,OFFSET([#ABC],-1,0)+1)
3 =IF(OFFSET([#ABC],-1,0)=Table1[[#Headers],[ABC]],42,OFFSET([#ABC],-1,0)+1)
4 ....
Note you can set the initial value to be a cell outside the table to define the initial value (in say $A$1) and increment (in say $A$2) as below
ABC
1 =IF(OFFSET([#ABC],-1,0)=Table1[[#Headers],[ABC]],$A$1,OFFSET([#ABC],-1,0)+$A$2)
2 =IF(OFFSET([#ABC],-1,0)=Table1[[#Headers],[ABC]],$A$1,OFFSET([#ABC],-1,0)+$A$2)
3 =IF(OFFSET([#ABC],-1,0)=Table1[[#Headers],[ABC]],$A$1,OFFSET([#ABC],-1,0)+$A$2)
4 ....
I use this IF OFFSET combination all the time for iterating and looping in tables.
If you have alot of columns that need to determine if they are the first row you can have one column test if first row and the rest can work with a simpler if. eg ABC will give true for first row false for others, then DEF with increment the initial value
ABC DEF
1 =OFFSET([#ABC],-1,0)=Table1[[#Headers],[ABC]] =IF([#ABC],$A$1,OFFSET([#DEF],-1,0)+$A$2)
2 =OFFSET([#ABC],-1,0)=Table1[[#Headers],[ABC]] =IF([#ABC],$A$1,OFFSET([#DEF],-1,0)+$A$2)
3 =OFFSET([#ABC],-1,0)=Table1[[#Headers],[ABC]] =IF([#ABC],$A$1,OFFSET([#DEF],-1,0)+$A$2)
4 ....
Hope that helps
I don't know if you are looking for something as simple as locking down a formula. You can do that by highlighting the part of the formula you do not want to change and then hitting F4. This will absolute this section of the formila, using a $ to indicate it, and will not change as you copy/paste it down the table.
Alternately, you may be able to use Defined Names. These you can set up in the Data tab and basically assigns something to a name or variable you can then put into your formulas. These can be as simple as an easy reference for a cell on another sheet to incredibly complex multi-sheet formals.
Normally, to handle "exceptional" formula in the first row of a table consiting of several columns, you simply enter it there manually, and fill only the lines below. But if you have more "exceptional" cases scattered around, you will need another column with 0/1 values indicating where the exceptins are. And then you use if(condition, formula_if_true, formula_if_false) everywhere.
A B
Number Exceptional?
1 if(C1,42,A1+1) 0
2 if(C2,42,A2+1) 1
3 if(C3,42,A3+1) 0
As much as I love Excel, and as much as it is the best product of whole MS, it is still a weak tool. FYI, you can quiclky learn modern and poweful scripting languages, such as Ruby, here, and never be bothered by spreadsheet idiosyncrasies again.