In C++ I would use boost::clamp for this. Basically I have some excel function
A1*B2+C3+D4
I want to do constrain it to +/- some number, call it X1. The obvious way is this:
MAX(-X1, MIN(X1, A1*B2+C3+D4))
But I want to be able to do this:
CLAMP(A1*B2+C3+D4, -X1, X1)
Does this or something similar exist? I'm just curious - obviously the workaround works, it's just ugly.
This can be done using MEDIAN. MEDIAN picks the middle of the three values, thus effectively restricting the lower and upper limits.
For example say your minimum is 5 and your maximum is 10:
=MEDIAN(5,0,10) is 5
=MEDIAN(5,7,10) is 7
=MEDIAN(5,12,10) is 10
With spreadsheet formulas I don't think that you can do much better than that min/max construct. You could write clamp in VBA:
Function clamp(x As Double, lower As Double, upper As Double) As Double
If x < lower Then
clamp = lower
ElseIf x > upper Then
clamp = upper
Else
clamp = x
End If
End Function
If you enter that in a standard code module then you could e.g. do something like this:
In column A I have values in the range 0 to 2*pi. In C2 I have the value 0.5. In B1 I entered
=clamp(SIN(A1),-$C$2,$C$2)
and copied down. The graph shows the result.
(Since I gave a VBA solution I'll add the Excel-VBA tag. Even if you prefer a non-VBA solution, it is possible that others in the future might search the question and be comfortable with a VBA solution).
Related
I am trying to get equal result of two exact calculations which are computed in a cell formula and the other one with a UDF:
Function calc()
Dim num as Double
num = 30000000 * ((1 + 8 / 100 / 365) ^ 125)
calc = num
End Function
Result of the calculation is different
A1 = 30000000 * ((1 + 8 / 100 / 365) ^ 125) not equal to A2 = calc()
We can test it with =if(A1=A2, TRUE, FALSE) which is false. I do understand that it has something to do with data types in vba and executing cell formula. Do you know how to make calculations to from vba function(s) and excel cell field(s) to render same result?
So, the calculation in application excel and the calculation in vba are presenting different outputs (what you've presented, with format displaying 20 decimal places):
As such, you would see false when comparing them. You will need to round() or format() to truncate the calculation at a level that is appropriate. E.g.:
calc = round(num,4)
calc = format(num,"0.###0")
The reason this is occurring is because of the inherent math you're using, specifically, ((1 + 8 / 100 / 365) ^ 125), and how that is being truncated/rounded in the allocated memory to each part of the calculation, which differs in VBA and in-application Excel.
Edit: Final image with the VBA changes I'd suggested:
Explanation
Double Data type seems to have flaws being "precise" after the "nth" digit. This is stated as well in the documentation
Precision. When you work with floating-point numbers, remember that they do not always have a precise representation in memory. This could lead to unexpected results from certain operations, such as value comparison and the Mod operator.
Troubleshooting
It seems that is the case here: I set up the value from the division on a cell and the division as formula in another one, although excel interface says there are not differences, when computing that value again, the formula on the sheet seems to be more precise.
Actual result
Further thoughts
It seems that is limited by the data type itself, if precision is not an issue, you may try to round it. If it is critical to be as precise as possible, I would suggest you to connect with an API to something that is able to handle more precision. In this scenario, I would use xlwings to use python.
Excel
Need to find nearest float in a table, for each integer 0..99
https://www.excel-easy.com/examples/closest-match.html explains a great technique for finding the CLOSEST number from an array to a constant cell.
I need to perform this for many values (specifically, find nearest to a vertical list of integers 0..99 from within a list of floats).
Array formulas don't allow the compare-to value (integers) to change as we move down the list of integers, it treats it like a constant location.
I tried Tables, referring to the integers (works) but the formula from the above web site requires an Array operation (F2, control shift Enter), which are not permitted in Tables. Correction: You can enter the formula, control-enter the array function for one cell, copy the formulas, then insert table. Don't change the search cell reference!
Update:
I can still use array operations, but I manually have to copy the desired function into each 100 target cells. No biggie.
Fixed typo in formula. See end of question for details about "perfection".
Example code:
AI4=some integer
AJ4=MATCH(MIN(ABS(Table[float_column]-AI4)), ABS(Table[float_column]-AI4), 0)
repeat for subsequent integers in AI5...AI103
Example data:
0.1 <= matches 0
0.5
0.95 <= matches 1
1.51 <= matches 2
2.89
Consider the case where target=5, and 4.5, 5.5 exist in the list. One gives -0.5 and the other +0.5. Searching for ABS(-.5) will give the first one. Either one is decent, unless your data is non-monotonic.
This still needs a better solution.
Thanks in advance!
I had another problem, which pushed to a better solution.
Specifically, since the Y values for the X that I am interested in can be at varying distances in X, I will interpolate X between the X point before and after. Ie search for less than or equal, also greater than or equal, interpolate the desired X, then interpolate the Y values.
I could go a step further and interpolate N - 1 to N + 1, which will give cleaner results for noisy data.
So VBA is completely new to me. I come from a C# background.
Currently creating an order form, whereby I can input the total amount I require of an object and then the price is calculated in a different cell.
However I also want the price to change based off amount thresholds for that object.
Say for example 0 - 100 will cost £2.50 so I expect the answer to be anywhere within that range is multiplied by 2.50. Meanwhile if the amount exceeds 100 and becomes 120 I want the object price to now reflect £2.30 and proceed to multiple the 120 by £2.30.
I've noticed a few tutorials on line but they don't exactly explain how I might be able to achieve the above. Wondering if anyone can point me in the right direction?
Non VBA Soluion
If you build a table with the bottom and upper thresholds for a price, you can simply use a VLOOKUP and return the approximate match.
In photo, Column C is the output from the equation that is shown in Column D
VBA Solution
You can also use a simple UDF. Paste the code inside a Module and then you can call the function PRICEINDX from a cell just like any other equation. You can either manually type in a value like PRICEINDX(164) or select a cell that has the value to be tested like PRICEINDX(A1)
You can also set up more complex thresholds easily by using Select Case
Option Explicit
Public Function PRICEINDX(Target As Double) As Double
Dim ans As Double
Select Case Target
Case 0 To 100
ans = 2.5
Case 101 To 200
ans = 2.3
Case 201 To 300
ans = 2.1
Case Is > 300
ans = 2
End Select
PRICEINDX = ans
End Function
I'm very confused on how to use Microsoft Excel to simulate a "problem", but I've been assured that it's possible.
I have the equation
v(t) = (mg/c)(1-e^((-c/m)(t)))
And I know the values of m, g, k, and c.
m = 170
g = 32 ft/s^2
k = 2.5 lb/ft
c = 1.2 lb/ft/s
So my formula changes into
v(t) = (170*32/1.2)(1-e^((-1.2/170)(t)))
v(t) = (453.33)(1-e^((-.00705)(t)))
The problem is about a bungee jumper, and this is one function that I should use to find velocity, and another that is used for x (distance), but if I can learn how to properly implement this one, I should be able to easily figure out the other one.
I need to somehow implement this in Excel, as a spreadsheet simulation. I have no idea how to implement this in Excel, and I don't know the formulas to do it. I know I could just go through the formula manually and just substitute variables in for t (i.e., .5, 1, 1.5, 2, 2.5, ...), but I know there's supposed to be some way for Excel to do it for me. Additionally, I'm not sure how to simplify the powers and the "e" in my formula, and I actually don't know if I need it if I can just sub in variables like I think I can. Any help would be greatly appreciated.
EDIT: The other state equation, x(t), is below
x(t) = (mg/c)(t) + ((m^2 * g) / c^2))e^((-c/m)(t) - (m^2 * g / c^2))
This formula as mentioned in the OP:
v(t) = (453.33)(1-e^((-.00705)(t)))
needs a little adaptation, as suggested by #Tim Williams, to be suitable for Excel:
=453.33*(1-EXP(-.00705*t)
Excel does not multiply letters by numbers but will attempt to interpret t above as a named range (which may contain one or more numbers) before objecting. So t may be the name given to a range starting .5 and stepping .5 up to and including 10 (may easily be created with Fill , Series…).
If the above formula is then placed in the same row as 0.5 and copied down to suit the results should be as required.
It may however be worth noting that naming a range as a single letter is not best practice and for accuracy, convenience and versatility the constants (eg re gravity) and the variables (eg mass) would be better fed as parameters to the formula.
Which formulae in MS Excel can we use for -
equi-depth binning
equi-width binning
Here's what I used. The data I was binning was in A2:A2001.
Equi-width:
I calculated the width in a separate cell (U2), using this formula:
=(MAX($A$2:$A$2001) - MIN($A$2:$A$2001) + 0.00000001)/10
10 is the number of bins. The + 0.00000000001 is there because without it, values equal to the maximum were getting put into their own bin.
Then, for the actual binning, I used this:
=ROUNDDOWN(($A2-MIN($A$2:$A$2001))/$U$2, 0)
This function is finding how many bin-widths above the minimum your value is, by dividing (value - minimum) by the bin width. We only care about how many full bin-widths fit into the value, not fractional ones, so we use ROUNDDOWN to chop off all the fractional bin-widths (that is, show 0 decimal places).
Equi-depth
This one is simpler.
=ROUNDDOWN(PERCENTRANK($A$2:$A$2001, $A2)*10, 0)
First, get the percentile rank of the current cell ($A2) out of all the cells being binned ($A$2:$A$2001). This will be a value between 0 and 1, so to convert it into bins, just multiply by the total number of bins you want (I used 10). Then, chop off the decimals the same way as before.
For either of these, if you want your bins to start at 1 rather than 0, just add a +1 to the end of the formula.
Best approach is to use the built-in method:
http://support.microsoft.com/kb/214269
I think the VBA version of the addin (step 3 with most versions) will also give you the code.
Put this formula in B1:
=MAX( ROUNDUP( PERCENTRANK($A$1:$A$8, A1) *4, 0),1)
Fill down the formula all across B column and you are done. The formula divides the range into 4 equal buckets and it returns the bucket number which the cell A1 falls into. The first bucket contains the lowest 25% of values.
General pattern is:
=MAX( ROUNDUP ( PERCENTRANK ([Range], [TestCell]) * [NumberOfBuckets], 0), 1)
You may have to build the matrix to graph.
For the bin bracket you could use =PERCENTILE() for equi-depth and a proportion of the difference =Max(Data) - Min(Data) for equi-width.
You could obtain the frequency with =COUNTIF(). The bin's Mean could be obtained using =SUMPRODUCT((Data>LOWER_BRACKET)*(Data<UPPER_BRACKET)*Data)/frequency
More complex statistics could be reached hacking around with SUMPRODUCT and/or Array formulas (which I do not recommend since are very hard to comprehend for a non-programmer)