HP Forums
How do I learn RPL and solve this problem with it? - Printable Version

+- HP Forums (https://www.hpmuseum.org/forum)
+-- Forum: HP Calculators (and very old HP Computers) (/forum-3.html)
+--- Forum: General Forum (/forum-4.html)
+--- Thread: How do I learn RPL and solve this problem with it? (/thread-9150.html)

Pages: 1 2


How do I learn RPL and solve this problem with it? - setq - 09-24-2017 12:48 PM

I’m the owner of a 50g and I’d like to port a few programs away from the PC. I get distracted pretty easily and end up on eBay if I go near it Smile

I am pretty much a newbie when it comes to RPL programming. I’ve written a couple of things that do simple solvers like parallel resistance/capacitance etc where you dump two values on the stack and execute a program to get a solution but I have a more complicated problem to solve. However I need to know where to start and how to learn it effectively. I’ve been programming for 25 years in C etc so I’m not a complete programming newbie.

Basically I do a lot of EE work which requires precise resistor values. We carry stock of standard E12 values in I.e 10, 12, 15, 18, 22, 27, 33, 39, 47, 56, 68, 82. In ranges x0.1, x1, x10, x100, x1k, x10k, x100k, x1M. Instead of waiting 2-3 days for the correct value to arrive from a supplier, I tend to use value combinations of two resistors in parallel and series on the breadboard. Unfortunately calculating these takes time by hand.

So I wrote a C program that generated a list of all series and parallel combinations of any two resistors sorted in value order. I then wrote another program that sorts them by closest match, reports the two values either side of the match and reports a percentage difference so I can evaluate tolerance.

I’d like to port that to RPL or come up with a better method. Any pointers appreciated. I explicitly don’t want hand holding, just a nudge in the right direction Smile


RE: How do I learn RPL and solve this problem with it? - pier4r - 09-24-2017 01:29 PM

It sounds interesting as personal challenge!

Also I am pretty sure RPL EE programs already exist scattered on hpcalc.org , this forum and comp.sys.hp48 (a news group) although your request may need a program ad hoc.

I am not sure if I understood what is your objective though, can you make a poignant example?

What I understood is the following.

You need to produce a resistor of value 177 , you don't have the piece with you so you want to pick the pieces that can do this in the smallest amount given that you put them in series..

So a solution for 177 (maybe not the shortest one, it is just an example) would be to put in series resistor of 10 (x10), then 47 (x1) then two times 15 (x1) . Is that correct?

And this changes if some resistors are missing, correct? Like you don't have the 10 (x10)

edit: after a second read of your post I guess the example is not needed.
You want all the 2 possible combinations in series and in parallel and the closest match with the value in input (with some indication about: what what was used for the match and what is the difference).

That sounds like a task for the ListExtension of David. Docomb especially. here: http://www.hpmuseum.org/forum/thread-8555.html


RE: How do I learn RPL and solve this problem with it? - HP67 - 09-24-2017 01:44 PM

It should go without saying there are at least two pieces to any programming task. The first one is you have to design your solution. That could mean selecting an algorithm or a formula etc. The second this is picking the language and system you want to write it for.

RPL is different from most languages in that it is stack-based. If you have a formula to solve a problem a lot of the effort that will go into coding it in RPL is to use the stack effectively. comp.lang.forth on usenet is a good source of info on how to think in stack-based terms. Unfortunately the noise level is pretty high there at times.

I am no expert in RPL either and I also have a long background in programming. I have written a bunch of RPL so as a fellow newbie I can tell you the way I got started.

I converted some programs from a language I knew and from algorithms that were stated clearly enough into RPL. I got out a big pad of paper and started making stack diagrams. I figured out which arguments would be input and then tried to figure out how to manage them on the stack. After a while I started focusing on how to maximize the use of the stack and keep temp variables on top or close to the top by reorganizing the calculations in a more stack-friendly way.

It is fun but it is also frustrating at times. Sometimes a mistake in your code will require you to make a lot more changes than you would in most other languages to fix it. On the other hand when you get a piece of RPL doing what you want I think you get a sense of satisfaction that lasts longer because in some ways RPL is harder.

There are several guys here on the forum who have written and debugged a lot of RPL. If you post code samples of things you tried that didn't work I'm sure they can help. If you can't get started, post a formula or two or describe the algorithm you want to implement and I'm sure you will get some ideas from the guys how to approach coding it in RPL.

I like RPL because I find it is extensible. I like building primitives and then making my solution out of those basic functions. Once they are tested and work correctly you can assemble a nice collection of tools that make every subsequent program that much easier. That method of approaching a solution is something I have always done. And I feel RPL is particularly good for people who like working that way.

"So I wrote a C program that generated a list of all series and parallel combinations of any two resistors sorted in value order. I then wrote another program that sorts them by closest match, reports the two values either side of the match and reports a percentage difference so I can evaluate tolerance."

You could break the RPL solution up into the same types of logical pieces. You could have a function that produces the list and then another function that sorts them, then another one or more that does the reports. The stack is great for holding lists and temporary values and you don't have to use variable names.


RE: How do I learn RPL and solve this problem with it? - John Keith - 09-24-2017 03:03 PM

As to your general question on learning RPL, There are many resources on hpcalc.org, and on the Museum USB stick. The USB stick has nearly every HP calculator manual in existence and much else besides.

You can also learn a lot just by reading posts on this site (I sure have!) especially threads regarding programming contests and challenges.

John


RE: How do I learn RPL and solve this problem with it? - setq - 09-24-2017 03:18 PM

Thanks all for the replies. Much appreciated.

Fundamentally the problem is, I need a 523K resistor for example as the output of a filter design program. If I enter this into my current program it will pop out:

560K || 8.2M = 524.2K (0.23%)

That means if I parallel 560K and 8.2M I will get 524.2k to within 0.23%. Now the resistor bank is a 1% accuracy one so that will be within the design tolerance (ignoring external factors like capacitor tolerance)

I'm not sure that the current solution is actually viable on the HP 50G as the combined list is quite large. I don't have it here in front of me now as it's on my Mac and I'm on a phone but I think it was in the order of a few Mb of data.

I'm aware of stack languages (about 20 years ago I actually wrote a FORTH implementation for Z80 CPUs whilst bored at university) so I'm aware of the concepts. Will have a look around at what people have suggested.

Thanks again.


RE: How do I learn RPL and solve this problem with it? - pier4r - 09-24-2017 03:21 PM

So I am really interested by your problem, that for what I understood is not that "difficult" for a couple of terms but for many it starts to be a challenge.

As usual, a lot of data is challenging to process in limited time.

So far I got "insufficient memory" (my 50g has 'only' 160 KB free in port 0) . I need to improve the algorithm because the search is too naive at the moment.

Nevertheless, such problems are always a chance to learn the vast amount of possible commands that the 50g offers. So thanks for it! (and I wonder how many others I miss that were posted here)

quick explanations nonetheless.


First of all my workflow. I use a windows XP system to develop for calculators and embedded devices.

What do I do? I have the 50g connected via USB. In notepad++ (using the "normal text language") I write my program. For this I create a duplicate of a template file and I call it with some name, like:

mathDirMisc.txt

The content at the start is this

Code:

%%HP: T(0)A(D)F(.);
@ alternative found online %%HP: T(3)A(R)F(.);
@ You may edit the T(0)A(D)F(.) parts.
@ The earlier parts of the line are used by Debug4x.

@ in npp, just select language "normal" to get rid of the highlight.

(yes I picked the template from debug4x mostly)

Then I create a directory, because according to the topic I may have several programs. Even one program may be split in subprograms so a directory is a nice container for it.

Code:

%%HP: T(0)A(D)F(.);
@ alternative found online %%HP: T(3)A(R)F(.);
@ You may edit the T(0)A(D)F(.) parts.
@ The earlier parts of the line are used by Debug4x.

@ in npp, just select language "normal" to get rid of the highlight.

DIR
  @here the code will be inserted

END


Then I insert what I need, normally a program, so it gets like

Code:

%%HP: T(0)A(D)F(.);
@ in npp, just select language "normal" to get rid of the highlight.

DIR
  @here the code will be inserted
  directoryEntryName
  \<<
     "hi there"
     "notice that the name of this program is equal to 'directoryEntryName'"
     "this program, when executed, will put those three strings on the stack"
  \>>
END

Note the use of digraphs, that are the ASCII translation of some important symbols on the 50g. In particular you find details about them in the hp 50g AUR. See http://www.hpmuseum.org/forum/thread-9090.html

With conn4x you can drag and drop the txt file on the calculator and it will be a valid directory afterwards.

Then it comes the actual program that I was trying.

Code:

%%HP: T(0)A(D)F(.);
@ in npp, just select language "normal" to get rid of the highlight.

DIR
  resistorsFindCouple
  @2017-09-24-16-00
  @Problem: given a list of resistors, compute any combination of two of them
  @in series or parallel to find the one that is closer to the input value.
  @see also www.hpmuseum.org/forum/thread-9150.html
 
  @Todo: 
  @ - faster search of possible values.
  @ - to precompute the list of resistors
  @ - to extend to more than 2 resistors.
  
  @requires: 
  @ - LSORT (see hp_calc_torrent and hpcalc.org)
  @ - listExt from DavidM (see hpmuseum forum or hp_calc_torrent)
  \<<
    { 10 12 15 18 22 27 33 39 47 56 68 82 }  "baseResistors" DROP
    DUP "allResistors" DROP
    { 0.1 10 100 1000 10000 100000 1000000 } "resistorRanges" DROP
    
    \->
    @input
    
    @localVar
    baseResistors
    allResistors
    resistorRanges
    
    \<<
      @first we build the list of all possible resistors from the base one.
      
      @for every element in the range of resistors we expand the list of available
      @resistors
      1 resistorRanges SIZE
      FOR position
        'allResistors'
        baseResistors
        resistorRanges position GET
        *
        STO+
      NEXT
      
      @now we order the resistors, although it is not strictly needed for the result
      allResistors :2:LSORT EVAL 'allResistors' STO
      
      @here we have all the resistors needed.
      @now we need to compute all the possible compositions of those in serial or parallel.
      
      allResistors
      2
      \<<
        "" "stringTag" DROP
        
        \->
        @input
        inputList
        
        @var
        stringTag
        \<<
          @we build the tag
          inputList \->STR 'stringTag' STO
          
          @we compute the values
          
          @series
          inputList LSUM
          "S" stringTag +
          \->TAG
          
          @parallel
        \>>
      \>>
      DOCOMB
    \>>
  \>>
END

but the search space is too large. So for now I have to think about something smarter. If you have questions about the simbols I used, ask! Asking is great to trigger possible explanations.


RE: How do I learn RPL and solve this problem with it? - HP67 - 09-24-2017 04:06 PM

I can't remember if you can store a giant list on the SD card and then recall it to the stack in a program but I guess you should be able to do that.


RE: How do I learn RPL and solve this problem with it? - pier4r - 09-24-2017 04:10 PM

Only if you split it in pieces, because the processing is done nevertheless in memory.

Anyway my approach was very naive, likely there is a lot of space for ad hoc optimizations. I already see better ways for serial resistors. I will have to think some more about parallel resistors.

Anyway what helps a lot are the limits that so far I did not consider. Only 2 resistors. Only 1% of error tolerance and so on. due to these one can speed up the process a lot.

Nice problem though, it could have been something for the HHC or even list processing.


RE: How do I learn RPL and solve this problem with it? - HP67 - 09-24-2017 04:14 PM

(09-24-2017 04:10 PM)pier4r Wrote:  Only if you split it in pieces, because the processing is done nevertheless in memory.

I don't know why you would have to split it in pieces. You have to create it once as a list and then save the list on the card, right?

BTW I didn't see that setq specifies the tolerance of his resistors. The 4th band...


RE: How do I learn RPL and solve this problem with it? - pier4r - 09-24-2017 04:17 PM

Yes. The point is that if the list of all the possible solution is larger than memory it won't the memory when you need to recall it.

Anyway you gave me an idea. Precompute the values. store them in several files on the sd card and then recall them when needed. So the computation is done mostly once.


RE: How do I learn RPL and solve this problem with it? - HP67 - 09-24-2017 04:25 PM

(09-24-2017 04:17 PM)pier4r Wrote:  Yes. The point is that if the list of all the possible solution is larger than memory it won't the memory when you need to recall it.

Ok, I missed that. But the 50g has an awful lot of memory! I guess some creative tricks could be used to slim the list down if it really doesn't fit. And I wasn't talking about the solution- I was talking about the list of input values! The calculation is why we're doing this on a calculator!

(09-24-2017 04:17 PM)pier4r Wrote:  Anyway you gave me an idea. Precompute the values. store them in several files on the sd card and then recall them when needed. So the computation is done mostly once.

Certainly if anything can be precalculated it goes without saying that should be done, especially in an embedded application. But I thought the list was about the various values of resistors he has to work with, not about how they might be used.


RE: How do I learn RPL and solve this problem with it? - pier4r - 09-24-2017 06:02 PM

well if I am not mistaken with the list of the resistors, there are 4560 possible couples.

If I want to tag every couple with the values used and "series or parallel" I use too much memory (over 160kb).

Solution: clever code or precomputation on the SD and then a program that based on the input selects the right SD file that contains likely the input needed.

For example on the SD one can store a list of all the solutions that have a value under 10. A list that have a value between 10.01 and 100 , a list between 100.01 and 1000 and so on.

Although I would like to attempt first a clever selection given the constraints.

What irks me is that such small but interesting problems are likely everywhere but I don't see them, and those are great to learn more about the 50g and its large library of functions, list processing and testing the list of David.


RE: How do I learn RPL and solve this problem with it? - Brad Barton - 09-24-2017 06:35 PM

(09-24-2017 12:48 PM)setq Wrote:  Any pointers appreciated. I explicitly don’t want hand holding, just a nudge in the right direction Smile

If you want to learn RPL and how to use it to interact with the stack on the 50G, then the the 2 volumes by Bill Wickes are the go-to reference in my mind. The are titled "HP-48 Insights Part I" and "HP-48 Insights Part II" Both are available on the MoHP documents USB drive, which is available here http://www.hpmuseum.org/cd/cddesc.htm . This collection includes manuals for every HP calculator along with many useful documents. You may be able to find pdf's available on line as well. All example programs in the books can be downloaded from hpcalc.org http://www.hpcalc.org/details/8112

As a new user, you may not realize that the HP-50G is a grown up version of the HP-48, and the concepts that apply in the 48 will also apply in the 50G. The 50G has a larger command set, but the study of RPL implementations in the 48 will apply directly to what you'll need to program the 50G.

For a full explanation of the 50G command set you'll want to download a copy of the HP-50G Advanced User's Guide (AUR). It can be obtained at hpcalc.org http://www.hpcalc.org/details/7141

I find RPL a very useful language with many nuances. To make truly useful programs with it requires a bit of study, but it's very satisfying to craft an elegant solution to the problem at hand. A common complaint though is that it is difficult to debug or modify in the future, because keeping track of stack manipulations is an abstraction that requires effort to re-create in your mind once you've moved past the immediate problem.


RE: How do I learn RPL and solve this problem with it? - pier4r - 09-25-2017 05:48 AM

My second approach, inspired by the discussion with hp67 (thanks!) is to pre-compute the value and then having the real program searching the right value among the pre-computed ones .

So at the moment I am in the process to pre compute the value (not storing them on the SD card at first) but on the 50g it takes quite a while.

Since I discovered that the 50g when it is busy does not update the clock, I can tell how long it is computing.

In this moment the actual date is: 2017-09-25-07-46
The calculator shows the clock locked at 2017-09-24-22-18

I checked the program once again and I do not see parts where it can end in loop, so I leave it running because it can end from a moment to another.

Surely I feel that there would be room for improvement.

Code:

\<<
    { 10 12 15 18 22 27 33 39 47 56 68 82 }  "baseResistors" DROP
    { 1. 1.2 1.5 1.8 2.2 2.7 3.3 3.9 4.7 5.6 6.8 8.2 
10. 12. 15. 18. 22. 27. 33. 39. 47. 56. 68. 82. 100. 120. 
150. 180. 220. 270. 330. 390. 470. 560. 680. 
820. 1000. 1200. 1500. 1800. 2200. 2700. 3300. 
3900. 4700. 5600. 6800. 8200. 10000. 12000. 
15000. 18000. 22000. 27000. 33000. 39000. 
47000. 56000. 68000. 82000. 100000. 120000. 
150000. 180000. 220000. 270000. 330000. 390000. 
470000. 560000. 680000. 820000. 1000000. 1200000. 
1500000. 1800000. 2200000. 2700000. 3300000. 
3900000. 4700000. 5600000. 6800000. 8200000. 
10000000. 12000000. 15000000. 18000000. 
22000000. 27000000. 33000000. 39000000. 47000000. 
56000000. 68000000. 82000000. } "allResistors" DROP
    DUP SIZE "allResistorsNumber" DROP
    { 0.1 10 100 1000 10000 100000 1000000 } "resistorRanges" DROP
    {} "resultSerial" DROP
    {} "resultParallel" DROP
    0 "value1" DROP
    0 "value2" DROP
    {} "allResistorsListTemp" DROP
    {} "allResistorsListTemp2" DROP
    
    \->
    @input
    
    @localVar
    baseResistors
    allResistors
    allResistorsNumber
    resistorRanges
    resultSerial
    resultParallel
    value1
    value2
    allResistorsListTemp
    allResistorsListTemp2
    
    \<<
      \<<
        @first we build the list of all possible resistors from the base one.
    
        @for every element in the range of resistors we expand the list of available
        @resistors
        1 resistorRanges SIZE
        FOR position
          'allResistors'
          baseResistors
          resistorRanges position GET
          *
          STO+
        NEXT
        
        @now we order the resistors, although it is not strictly needed for the result
        allResistors :2:LSORT EVAL 'allResistors' STO      
        @we can also save the result as precomputed list
      \>> 
      DROP
        @not needed, we have the list precomputed now.
    
      @here we have all the resistors needed.
      @now we need to compute all the possible compositions of those in serial or parallel.
      
      @computing the result in order, so from the position of the element we can
      @infer the two components making the element (maybe not that easy with more than)
      @two components.
      @Cannot use docomb for this due to the not predictable way of making combinations.
      
      allResistors 'allResistorsListTemp' STO
      
      1 allResistorsNumber 1 -
      FOR index1
        allResistorsListTemp LPOP
        'value1' STO
        'allResistorsListTemp' STO
        
        allResistorsListTemp 'allResistorsListTemp2' STO
        
        index1 1 + allResistorsNumber
        START
          allResistorsListTemp2 LPOP
          'value2' STO
          'allResistorsListTemp2' STO
          
          'resultSerial'
          value1 value2 +
          STO+
        NEXT
      NEXT
      
      resultSerial
    \>>
  \>>

Once again, setq, if you have question about the syntax of the program (I have no doubts that you can figure out the meaning once being able to decode the syntax), ask!


edit: discovered that the code block on thi forum limits the shown text vertically but not horizontally. It was not expected.


RE: How do I learn RPL and solve this problem with it? - HP67 - 09-25-2017 04:08 PM

I guess Dieter or Werner or Thomas could reduce that silly list of resistor values to some kind of arithmetic series and dramatically reduce the storage requirements Wink


RE: How do I learn RPL and solve this problem with it? - pier4r - 09-25-2017 05:39 PM

(09-25-2017 04:08 PM)HP67 Wrote:  I guess Dieter or Werner or Thomas could reduce that silly list of resistor values to some kind of arithmetic series and dramatically reduce the storage requirements Wink

I guess too, they are pretty good. But well, I have to apply myself to improve as well. Only looking is not enough (and I often do not have time to find out how they reach some result unless they explain them).

Anyway I had to stop the process because after 20+ hours it was not finished.

I am not sure if there is a infinite loop in my code, I debug it once again for some values and it was ok. So I wonder if the 50g starts to be really slow when expanding list past 1000 elements.


RE: How do I learn RPL and solve this problem with it? - mfleming - 09-25-2017 06:36 PM

(09-25-2017 05:39 PM)pier4r Wrote:  Anyway I had to stop the process because after 20+ hours it was not finished.

Hi guys,

I believe you've been misled by the OP's approach of pre-computing all possible values of two resistors in parallel (combinatorial explosion), when in reality there are only a few combinations of two resistors that will meet the original criteria of being within 1% of the desired resistance value.

Consider Req = R1 || R2 = R1*R2/(R1+R2). If R1 = R2, then R1 & R2 = 2*Req. Neither R1 or R2 can be less that Req which puts a lower bound on the values we can choose. Also notice that if R2 increases to infinity then the computed Req value will converge on R1. If 2*Req happens to be a valid discrete resistor value, pick two resistors of that value and we're done.

Highly unlikely though, so pick R1 and R2 such that they bracket 2*Req. If we maintain that R1 is less than 2*Req, then there are only a few discrete resistor values that satisfy the constraint Req < R1 < 2*Req. Furthermore if R1 is fixed and R1 || R2 > Req, then any further increase in the value of R2 will only diverge from the desired Req value.

To use pier4r's example value of 177 for Req, 2*Req is 354 which is not a valid discrete resistor value. So choose R1=330 and R2=390. According to the previous constraint, the discrete value of R1 can only be 180, 200, 270, 300 and 330.

330||390 = 178.8 which is greater than 177, so no point increasing R2 any further. We will need to decrease R1 and compute again.

300||390 = 169.5 < 177 and 300||470 = 183.1 > 177 so keep the value of R2 and decrease the value of R1 again.

270||470 = 171.5 < 177 and 270||560 = 182.1 > 177 so again keep the value of R2 and decrease the value of R1.

I won't bore you with the rest of the series, but there are obviously a limited number of pairs to examine. Keep them sorted by how close they are to the desired resistor value and pick the closest pair.

Give this a try in RPL!
~Mark


RE: How do I learn RPL and solve this problem with it? - pier4r - 09-25-2017 07:10 PM

Thanks mfleming.

The problem though is not to filter the values that are out of the margin, that can be done (in a more or less optimized way).

The problem is to pick and report the values that create the closer match (or "a close") match. For this I wanted to precompute things, because then from the position in the list I know the original resistors, and that for every allowed input, it is quite quick then.

Every time I sort / filter, since there is no associative list (well I could do with lists of lists) I lose the relationships.

Furthermore I don't want to filter much because the next step is to have "missing resistors". So like "ok 82k would have been good, but it is missing, what now?" so giving out the closer 3-5 possibilities wouldn't be bad.

Anyway as expected (especially for the size) it is an interesting problem, let's see what I get.


RE: How do I learn RPL and solve this problem with it? - Claudio L. - 09-25-2017 07:41 PM

(09-25-2017 07:10 PM)pier4r Wrote:  The problem is to pick and report the values that create the closer match (or "a close") match. For this I wanted to precompute things, because then from the position in the list I know the original resistors, and that for every allowed input, it is quite quick then.

Remarkably similar to the HHC 2017 RPL contest, at least the approach I took was to solve 1/C=1/A+1/B and look for the best solution.


RE: How do I learn RPL and solve this problem with it? - David Hayden - 09-25-2017 07:55 PM

What a fantastic problem!!!

For UserRPL programming, download HPUserEdit 6 from hpcalc.org. Also download the file that converts the menus etc into English since the original is in... Spanish? HPUserEdit will let you write and debug your programs on the PC.

If your 50g came with the 184 page "User's Manual" then you should lock that book securely in a safe for now. It's more like a quick reference quide and will only serve to confuse you as a beginner. Use the "User's Guide" instead. It has much more detail.

The biggest problem with the User's Guide has to do with the 4 major modes of operation of the 50g: RPN vs. Algebraic input, and Soft Menus vs. choose boxes. Because of these modes, the User's Guide is full of things that say:

Now to do XYZ in RPN mode, enter these keys (half-page examples follows). If you're using algebraic mode, do this (another half page example follows). The above assume that you're using choose boxes. If you have soft menus, your screens will look like this... and this...

For this reason, you might want to consider using the 48GX User's Guide instead. It's all RPN and all soft menus.