What INC From N to M in Exactly S Steps?

Just starting out? Need help? Post your questions and find answers here.
oldefoxx
Enthusiast
Enthusiast
Posts: 532
Joined: Fri Jul 25, 2003 11:24 pm

What INC From N to M in Exactly S Steps?

Post by oldefoxx »

My wife likes to watch "Who Wants to be a Millionaire?" during the week. The numbers they pick are odd, because they represent a feeble effort to double up the amount won at each step while always keeping the results rounded off to thousands, while starting at $500. The show use ro start at $100, so the rounding to nearest $1000 did not happen until you reached $1,000.

But what if you didn't round off? What it you looked for an exact increment where you went from one amount to the next in a given number of steps, and every step up was the same increment used in previous steps? I solved the problem of what Millionaire's increment should be in about 10 minutes using a spreadsheet and making manual corrections. This is what it takes to go from $500 to $1,000,000 in equal stages:

Code: Select all

       $500.00        Increment:     1.794425302
       $897.21	
     $1,609.98	
     $2,888.99	                  Find the Increment
     $5,184.08                    to Go From $500 to	
     $9,302.44                     $1 Million in a
    $16,692.54	                  Certain Number of
    $29,953.51                         Steps.	
    $53,749.33	
    $96,449.16	
   $173,070.82	
   $310,562.66	
   $557,281.49	
 $1,000,000.00	                  $1,000,000.00
I thought about coding it up, but then I thought that the challenge of it might interest others as well. So there is the challenge, or opportunity, to try something different.
has-been wanna-be (You may not agree with what I say, but it will make you think).
User avatar
BasicallyPure
Enthusiast
Enthusiast
Posts: 539
Joined: Thu Mar 24, 2011 12:40 am
Location: Iowa, USA

Re: What INC From N to M in Exactly S Steps?

Post by BasicallyPure »

This will do the calculation.

Code: Select all

N.d = 500
M.d = 1000000
S.i = 13 ;number of steps between 500 and 1000000
Inc.d = Pow(M/N,(1/S)) ; calculate the increment (multiplier)

Debug Inc

Debug ""

Repeat
   Debug N
   N * Inc
   S - 1
Until S < 0
An interesting observation.
The same code can produce the exact frequencies for an octave of musical notes.

Code: Select all

N.d = 440
M.d = 880
S.i = 12 ;number of steps between 440 and 880 (one octave)
Inc.d = Pow(M/N,(1/S)) ; calculate the multiplier

Debug Inc

Debug ""

Repeat
   Debug N
   N * Inc
   S - 1
Until S < 0
BasicallyPure
Until you know everything you know nothing, all you have is what you believe.
oldefoxx
Enthusiast
Enthusiast
Posts: 532
Joined: Fri Jul 25, 2003 11:24 pm

Re: What INC From N to M in Exactly S Steps?

Post by oldefoxx »

Nicely done. I knew it was going to be somewhat similar to mortgage calculations, but their approach does not work here because we are not dealing with an interest rate. Your use of # steps - 1 is a part of the mortgage process, as well as your use of Pow(). Much faster than the manual approach by a long shot. In the manual approach, you determine if the final total is lower or higher than the sought final, and if you overshoot, you reduce your next variation by dividing it by 10 and reverse the sign, then apply that. going back and forth until you get the final value after a round-off to the nearest penny or cent.

I made some additions to your code, so that you can see the step number and the amount us shown as a currency. In doing this, I uncovered some weaknesses in PureBasic. The lines that have been commented out are what does not work:

Code: Select all

A.d = 500
B.d = 1000000
N.i = 13 ;number of intervals between 500 and 1000000
M.d = Pow(B/A,(1/N)) ; calculate the multiplier

Debug M

Debug ""
;n.i = 1
x.i = 1
Repeat
  C.d = Int((A * 1000 + 5)/10)
  ;C.d = Int(A * 100 + .5)
  ;C.d = Int((A * 100 + .5))
  aa.s = "."+Right("0"+Str(Mod(C,100)),2)
  C / 100
  ;C = Int(C/100)
  While Abs(C)>=1000
    aa=","+Right("00"+Str(Mod(C,1000)),3)+aa
    C/1000
  Wend
  aa="$"+Str(C)+aa
  Debug Right("  "+Str(x),3) + "  "+Right(Space(15)+aa,15)
  A * M
  N - 1
  ;n + 1
  x + 1
Until N < 0
What I found first is that Int() is real fussy about the inclusion of an add or subtract operation inside its parameters. Two ways failed, and forced me to try and adopt the third.

The other problem is that PureBasic could not distinguish between N.d and n.i when it came to N-1 and n+1 inside the loop. I had to replace n,i with x.i to get it to work properly.
has-been wanna-be (You may not agree with what I say, but it will make you think).
chris_b
Enthusiast
Enthusiast
Posts: 103
Joined: Sun Apr 27, 2003 1:54 am

Re: What INC From N to M in Exactly S Steps?

Post by chris_b »

oldefoxx wrote:What I found first is that Int() is real fussy about the inclusion of an add or subtract operation inside its parameters.
That's not the problem - you need to use 0.5 instead of just .5
User avatar
Demivec
Addict
Addict
Posts: 4259
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: What INC From N to M in Exactly S Steps?

Post by Demivec »

oldefoxx wrote:The other problem is that PureBasic could not distinguish between N.d and n.i when it came to N-1 and n+1 inside the loop. I had to replace n,i with x.i to get it to work properly.
If I understand you correctly, it is because PureBasic treats the variables as being the same because it does not respect case. This is true of anything that is named as well, i.e. variables, procedures, structures, modules, etc.

You would have detected the problem sooner if you had used 'EnableExplicit'. This would of required you to define the variables before using them. If you defined 'N.d' and then 'n.i' the compiler would have told you the variable had already been delcared with a different type.
oldefoxx
Enthusiast
Enthusiast
Posts: 532
Joined: Fri Jul 25, 2003 11:24 pm

Re: What INC From N to M in Exactly S Steps?

Post by oldefoxx »

Good to know. I've spent the last few hours trying to put down the manual process into code. I've failed miserably. I can do it with ease, but coding it is a real challenge. I need to think it through further. There are two ways to consider this: The spreadsheet way, where each cell builds on the results of the cell before it:

Code: Select all

a1: = 500,  b1: = K         '; Adjust K until a14 equals b14
a2: = a1 * b$1
a3: = a2 * b$1
a4: = a1 * b$1
a5: = a2 * b$1
a6: = a1 * b$1
a7: = a2 * b$1
a8: = a1 * b$1
a9: = a1 * b$1
a10: = a2 * b$1
a11: = a1 * b$1
a12: = a2 * b$1
a13: = a1 * b$1
a14: = a2 * b$1, b14: = 1000000
The other way of looking at it is like this:

Code: Select all

A.d=500
B.d=1000000
N.i=14
K.d=Pow(B/A,1/N)
aa.s = Str(K)
Debug K
Debug aa
V.d=Int(K)
W.d=K-V
aa.s=Str(V)
If W<>0
  aa+"."
  While Len(aa)<56 And W<>0
    W*10
    x.d=Int(W)
    aa+Str(x)
    W-x
  Wend
EndIf
Debug "To go from "+Str(A)+" To "+Str(B)+" in "+Str(N)+" steps at precise intervals requires a Multiplier of"
Debug aa+" To advance from the previous Step."
v.d=a*Pow(K,N)
Debug Str(N)+"   "+Str(v)
Debug "difference = "+Str(B-v)
Now notice a couple of fiscrepancies in this program. The first is, that I am not computing all the steps. That is easy enough to do, but you really only need to see how close the final amount is. The second thing is that when I did a Str(K.d), the string was rounded off to the nearest integer. None of the fractional amount got through. I had to write in my pwn number-to-string conversion process to take care of this. Which brings up another discrepancy, in that Debug K and the contents of aa when displayed are different, and not just to the number of places that the number is carried to. Let me give you a copy-and-paste for comparison:

Code: Select all

1.721027685990313527142348    ; what the Debug showed
1.721027685990313571551268    ; what my number-to-string approach came up with
Which one is closest to the correct value I don't know. I would have to do the same process with a different compiler to have something to compare these with.
has-been wanna-be (You may not agree with what I say, but it will make you think).
oldefoxx
Enthusiast
Enthusiast
Posts: 532
Joined: Fri Jul 25, 2003 11:24 pm

Re: What INC From N to M in Exactly S Steps?

Post by oldefoxx »

Demivec wrote:
oldefoxx wrote:The other problem is that PureBasic could not distinguish between N.d and n.i when it came to N-1 and n+1 inside the loop. I had to replace n,i with x.i to get it to work properly.
If I understand you correctly, it is because PureBasic treats the variables as being the same because it does not respect case. This is true of anything that is named as well, i.e. variables, procedures, structures, modules, etc.

You would have detected the problem sooner if you had used 'EnableExplicit'. This would of required you to define the variables before using them. If you defined 'N.d' and then 'n.i' the compiler would have told you the variable had already been delcared with a different type.
I'm slow to pick up on things sometimes. Normally I begin a program with Dim and Defines, but for little quick-and-dirty efforts, I use the shorthand approach. I also reuse variables a lot rather than keep introducing new ones. Goes back to my early computer years when RAM was small and you had to conserve as much space as you could.
has-been wanna-be (You may not agree with what I say, but it will make you think).
User avatar
BasicallyPure
Enthusiast
Enthusiast
Posts: 539
Joined: Thu Mar 24, 2011 12:40 am
Location: Iowa, USA

Re: What INC From N to M in Exactly S Steps?

Post by BasicallyPure »

Here is a way to calculate the value of each step directly without the cumulative error of previous steps.
The results match exactly the values of your first post.

Code: Select all

EnableExplicit

Define s.i, i.i, n.d, m.d, v.d

n = 500
m = 1000000
s = 13

For i = 0 To s
   v = n * Pow(m/n, i/s) ;calculate the value
   Debug RSet("$" + StrD(v,2), 12)
Next i
BasicallyPure
Until you know everything you know nothing, all you have is what you believe.
oldefoxx
Enthusiast
Enthusiast
Posts: 532
Joined: Fri Jul 25, 2003 11:24 pm

Re: What INC From N to M in Exactly S Steps?

Post by oldefoxx »

Nicely done. I was most impressed by your use of StrD() to convert a double-quad to a string. I had not been aware of it before. It even rounds off the amount to the hundredths place, which is evidently what the "2" does. I had not known of StrD() before.

If you wanted to set up a game show to competee with millionaire, you have a problem: The audience wants numbers that are easy to understand. None of this "to the nearest penny" stuff would do. Thr roundoffs have to be to the nearest 100, 250, 500, or 1000. To achieve that, you have to do one of the following:

(1) Change the number of steps involved
(2) Change the initial amount
(3) Change the final amount

Depending on your initial amount, you might be able to work out a multiple that does this, such as 500 * 2, 500 * 1,2, 500 * 1.5, 1000 * 1.1, and so on. You might even decide that as the amount accumulates, the multiple can slip down a bit at a time. I haven't tried it yet, but it would mean that at $500, you begin with a multiple of 2, then work down from there. For parity with Millionaire, it might be best to begin at 500 and continue to 1,000,000. and the number of steps should remain close as well. It's an exercise in how Millionaire should have done it for uniformity across the board.
has-been wanna-be (You may not agree with what I say, but it will make you think).
User avatar
BasicallyPure
Enthusiast
Enthusiast
Posts: 539
Joined: Thu Mar 24, 2011 12:40 am
Location: Iowa, USA

Re: What INC From N to M in Exactly S Steps?

Post by BasicallyPure »

You could use a 1, 2, 5 sequence.
The 1, 2, 5 being the most significant digit of the dollar amount.
You get fewer steps but I like the dollar values it gives.
Starting with 500 the multipliers are 2, 2, 2.5 then repeat.
This method yields 500, 1000, 2000, 5000...

Code: Select all

n.i = 500
m.i = 1000000
i.i = 1 ;<-- try with an initial value of 2

Repeat
   Debug RSet("$"+StrF(n,2),11)
   n * (2 + 0.5 * Bool(Mod(i,3)=0))
   i + 1
Until n > m
BasicallyPure
Until you know everything you know nothing, all you have is what you believe.
oldefoxx
Enthusiast
Enthusiast
Posts: 532
Joined: Fri Jul 25, 2003 11:24 pm

Re: What INC From N to M in Exactly S Steps?

Post by oldefoxx »

Now I learn about using RSet() and Bool(). A well=reasoned response as well. But I'm thinking along the lines of crowding the big increments towards the earlier, lower steps. Let me play with that notion a bit. This approach of yours clusters around a 2-2-2.5 approach and gets you to the thousands divisor stage in one step. But what if you were to turn it around and do it 2.5-2-2 instead? And then recluster all the 2.5's at the beginning? I will have to look at what that would do to the results. Meanwhile, here is a slight rework of your excellent code. I just prefer to have numbers with thousands separators.

Code: Select all

Define.l n = 500, m = 1000000, i, j
Define.s aa, bb

While n<=m
  i + 1
  aa = RSet("$"+StrF(n,2),20)
  For j = Len(aa)-6 To 2 Step -4
    bb = Mid(aa,j,1)
    If bb =" " Or bb = "$"
      Break
    EndIf
    aa = Mid(aa,2,j-1)+","+Mid(aa,j+1)
  Next
  Debug RSet(Str(i),4)+aa
  n * (2 + 0.5 * Bool(Mod(i,3)=0))
Wend
What really surprised me though is having to use a Step -4 instead of Step -3. With other Basics, you find that the Len(aa) becomes fixated at the start of the For...Next statement, meaning it is treated like a constant. But with PureBasic, it looks a the current Len(aa), and you have to factor in the increased length by having a comma inserted at given intervals. If I wanted PureBasic to behave the same way, I might have to do this:

Code: Select all

hLen.l = Len(aa)-6
For j = hLen To 2 Step -3
  ...
Next
What's different is that Len(aa) is focused on working from the Right. Using hLen, I shift the focus to working from the Left.

What's odd though is that Len(aa)-6 or hLen are the initial values for the loop, not the termination limits. It's more understandable if they were the termination values, where you do the test. It's like PureBasic calibrates a new value for j from scratch for each cycle through, rather than just applying the +/- Step value to what j is currently set to. If true, this raises all sorts of possibilities for how a For...Next statement can be made to work, based on the initial For statement and how it is declared.

Now you can always modify the variable used as principal inside a For...Next loop, but that means accounting to the effect of the Step which is yet to be applied. If done as part of the For statement, the effect would be after the Step is applied. It also means the Step may not act as you expect it to, because of this difference in behavior. As in this case where I had to move to using -4 in place of -3.

While it gives prospect of doing something highly unusual with For...Next statements, it diminishes its value with respect to more stable results using Repeat or While statements in its place. With those, variables are controlled by the programmer in code.
has-been wanna-be (You may not agree with what I say, but it will make you think).
User avatar
BasicallyPure
Enthusiast
Enthusiast
Posts: 539
Joined: Thu Mar 24, 2011 12:40 am
Location: Iowa, USA

Re: What INC From N to M in Exactly S Steps?

Post by BasicallyPure »

oldefoxx wrote: I just prefer to have numbers with thousands separators.
Some time ago I wrote a procedure that would insert commas every three places in a numeric string.
The numeric string can be with or without a decimal point.
It works nicely with input from Str(), StrF(), or StrD().
Anytime I need to format a numeric string with comma separators I just invoke this handy procedure so I don't have to reinvent the wheel every time I need it.

Code: Select all

Procedure.s Commatize(text.s)
   ;inserts ',' into numeric string every 3 places
   Protected.i n, length
   Protected.s temp, frac = StringField(text, 2, ".")
   
   If frac : text = StringField(text, 1, ".") : EndIf
   
   length = Len(text)
   
   If length > 3
      For n = 1 To length / 3
         temp = "," + Right(text,3) + temp
         text = Left(text,Len(text)-3)
      Next n
      
      text = LTrim(text + temp,",")
   EndIf
   
   If frac : text + "." + frac : EndIf
   
   ProcedureReturn text
EndProcedure

Define.i n=500, m=1000000, i=1

Repeat
   Debug RSet(Str(i),2,"0") + RSet("$" + Commatize(StrF(n,2)),15)
   n * (2 + 0.5 * Bool(Mod(i,3)=0))
   i + 1
Until n > m
BasicallyPure
Until you know everything you know nothing, all you have is what you believe.
oldefoxx
Enthusiast
Enthusiast
Posts: 532
Joined: Fri Jul 25, 2003 11:24 pm

Re: What INC From N to M in Exactly S Steps?

Post by oldefoxx »

First case I've seen where StringField() was used. I didn't even know it existed. Very handy feature. Thanks for bringing it to my attention.
has-been wanna-be (You may not agree with what I say, but it will make you think).
oldefoxx
Enthusiast
Enthusiast
Posts: 532
Joined: Fri Jul 25, 2003 11:24 pm

Re: What INC From N to M in Exactly S Steps?

Post by oldefoxx »

Here is a bit of code I cooked up this evening. I wrote a few Procedures to do a few things I wanted, and these are:
(1) MultiString() -- Returns a string composed of multiples of a substring passed to it
(2) CramString() -- Returns a length-limited string compose of multiple substrings passed to it
(3) MCaseAll() -- Returns a string where MCase does only its capitalization
(4) MCase() -- Returns a string where MCase accepts most capitalization already done

Code: Select all

#AlNum = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

Procedure.s MultiString(text.s, many.l)
  Define.s temp
  If Len(text) = 0 Or many<1
    ProcedureReturn ""
  ElseIf many = 1
    ProcedureReturn text
  EndIf
  temp=Space(Len(text)*many)
  ProcedureReturn ReplaceString(temp, Space(Len(text)),text)
EndProcedure

Procedure.s CramString(text.s, length,l)
  Define temp.s
  If Len(text) = 0 Or length < 1
    ProcedureReturn ""
  EndIf
  temp = text
  While Len(temp) < length 
    temp + temp
  Wend
  ProcedureReturn Left(temp,length)
EndProcedure

Procedure.s MCaseAll(text.s)
  Define.l a
  Define.s aa, bb, cc
  aa = UCase(Left(text,1))+LCase(Mid(text,2)) ; force lowercase first
  For a = 1 To Len(aa)-1
    bb = UCase(Mid(aa,a,1))
    If FindString(#AlNum,bb) = 0
      cc = UCase(Mid(aa,a+1,1))
      If FindString(#AlNum,cc)
        aa = Left(aa,a) + cc + Mid(aa,a+2)
      EndIf
    EndIf
  Next
  ProcedureReturn aa
EndProcedure

Procedure.s MCase(text.s)
  Define.l a
  Define.s aa, bb, cc
  aa = UCase(Left(text,1))+Mid(text,2)      ; retain existing case where already set
  For a = 1 To Len(aa)-1
    bb = UCase(Mid(aa,a,1))
    If FindString(#AlNum,bb) = 0
      cc = UCase(Mid(aa,a+1,1))
      If FindString(#AlNum,cc)
        aa = Left(aa,a) + cc + Mid(aa,a+2)
      EndIf
    EndIf
  Next
  ProcedureReturn aa
EndProcedure

aa.s = MultiString(" This is a test. ",10)
bb.s = Space(99)+MultiString("1",100)+MultiString("2",160)
cc.s = Space(9)
For a.l = 1 To 26
  cc + MultiString(Str(Mod(a,10)),10)
Next
dd.s = MultiString("1234567890",25)
Debug aa
Debug Left(bb,Len(aa))
Debug Left(cc,Len(aa))
Debug Left(dd,Len(aa))
a = Int(Len(aa)/26)
b.l = 1
Repeat
  ee.s = Left(Space(a+a*b)+MultiString(Chr(64+b),a),Len(aa))
  Debug ee
  b+1
Until b>26

aa = "tHIS sHOULD blOW yOUR mIND!"
Debug aa + "  " + MCase(aa) + "  "  + MCaseAll(aa)
But, in running my code, it appears I got the Debug Output window screwed up the other night.
Trying yo see the Debug Window in small size as part of my Debug effort, while walking my code, I got it to go down to a small size. Fine for then. But now I want it back full screen, and I don't know how I got it small to start with. Maybe someone can tell me how to do it.
has-been wanna-be (You may not agree with what I say, but it will make you think).
oldefoxx
Enthusiast
Enthusiast
Posts: 532
Joined: Fri Jul 25, 2003 11:24 pm

Re: What INC From N to M in Exactly S Steps?

Post by oldefoxx »

Instead of using a different compiler to see how accurate Pow(1000000/500,1/14) could be computed to, I decided to see what any online calculators might say on the matter. There are quite a few out there, but some just don't work well. And how any calculator can be classified as "scientific" when it does not even recognize a set of parentheses is beyond me. Anyway, here are the results:

Code: Select all

1.7210276859903135            # https://my.hrw.com/math06_07/nsmedia/tools/Sci_Calculator/Sci_Calculator.html
1.72102768599029
1.72102768599
1.721027686                   # Results from other so-called "Scientific Calculators" visited online to find
1.72102768599                 # the most accurate answer to the question of r = Pow(n/m,1/i), when n = 1000000
1.72102768599                 # (the final value), m = 500 (the initial value), and i = 14 (the number of steps
1.72102768599031              # to go from m to n in precisw increments using r as the multiplier for each step.
1.72102768599031              # The more digits returned, the more accurate the calculations.  This can be
1.721027686                   # important when the number of steps indicated does not work well with the givens
1.72102768599031              # for n and m.  Extended precision makes it more likely that you will hit n on
1.72102768599031              # the nose.  Round offs to the nearest cent at each step is of course necesary.
1.721
1.7
1.72102768599031364461       # https://keisan.casio.com/calculator
1.7210276859903135           # RPN Method:  http://http://icrank.com/data/calculator/calc_app.htm
1.7210276859903135           # JavaScript RPN:  http://www.cfd-online.com/Tools/rpncalc.html
1.7210276859903135           # RPN - Allows Copy & paste: http://www.arachnoid.com/lutusp/calculator.html 
The thing about online calculators is that they can be handy, and some can be reversed engineered into usable code in your own language of preference. You can also learn why some people prefer RPN with a four-tiered stack. Now there is nothing that limits you to four tiers except convention. If you were to write out code in a RPN sequence, a comma might act for an ENTER key. You would have to come up with something else for flipping the contents of x and y, or loading and saving variables in mid-course.

The added stack tiers are reference by letters in reverse order from the initial two. That leaves z dangling. It could be thought of as a holding register I guess. Makes for interesting mind games. The vertical bar could be used to exchange two registers, such as x|y, or x|z, while the & symbol between two registers like v&w means copy w's contents into v. You could use variables. constants, and expressions on the right side of &, but only only variables and stack elements on the left side. Only variables and stack elements can be on either side of |.

A problem with RPN is that it only extends to numbers, and these of a given type. The return to the symbols of Basics of the past to represent different types of variables and constants might have to be allowed for. They may actually refer to indexes in different tables, each for a given type, as this would mean that the stack only has to support a reference to a table of types and items that currently exist on the stack. The trick is, to get the final reference down to numeric form that tacks back to the type, name of variable, constant, or expression involved in creating the type, and so on, until it all pieces together. Gets rather hairy when you think about it.

I know it can be done, because Nortel uses this type of logic in its DMS programming. I doubt that they are the only ones.
has-been wanna-be (You may not agree with what I say, but it will make you think).
Post Reply