Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
Home
DiscussionsAccessExcelInfoPathOutlookPowerPointPublisherWord
DirectoryUser Groups
Related Topics
Outlook ExpressInternet ExplorerWindowsMS Server ProductsMore Topics ...

MS Office Forum / Excel / New Users / March 2008

Tip: Looking for answers? Try searching our database.

I need elegance.....

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
MDBJ - 30 Mar 2008 19:06 GMT
I'm stumped and asking for elegance here....

I have a table that doesn't scale in a linear fashion
(it is for use with computing the langolier pool water index)
when I check the water I get  a test result to compare to my table,
and I then take the result from the other side for further computation

     32 0
     37 0.1
     46 0.2
     53 0.3
     60 0.4
     66 0.5
     76 0.6
     84 0.7
     94 0.8
     105 0.9

what I want is for a test result like 35-  I'd like to get a formula
response that is .06

so I'd like a formula that finds
which two table numbers it falls between, then computes the scale in
difference
(the steps between the higher & lower chart numbers)
then adds the # of steps necassary from the diff of my test result and the
lower table number.

i.e.  if test result is 79--
1st- find that the result is between 76 & 84 on the table
2nd from 76 to 84 (8 digits) the steps are .0125 each
3rd 79 is three more steps than 76- so my answer is the .6 from 76 (on the
table) + 3 steps of .0125 or final answer .6375

I did in fact, when attempting this the first time, create on a second
worksheet a strict list of the table
from 32 to 105, and computed each individual # result.
(creating a new table 73 lines long)
the problem is- my next 2 table sets would be 995 lines long....
thanks for any ideas...

     5 0.3
     25 1
     50 1.3
     75 1.5
     100 1.6
     125 1.7
     150 1.8
     200 1.9
     250 2
     300 2.1
     400 2.2
     800 2.5
     1000 2.6
Three Lefts - 30 Mar 2008 19:31 GMT
>I'm stumped and asking for elegance here....
>
>I have a table that doesn't scale in a linear fashion
>(it is for use with computing the langolier pool water index)

Did you mean "langelier" water pool index, or are you in a Stephen
King novel? ;-)

>when I check the water I get  a test result to compare to my table,
>and I then take the result from the other side for further computation
[quoted text clipped - 46 lines]
>      800 2.5
>      1000 2.6
MDBJ - 30 Mar 2008 19:52 GMT
>>I'm stumped and asking for elegance here....
>>
[quoted text clipped - 3 lines]
> Did you mean "langelier" water pool index, or are you in a Stephen
> King novel? ;-)

Yes, you are correct.

thank you for your prompt attention in addressing the most critical portion
of my posting.

I really do appreciate it.
Three Lefts - 30 Mar 2008 22:01 GMT
>>>I'm stumped and asking for elegance here....
>>>
[quoted text clipped - 8 lines]
>thank you for your prompt attention in addressing the most critical portion
>of my posting.

Apparently, you couldn't find any humor in it and you couldn't ignore
it.

>I really do appreciate it.

Hey, my main goal in life is to help you out. Which way did you come
in?
Niek Otten - 30 Mar 2008 19:45 GMT
Use this User Defined Function (UDF)
If you're new to VBA, look at the instructions at the end of this post

' ====================================
Function TabInterpol(ToFind As Double, Table As Range) As Double
Dim RowNrLow As Long
Dim RowNrHigh As Long
Dim TableEntryLow As Double
Dim TableEntryHigh As Double
Dim ToFindLow As Double
Dim ToFindHigh As Double
Dim i As Long
Dim a As Double

For i = 1 To Table.Rows.Count
   a = Application.WorksheetFunction.Index(Table, i, 1)
   If a >= ToFind Then
       RowNrLow = i - 1
       Exit For
   End If
Next i

RowNrHigh = RowNrLow + 1
TableEntryLow = Application.WorksheetFunction.Index(Table, RowNrLow, 2)
TableEntryHigh = Application.WorksheetFunction.Index(Table, RowNrHigh, 2)
ToFindLow = Application.WorksheetFunction.Index(Table, RowNrLow, 1)
ToFindHigh = Application.WorksheetFunction.Index(Table, RowNrHigh, 1)
TabInterpol = TableEntryLow + (ToFind - ToFindLow) / (ToFindHigh - ToFindLow) _
* (TableEntryHigh - TableEntryLow)
End Function

' ====================================

     ================================================
     Pasting a User Defined Function (UDF)
     Niek Otten, March 31, 2006

     If you find a VBA function on the Internet or somebody mails you one, and you don't know how to implement it, follow these
steps:

     Select all the text of the function.
     CTRL+C (that is, press and hold down the CTRL key, press C, release both). This a shortcut for Copy.
     Go to Excel. Press ALT+F11 (same method: press and hold the ALT key, press the F11 key and release both). You are now in the
Visual Basic Editor (VBE).
     From the menu bar, choose Insert>Module. There should now be a blank module sheet in front of you. Click in it and then
press CTRL+V (same method.). This a shortcut for Paste. You should now see the text of the function in the Module.
     Press ALT+F11 again to return to your Excel worksheet.
     You should now be able to use the function as if it were a built-in function of Excel, like =SUM(..)
     ================================================

Signature

Kind regards,

Niek Otten
Microsoft MVP - Excel

| I'm stumped and asking for elegance here....
|
[quoted text clipped - 50 lines]
|      800 2.5
|      1000 2.6
Mike Tordoff - 30 Mar 2008 21:17 GMT
It looks like the original table is a second order polynomial function that
has been rounded to the nearest integer or tenth of an integer.  The
following formula should give you a close enough answer

=-0.54128+0.01848*A1-0.000045*A1^2

where A1 is the cell containing the value you want to convert

> Use this User Defined Function (UDF)
> If you're new to VBA, look at the instructions at the end of this post
[quoted text clipped - 109 lines]
> |      800 2.5
> |      1000 2.6
Harlan Grove - 30 Mar 2008 21:43 GMT
"Niek Otten" <nicol...@xs4all.nl> wrote...
>Use this User Defined Function (UDF)
...

Why a udf? The OP's problem requires simple linear interpolation. If
the OP's table were in a range named Tbl, and the measured value
entered in a cell named MV, the resulting interpolated index value
would be given by the formulas

=((INDEX(Tbl,MATCH(MV,INDEX(Tbl,0,1))+1,1)-MV)*VLOOKUP(MV,Tbl,2)
+(MV-VLOOKUP(MV,Tbl,1))*INDEX(Tbl,MATCH(MV,INDEX(Tbl,0,1))+1,2))
/(INDEX(Tbl,MATCH(MV,INDEX(Tbl,0,1))+1,1)-VLOOKUP(MV,Tbl,1))

or

=TREND(OFFSET(Tbl,MATCH(MV,INDEX(Tbl,0,1))-1,1,2,1),
OFFSET(Tbl,MATCH(MV,INDEX(Tbl,0,1))-1,0,2,1),MV)

or if you use another cell named FI containing the formula

=MATCH(MV,INDEX(Tbl,0,1))

you could return the desired result with the formula

=TREND(INDEX(Tbl2,FI,2):INDEX(Tbl2,FI+1,2),
INDEX(Tbl2,FI,1):INDEX(Tbl2,FI+1,1),MV)

Perhaps none of these is elegant, but linear interpolation into a
table with the key values in the leftmost column is elementary. IMO,
simplicity is lost in your udf due to overly long variable names which
distract and obscure. Also, the udf should include initial error
checking to catch common errors.

I can't see any benefit to using a For loop repeatedly calling
Application.WorksheetFunction.Index vs a simple assignment calling
Application.WorksheetFunction.MATCH once. Also no clear benefit to
multiple Application.WorksheetFunction.Index calls to fetch table
values rather than using the .Cells property of the table range
object.

Finally, this is simple to generalize to tables containing more than 2
columns which would allow the user to specify which column to
interpolate. Default to the presumably most common 2nd column.

Function lininterp( _
x As Double, _
tbl As Range, _
Optional ycol As Long = 2 _
) As Variant
'------------------------
 Dim k As Long
 Dim xlo As Double, xhi As Double, ylo As Double, yhi As Double

 If tbl.Rows.Count < 2 Or tbl.Columns.Count < ycol Then
   lit = CVErr(xlErrRef)
   Exit Function
 End If

 If x < tbl.Cells(1, 1).Value2 _
  Or x >= tbl.Cells(t.Rows.Count, 1).Value2 Then
   lit = CVErr(xlErrNA)
   Exit Function
 End If

 k = Application.WorksheetFunction.Match(x, tbl.Resize(, 1))

 xlo = tbl.Cells(k, 1).Value2
 xhi = tbl.Cells(k + 1, 1).Value2
 ylo = tbl.Cells(k, ycol).Value2
 yhi = tbl.Cells(k + 1, ycol).Value2

 lininterp = ((xhi - x) * ylo + (x - xlo) * yhi) / (xhi - xlo)

End Function

[Digression: maybe long variable names serve some purpose in long and/
or complex nonmathematical procedures, but they're decidedly
deleterious in simple mathematical procedures.]
Niek Otten - 30 Mar 2008 23:48 GMT
<Why a udf?>

Because

=TabInterpol(10,A1:A20)

is easier to remember than

=((INDEX(Tbl,MATCH(MV,INDEX(Tbl,0,1))+1,1)-MV)*VLOOKUP(MV,Tbl,2)
+(MV-VLOOKUP(MV,Tbl,1))*INDEX(Tbl,MATCH(MV,INDEX(Tbl,0,1))+1,2))
/(INDEX(Tbl,MATCH(MV,INDEX(Tbl,0,1))+1,1)-VLOOKUP(MV,Tbl,1))

Thanks very much for your comments on my programming style, although I'm not entirely convinced that will help the OP solving
his/her problem.

Signature

Kind regards,

Niek Otten
Microsoft MVP - Excel

| "Niek Otten" <nicol...@xs4all.nl> wrote...
| >Use this User Defined Function (UDF)
[quoted text clipped - 74 lines]
| or complex nonmathematical procedures, but they're decidedly
| deleterious in simple mathematical procedures.]
Ron Rosenfeld - 30 Mar 2008 21:43 GMT
>I'm stumped and asking for elegance here....
>
[quoted text clipped - 50 lines]
>      800 2.5
>      1000 2.6

Set up two columns:

Reading    LangIndex
32    0
37    0.1
46    0.2
53    0.3
60    0.4
66    0.5
76    0.6
84    0.7
94    0.8
105    0.9

I selected the table, and then NAME'd the columns using the column labels at
the top.  (So if the table started in A1, Reading would refer to:  A2:A11 in
this example).

Then use the formula:

=FORECAST(TestValue,OFFSET(Reading,-1+MATCH(Value,Reading),1,2),
OFFSET(Reading,-1+MATCH(Value,Reading),0,2))

This should work for   MIN(Reading)<=TestValue<MAX(Reading)

--ron
Lori - 30 Mar 2008 23:39 GMT
=percentile(b:b,percentrank(a:a,c1,30))

assuming data in the first two columns e.g. c1=79 gives 0.6375.
Ron Rosenfeld - 31 Mar 2008 00:25 GMT
>=percentile(b:b,percentrank(a:a,c1,30))
>
>assuming data in the first two columns e.g. c1=79 gives 0.6375.

Very nice!
--ron
Roger Govier - 31 Mar 2008 12:16 GMT
Now that's what I call elegance.
Very nice indeed Lori

Signature

Regards
Roger Govier

> =percentile(b:b,percentrank(a:a,c1,30))
>
> assuming data in the first two columns e.g. c1=79 gives 0.6375.
MDBJ - 31 Mar 2008 19:05 GMT
wow.

I've now read up on the percentile & percentrank functions,
picked apart the statement and I see how this works-
that is amazing-  I am dumbfounded..  I haven't comprehended/absorbed this
into my
understanding of excel yet, but I must say- you have definately hit my
desire to a T

I was expecting something I'd have to merge with an if statement for when it
was a perfect table match result--
but that is an absolute killer, take a bow--  thank you, both for the answer
and the education....

Just wow.

> =percentile(b:b,percentrank(a:a,c1,30))
>
> assuming data in the first two columns e.g. c1=79 gives 0.6375.

Rate this thread:






 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.