Shop OBEX P1 Docs P2 Docs Learn Events
Using the ** operator — Parallax Forums

Using the ** operator

NewzedNewzed Posts: 2,503
edited 2006-03-23 17:27 in General Discussion
If you have used the ** operator, you know the fractional 5-digit operator has to be calculated externally and then plugged into the program.

Here is a modified ** program that lets you enter the fractional multiplier directly, then it calculates 5-digit operator "on the fly".· Accuracy is about .01 percent compared to calculating the 5-digit operator externally.· I would think this is close enough for all but the most precise calculations.

Remember, your decimal multiplier has to be entered as exactly four digits without the decimal point.

If you wonder about the file name, you can not use * when naming a file.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Sid Weaver
Do you have a Stamp Tester yet?
http://hometown.aol.com/newzed/index.html

Comments

  • Ryan ClarkeRyan Clarke Posts: 738
    edited 2006-03-08 00:35
    Sid,

    Could you document what you are doing more clearly- I see greater error than what you have listed...

    Ryan

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Ryan Clarke
    Parallax Tech Support

    RClarke@Parallax.com

    Post Edited (Ryan Clarke (Parallax)) : 3/8/2006 1:00:59 AM GMT
  • NewzedNewzed Posts: 2,503
    edited 2006-03-08 01:00
    Ryan, run the program and enter a value of 9347 and hit Enter.· Enter the decimal .4382 as 4382 and hit enter.· You should get an answer of 4096.

    9347 x .4382 = 4095.855 on my calculator, which is pretty close.

    Sid
  • Ryan ClarkeRyan Clarke Posts: 738
    edited 2006-03-08 01:02
    Pretty close and declaring "0.01 percent" are two different things. I just don't want people to consider precision issues without all of the facts on the code they are dealing with.

    That's a neat app. I noticed you went with the 1678 (rounding the digit up)- an analysis can be made on how/when to round up (or down) can change accuracy. Some more complex algorithms flip/flop up/down to help reduce error further.



    Ryan

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Ryan Clarke
    Parallax Tech Support

    RClarke@Parallax.com
  • NewzedNewzed Posts: 2,503
    edited 2006-03-08 01:07
    In· the example I just gave you, the derived answer was 4096.· The calculated answer was 4095.855.· 4096/4095.855 = 1.000035, which is an error of .0035 percent.· I ran several other numbers and the average error is about .01 percent or less.

    Sid
  • Ryan ClarkeRyan Clarke Posts: 738
    edited 2006-03-08 01:17
    Often times a few trials can appear to not skew as badly towards certain parts of a distribution- careful, do you math like a physicist (joke)....

    Ryan

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Ryan Clarke
    Parallax Tech Support

    RClarke@Parallax.com
  • Fe2o3FishFe2o3Fish Posts: 170
    edited 2006-03-08 06:33
    Be careful, Newzed!

    Value = 1
    Frac = 0001
    Answer = 0

    Yer off by 0.0001 but that's an error of 100% !!!

    Luckily though, for all 9,999 non-zero fractional values, for all values of Value from 1 to 9999,
    that's your largest error! Yes, I did calculate all possible outcomes. It only took 19-seconds
    on a 1-GHz PIII.

    Your smallest, non-zero error is 0.00000149% which occurs at value = 8199, frac = 8201.
    There may be more but that's the first of the smallest, non-zero percent error detected.

    On the bright side, you do have no error when you have something like value = 2, frac = 5000.

    Your average error (taking into account the 100% error as well as the 0% errors)
    over the entire range above, though, is 0.305% so....
    claiming an error of about 0.01%.... might be a tad bit of an exaggeration. smile.gif

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    -Rusty-
    --
    Rusty Haddock = KD4WLZ = rusty@fe2o3.lonestar.org
    **Out yonder in the Van Alstyne (TX) Metropolitan Area**
    Microsoft is to software what McDonalds is to gourmet cooking
  • Jon WilliamsJon Williams Posts: 6,491
    edited 2006-03-08 06:37
    Lesson: Just calculate your ** and */ parameters.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Jon Williams
    Applications Engineer, Parallax
  • neotericneoteric Posts: 144
    edited 2006-03-08 19:45
    Newzed,

    Thanks for this code.· It really helped me in trying to understand this operator!· (**)

    I am adding a calibration routine to my "touch a sketch"· see in projects.

    I was trying to figure out this exact thing!



    Thanks. ALOT!


    Post Edited (neoteric) : 3/8/2006 8:22:20 PM GMT
  • NewzedNewzed Posts: 2,503
    edited 2006-03-08 20:27
    Neoteric, here is Rev A of the program.· The accuracy has been improved quite a bit, but it is still not as close as I want it to be.· I'm still working on it.

    Rusty, I'd appreciate if you did the analysis on Rev A and see if the error rate has improved.



    Sid
  • Ryan ClarkeRyan Clarke Posts: 738
    edited 2006-03-08 21:06
    Jon Williams (Parallax) said...
    Lesson: Just calculate your ** and */ parameters.

    In light of how the code is growing now, Jon's words resonate...


    Ryan

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Ryan Clarke
    Parallax Tech Support

    RClarke@Parallax.com
  • NewzedNewzed Posts: 2,503
    edited 2006-03-08 21:49
    Ryan, lesson learned today:· Spot checks don't cut it.

    We're getting closer.

    Sid
  • NewzedNewzed Posts: 2,503
    edited 2006-03-08 22:57
    Rusty, the average error you came up with - was that comparing my program results with the true calculated answer, or was it comparing my program output to the output of a ** routine where frac was calculated externally?

    Thanks

    Sid
  • Fe2o3FishFe2o3Fish Posts: 170
    edited 2006-03-08 23:33
    Sid,

    The average error I came up with was comparing your program results with the true calculated answer.
    I believe that I simulated a */ and ** operators correctly in C. The true calculated results were done in
    floating point. I'd hate to think how long this would take if I had written my program to just spew out all
    the possibilities on the BS2e or whatever. BasicStamps are great for some things but they aren't necessarily
    the fastest things on 8-bits. smile.gif

    I'll code up your new routine later tonight after I get home from work but, sorry dude, I've gotta agree with
    Jon and Ryan.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    -Rusty-
    --
    Rusty Haddock = KD4WLZ = rusty@fe2o3.lonestar.org
    **Out yonder in the Van Alstyne (TX) Metropolitan Area**
    Microsoft is to software what McDonalds is to gourmet cooking

    Post Edited (Fe2o3Fish) : 3/9/2006 12:09:26 AM GMT
  • Fe2o3FishFe2o3Fish Posts: 170
    edited 2006-03-09 04:27
    Sorry Sid, while your minimum (non-zero) err went down a tad (1.15e-06 vs 1.49e-06)
    your average error went UP from 0.305% vs 0.316%. One worry that I had was about my
    "emulation" of PBASIC's */ and ** operators. I have checked them and they are, in fact,
    quite accurate.

    Min err % = 1.15e-06% @ value = 9797, frac = 8867
    Max err % = 100% @ value = 1, frac = 0001
    Avg err % = 0.316%

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    -Rusty-
    --
    Rusty Haddock = KD4WLZ = rusty@fe2o3.lonestar.org
    **Out yonder in the Van Alstyne (TX) Metropolitan Area**
    Microsoft is to software what McDonalds is to gourmet cooking
  • NewzedNewzed Posts: 2,503
    edited 2006-03-09 18:30
    I have completely rewritten my original program.· I discovered that·some SELECT/CASE statements were apparently not operating.· Why I have no idea, but rather than fight it, I switched over to IF/THEN statements.

    When I refer to a "standard"·** program, I am referring to the routine where the frac value is calculated externally, then plugged into the program.

    I used 47 decimal multipliers, ranging from .0062 to .999.· In all cases my program output was exactly the same as the output from a standard ** program.· If you compare the program outputs to the true calculated values, you will find that the error is the same as comparing the standard ** outputs to the true calculated values.

    This program will allow you to use variables as decimal multipliers, calculating frac values "on the fly", so to speak.· Just remember that multipliers must be formatted as a 4-digit number without the decimal point.

    If you should find a multiplier that does not agree with the standard ** program output, please let me know and I will try to adjust the program.

    Rev B is attached.

    Sid
  • NewzedNewzed Posts: 2,503
    edited 2006-03-09 18:31
    I forgot to mention - the entire program takes only 374 bytes.

    Sid
  • Fe2o3FishFe2o3Fish Posts: 170
    edited 2006-03-10 00:35
    Sid,

    I see at least one problem in your code: if the value of frac is < 6555 it will not
    execute the statement IF frac>5400 THEN. Is this what you intended?

    Your previous program had some SELECT cases that produced no results.

    Also, keep in mind that my test program tests every possible value for 'value' and 'frac', except for zero.

    I would highly recommend that persistance into this project would best be rewarded by finding the
    real reason all these "special cases" for which you're adjusting.

    Oh he**.... just use this instead of all your SELECT/IF-THEN statements
    frac = (frac * 6) + (frac ** $8db9)
    


    This is the factor to be used with ** for a given fractional value.

    This cranks in with an average error like your first attempt.

    Execise for the reader: Adjust frac for truncation errors.

    P.S. The entire program only takes 145-bytes.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    -Rusty-
    --
    Rusty Haddock = KD4WLZ = rusty@fe2o3.lonestar.org
    **Out yonder in the Van Alstyne (TX) Metropolitan Area**
    Microsoft is to software what McDonalds is to gourmet cooking

    Post Edited (Fe2o3Fish) : 3/10/2006 5:58:40 PM GMT
  • NewzedNewzed Posts: 2,503
    edited 2006-03-14 20:55
    After spending many hours on my ** program, trying to match the output of a standard ** program, it occurred to me – why try to match a routine that generates an error on its own? Why not go for the real thing – the true calculated value.

    So I redid the program with a goal of having my program output as close as possible to the true calculated value. When I was finished, I temporarily modified the program so it would calculate the products of all 9848 multipliers and a constant. I captured the output to Excel, added a column to Excel to calculate the true value of each multiplier times the constant and a column to calculate the error between my program output and the true calculated value.

    When it was all done, I found 9 multipliers that had an error greater than .06 percent and 15 multipliers that had an error greater than -.06 percent. The largest error found was .123 percent. The remaining 9824 multipliers had errors between

    .06 and -.06 percent, with a large majority having errors of less that .050 to -.050

    percent.

    So there you are. If you have a use for the program, that’s great. If not, that’s OK, too. The real point is I finished what I started out to do. Quite an programming exercise, I can assure you.

    The program is attached. If you would like to see the spreadsheet showing all 9848 outputs, PM me and I will send it to you. It is quite large – 8MB - so I didn’t want to post it here.

    Sid

  • Tracy AllenTracy Allen Posts: 6,666
    edited 2006-03-14 22:42
    Hi Sid, I have a description on my web site, www.emesystems.com/BS2math2.htm, with examples, of how to invert a fraction for use with **. Given the fraction, N/D the following 4 lines of code calculate the ** multiplier that approximates N/D:

    '---------binary division loop-----------
    ' numerator N < denominator D
    ' Denominator D < 32768
    ' Calculates value F = N/D * 65536
    for J=15 to 0               ' 16 bits 
    N=N//D<<1                   ' remainder*2 
    F.bit0(J)=N/D               ' next bit 
    next
       '----------------------------------------
    




    The value F is what you then use with ** in something like result = raw * N / D, or in stampese,
    result = raw ** F

    With a 4 digit decimal fraction, you have been talking about N/D of the form, N/10000. But the binary division method works no matter what the denominator happens to be (up to 32767).

    I use this snippet all the time in the context of other programs, where a calibration value has to be back-calculated, or where a formula includes a fractional value. Not just for straight N**F type calculations. For example, suppose you have thermistor in series with a fixed resistor across the power supply, and the voltage input to an analog-todigital converter is,
    Vth = Vdd * Rth / (Rth+ Rfixed)
    


    and solving for Rth,
    Rth = Rfixed * Vth / (Vdd - Vth)
    


    At that point the input to the binary algorithm is Vth / (Vdd - Vth), and then Rth = Rfixed ** F.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Tracy Allen
    www.emesystems.com
  • Tracy AllenTracy Allen Posts: 6,666
    edited 2006-03-22 07:44
    Hi Sid,
    I know you got busy with your bargraph project (which looks great!).

    If you get back to this topic, here's a link to another recent thread where it was convenient to find the multiplier to use with ** at run time:
    http://forums.parallax.com/showthread.php?p=576994

    That shows a practical application of the above binary long division routine.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Tracy Allen
    www.emesystems.com
  • NewzedNewzed Posts: 2,503
    edited 2006-03-22 13:57
    Tracy, thanks for your comment on the X-Y bargraph [noparse]:)[/noparse])

    I tried the program you just referenced, but since I didn"t have a TMP04 I really couldn't get it to work right.· When you have time, could you modify the program to fit my situation?· For instance, I want to multiply a constant - 3254 - by a four digit decimal, such as 0330, 1256 or 3896 and so on.· Decimal entry would be prompted by the program.· I'd really like to try this out and compare the results with my program.

    Thanks

    Sid
  • Tracy AllenTracy Allen Posts: 6,666
    edited 2006-03-22 16:35
    Sid,

    Why 3254, a constant? In your original program you had the user enter one number, like 9347, and then a decimal fraction, like 0.4382, and then
    >>9347 x .4382 = 4095.855 on my calculator, which is pretty close.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Tracy Allen
    www.emesystems.com
  • NewzedNewzed Posts: 2,503
    edited 2006-03-22 17:16
    Tracy, I have a spreadsheet with 3254 multiplied by all decimals from .015 to .9999.· I use it as a reference to check modifications to my original program or to check other programs.· If you think the answers I'm getting are as close as I'm going to get then we can skip the other program you mentioned.

    Sid
  • Tracy AllenTracy Allen Posts: 6,666
    edited 2006-03-22 21:57
    Okay, I see where that number comes from. Here, try this program:

    ' {$STAMP BS2pe}
    ' {$PBASIC 2.5}
    ' demoStar2decimal.bse
    ' author Tracy Allen
    ' demos use of ** operator to calculate decimal fraction times whole number.
    
    N VAR WORD          ' this will be the result of (number * (decimal/10000)), on the Stamp, (number ** F)
    number VAR WORD  ' user enters this whole number
    decimal VAR WORD   ' and this integer representing xxxx/10000 = 0.xxxx
    F VAR WORD        ' this will the number to use with **, F = 65536 * xxxx/10000
    idx VAR NIB
    
    DO
      DEBUG CR,"enter an integer (0 to 65535): "
      DEBUGIN DEC number
      DEBUG CR,"enter a decimal fraction 0.xxxx as integer (0000 to 9999): "
      DEBUGIN DEC decimal
      GOSUB compute
      DEBUG CR, DEC number, " * 0.", DEC4 decimal, " = ", DEC   N
    LOOP
    
    compute:
      N = decimal
      FOR idx=15 TO 0   ' binary long division
        N = N // 10000 << 1
        F.BIT0(idx) = N/10000
      NEXT
      N  = number ** (F+1)    ' F contains the approximation , decimal/10000 ~= F/65536, plus 1 to round up
    RETURN
    
    



    Short and sweet. It is possible to eke out greater precision out of it if the range of values is limited, and for small numbers in general. So you would get 10 * 0.3333 = 3.333 instead of just 3, as it does above.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Tracy Allen
    www.emesystems.com
  • NewzedNewzed Posts: 2,503
    edited 2006-03-22 23:09
    Tracy, I tried out your program.· I really hate to say this but it looks like mine
    is more accurate.· For example:

    Your program - .425 x 3254 = 1892.· Error is .654 percent.

    My program - .425 x 3254 = 1383.· Error is .004 percent.

    I also noted that your program does not generate answers with decimals for
    the lower decimals, only integers.· For instance, with .0413 x 3254, your
    program says 134, error .291, ·while mine says 134.4, error .007 percent.

    However, your program is so beautifully short that I'm going to play around
    with it a bit and see if I can get answers closer to my program.· I can see
    the problems ahead - where you get 134 I need to get 1344, divide by 10, then
    display the last decimal.

    I appreciate very much your taking the time to write a special version for me.

    Sid
  • Tracy AllenTracy Allen Posts: 6,666
    edited 2006-03-23 02:12
    Hi Sid,

    I don't want to belabor the issue, but just as a point of fact, my program returns 0.425 * 3254 = 1382. (not 1392, and certainly not 1892). My algorithm as shown always truncates, rounds down. The correct answer is 1382.91..., so I guess your's is indeed closer. That earns you two stars (**)!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Tracy Allen
    www.emesystems.com
  • Tom WalkerTom Walker Posts: 509
    edited 2006-03-23 13:56
    ...then Newzed can use his program to figure out what the "two stars (**)" are worth [noparse]:)[/noparse]

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Truly Understand the Fundamentals and the Path will be so much easier...
  • NewzedNewzed Posts: 2,503
    edited 2006-03-23 17:27
    reklamot, nornally two ** are worth 84, but coming from Tracy you have to
    add 5 zeros.

    Tracy, as usual you are correct - I also get 1892.

    I made some slight modifications to your program:

    DO
    · DEBUG CR,"enter an integer (0 to 65535): "
    · DEBUGIN DEC number
    · DEBUG CR,"enter a decimal fraction 0.xxxx as integer (0000 to 9999): "
    · DEBUGIN DEC decimal

    · GOSUB compute

    · IF N<293 THEN····· 'added
    · N = N*/$0A08
    · DEBUG "0.", DEC4 decimal, " x ", DEC number, " = ", DEC n/10, ".", DEC1 n, cr
    · GOTO cont1
    · ENDIF

    · IF n<781 THEN······· 'added
    · n = n + 1
    · DEBUG "0.", DEC4 decimal, " x ",· DEC number, " = ", DEC n, cr
    · GOTO cont1
    · ENDIF

    · DEBUG· "0.", DEC4 decimal, " x ", DEC number, " = ", DEC·· N, cr
    · cont1:
    LOOP

    In the larger numbers the answers were about the same; however,
    accuracy was improved with the small numbers.· I have attached the
    spread sheet in case you would like to look at it.· It is quite large.

    I need to look at the spreadsheets again, but I think I'm going to use your
    program as modified.· It is so much shorter and much more efficient.· Thanks
    again.

    Sid
Sign In or Register to comment.