f



A Fascinating Resource for Programmers

The Rosettacode site - https://rosettacode.org/wiki/Category:BBC_BASIC
has a category dedicated to BBC BASIC. The version I am talking about
of course is Richard Russell's excellent BBC BASIC for Windows. The
site lists a huge resource of BASIC programs arranged in alphabetic
order. Quite a few will work in RISC OS BASIC unmodified and others
need some simple tweaks to make then run. This is one of the best
resources available for beginners. It contains some superb examples of
string algorithms based on functions (DEF FN).

I'm assuming that Richard wrote a significant number of them.

There are some very nice features in the Windows version. Its a shame
RISC OS users don't have the EXIT keyword for use in loops for
example.

Some of the examples require libraries which I believe are only
available by purchasing BBC BASIC for Windows..

Some examples...

Fractual tree, Greatest element of a list, Leap year, Metronome, Old
lady swallowed a fly, Ordered words, Palindrome detection, Pangram
checker, Pascal's triangle (one of my favourites - so simple and
cleverly programmed), Reverse a string, Roman numerals/Decode/Encode,
Siepinski triangle.

Each project (537 when I last looked) is coded in numerous other
languages (C, C++, Lua, Python might interest RISC OS users) -
fascinating for programming geeks ;-) Anyone tell me why so many?

Richard

0
Richard
9/11/2016 12:00:55 PM
comp.sys.acorn.programmer 2499 articles. 0 followers. Post Follow

12 Replies
237 Views

Similar Articles

[PageSpeed] 33

Richard Ashbery wrote:
> The Rosettacode site -
> https://rosettacode.org/wiki/Category:BBC_BASIC has a category
> dedicated to BBC BASIC. The version I am talking about of course is
> Richard Russell's excellent BBC BASIC for Windows. The site lists a
> huge resource of BASIC programs arranged in alphabetic order. Quite
> a few will work in RISC OS BASIC unmodified and others need some
> simple tweaks to make then run. This is one of the best resources
> available for beginners. It contains some superb examples of string
> algorithms based on functions (DEF FN).

It is interesting, although I have identified some routines that are
less than optimal lurking there.

As an example, here is the Leap Year function you mention:

DEFFNleap(yr%)
= (yr% MOD 4 = 0) AND ((yr% MOD 400 = 0) OR (yr% MOD 100 <> 0))

That requires all the conditions to be evaluated before combining them.

Contrast with:

DEFFNleap(yr%)
  IF yr% MOD 400 ELSE =TRUE
  IF yr% MOD 100 ELSE =FALSE
  IF yr% MOD 4   ELSE =TRUE
=FALSE

That runs about 25% faster for the non-leap-year case, but more than 50%
for the 400 year case. I also think it has more clarity.

> I'm assuming that Richard wrote a significant number of them.

I think so. He originally drew my attention to the site.

> Its a shame RISC OS users don't have the EXIT keyword for use in
> loops for example.

I wrote a simple version of that for Basalt with ARM BASIC a very long
time ago, before that was in BB4W, I think.

However, it is relatively easy to arrange a program to exit a loop by 
enclosing within a PROC.

> Reverse a string

This is another that is less than optimal:

DEFFNreverse(A$)
  LOCAL B$, C%
  FOR C% = LEN(A$) TO 1 STEP -1
    B$ += MID$(A$,C%,1)
  NEXT
=B$

Continuously incrementing a string in this way is not efficient in BASIC.

This alternative requires a 256-byte buffer at b% to exist, which will
usually be the case in wimp programs, or it could be a DIM LOCAL in RISC 
OS 5:

DEFFNreverse(a$)
  LOCAL i%,j%,l%
  $b%=a$
  l%=LEN$b%:j%=b%+l%
  FOR i%=b% TO b%+l%/2
   j%-=1
   SWAP ?i%,?j%
  NEXT i%
=$b%

For short strings there is only a few percent advantage, but for longer
strings, of say 50 characters, it is at least twice as fast.

I have recently added this facility to SWAP$ in Basalt, but not 
released. It is at least 20 times as fast. ;-)
0
Steve
9/11/2016 3:58:49 PM
On 11/09/16 16:58, Steve Drain wrote:
> Richard Ashbery wrote:

[Referring to the rosettacode.org site]

>> Reverse a string

> This is another that is less than optimal:
>
> DEFFNreverse(A$)
>  LOCAL B$, C%
>  FOR C% = LEN(A$) TO 1 STEP -1
>    B$ += MID$(A$,C%,1)
>  NEXT
> =B$

> Continuously incrementing a string in this way is not efficient in BASIC.

> This alternative requires a 256-byte buffer at b% to exist, which will
> usually be the case in wimp programs, or it could be a DIM LOCAL in RISC
> OS 5:

If you're going to offer up a routine that relies on an externally 
allocated block, that block ought to be an argument to the definition - 
so it should be DEFFNreverse(a$,b%)

In either case some kind of sanity check should be performed - the 
caller could accidentally put something that evaluates to zero there, 
for example. However, even with some decent checking, something that 
isn't a pointer at all could be passed.

But at least if the value is passed as an argument, it prompts the 
programmer to *consider* what that argument should be.


> DEFFNreverse(a$)
>  LOCAL i%,j%,l%
>  $b%=a$
>  l%=LEN$b%:j%=b%+l%
>  FOR i%=b% TO b%+l%/2
>   j%-=1
>   SWAP ?i%,?j%
>  NEXT i%
> =$b%

I like that one of the comments you made about the leap year alternative 
you offered is that it's clearer - then you go and offer *that* for the 
string reverse function.

Okay, it's clear to me - and a lot reading this group I should think, 
but still... p: !cinorI

-- 
Vince M Hudd
Soft Rock Software
0
Vince
9/11/2016 7:08:30 PM
On 11 Sep, Vince M Hudd wrote in message
    <CNGdnQ5NNc0yNkjKnZ2dnUU78TnNnZ2d@giganews.com>:

> On 11/09/16 16:58, Steve Drain wrote:
> > Richard Ashbery wrote:
> 
> [Referring to the rosettacode.org site]
> 
> > > Reverse a string
> 
> > This is another that is less than optimal:
> >
> > DEFFNreverse(A$)
> >  LOCAL B$, C%
> >  FOR C% = LEN(A$) TO 1 STEP -1
> >    B$ += MID$(A$,C%,1)
> >  NEXT
> > =B$
> 
> > Continuously incrementing a string in this way is not efficient in
> > BASIC.

True. On a quick test, using a Beagleboard to reverse a string 100,000
times, this takes ~235cs.

But you could avoid that by doing

DEFFNreverse(A$)
 LOCAL B$, C%, D%
 B$ = STRING$(LEN(A$), " ")
 D% = 1
 FOR C% = LEN(A$) TO 1 STEP -1
   MID$(B$,D%,1) = MID$(A$,C%,1)
   D% += 1
 NEXT
=B$

For the same test, this takes ~160cs.

> > This alternative requires a 256-byte buffer at b% to exist, which will
> > usually be the case in wimp programs, or it could be a DIM LOCAL in RISC
> > OS 5:
> 
> If you're going to offer up a routine that relies on an externally
> allocated block, that block ought to be an argument to the definition - so
> it should be DEFFNreverse(a$,b%)

[snip] 
 
> > DEFFNreverse(a$)
> >  LOCAL i%,j%,l%
> >  $b%=a$
> >  l%=LEN$b%:j%=b%+l%
> >  FOR i%=b% TO b%+l%/2
> >   j%-=1
> >   SWAP ?i%,?j%
> >  NEXT i%
> > =$b%

This method, using the global block, takes ~150cs.

And if you take into account Vince's not-unreasonable concern, and assume
RISC OS 5, you get this

DEFFNreverse(a$)
 LOCAL b%,i%,j%,l%
 DIM b% LOCAL 255
 $b%=a$
 l%=LEN$b%:j%=b%+l%
 FOR i%=b% TO b%+l%/2
  j%-=1
  SWAP ?i%,?j%
 NEXT i%
=$b%

which, including the local DIM, takes ~160cs.

-- 
Steve Fryatt - Leeds, England

http://www.stevefryatt.org.uk/
0
Steve
9/11/2016 8:10:50 PM
Vince M Hudd wrote:
> Steve Drain wrote:
>> This alternative requires a 256-byte buffer at b% to exist, which will
>> usually be the case in wimp programs, or it could be a DIM LOCAL in RISC
>> OS 5:
>
> If you're going to offer up a routine that relies on an externally
> allocated block, that block ought to be an argument to the definition -
> so it should be DEFFNreverse(a$,b%)

Yes, that was wrong. I was translating from using a DIM LOCAL. There is 
a trick that uses END for the buffer which I have used below. ;-)

>> DEFFNreverse(a$)
>>  LOCAL i%,j%,l%
>>  $b%=a$
>>  l%=LEN$b%:j%=b%+l%
>>  FOR i%=b% TO b%+l%/2
>>   j%-=1
>>   SWAP ?i%,?j%
>>  NEXT i%
>> =$b%
>
> I like that one of the comments you made about the leap year alternative
> you offered is that it's clearer - then you go and offer *that* for the
> string reverse function.

Agreed, that is not at all as clear as using string keywords, but you do 
gain speed. I dug these out from tests I did quite a long time ago 
without thinking. Perhaps some better-named variables would help:

DEFFNreverse(a$)
  LOCAL string%,ptr%,end%,length%
  string%=END:REM buffer at start of free space
  $string%=a$
  length%=LENa$
  end%=string%+length%
  FOR ptr%=string% TO string%+length%/2
   end%-=1
   SWAP ?ptr%,?end%
  NEXT ptr%
=$string%

I hope that helps. ;)

0
Steve
9/11/2016 8:26:20 PM
Steve Fryatt wrote:
> But you could avoid that by doing
>
> DEFFNreverse(A$)
>  LOCAL B$, C%, D%
>  B$ = STRING$(LEN(A$), " ")
>  D% = 1
>  FOR C% = LEN(A$) TO 1 STEP -1
>    MID$(B$,D%,1) = MID$(A$,C%,1)
>    D% += 1
>  NEXT
> =B$
>
> For the same test, this takes ~160cs.

Agreed. I had something very similar in my old tests, but for me the 
buffer method just shaved it. Using the MID$ pseudo-variable 
construction is often overlooked. Either beats multiple concatenations, 
especially as the target string gets longer.

0
Steve
9/11/2016 8:37:10 PM
In article <mpro.odcw1q01fvhzi01xk.news@stevefryatt.org.uk>,
   Steve Fryatt <news@stevefryatt.org.uk> wrote:
> On 11 Sep, Vince M Hudd wrote in message
>     <CNGdnQ5NNc0yNkjKnZ2dnUU78TnNnZ2d@giganews.com>:

> DEFFNreverse(A$)
>  LOCAL B$, C%, D%
>  B$ = STRING$(LEN(A$), " ")
>  D% = 1
>  FOR C% = LEN(A$) TO 1 STEP -1
>    MID$(B$,D%,1) = MID$(A$,C%,1)
>    D% += 1
>  NEXT
> =B$

> For the same test, this takes ~160cs.

To my mind it is much easier to see what the original Rosettacode is
doing because only two string keywords LEN and MID$ are used. It may
be slower but dead simple to understand. Steve - I know your example
works but can you explain... MID$(B$,D%,1) = MID$(A$,C%,1)

My feeling is that Richard (the other one) wanted to keep the examples
simple to the point where anyone with some BASIC knowledge can
understand the code without REMs. Speed was not an issue. You can come
back to them months in the future and still have some understanding
what they do. Have a look at Pascal's Triangle - a single line...
acc% = acc% * (row - element%) / element%
performs the calculation for all rows - this is a superb example of
'KISS'. Not sure about the + 0.5 on the end - I just deleted it.


> And if you take into account Vince's not-unreasonable concern, and assume
> RISC OS 5, you get this

> DEFFNreverse(a$)
>  LOCAL b%,i%,j%,l%
>  DIM b% LOCAL 255
>  $b%=a$
>  l%=LEN$b%:j%=b%+l%
>  FOR i%=b% TO b%+l%/2
>   j%-=1
>   SWAP ?i%,?j%
>  NEXT i%
> =$b%

> which, including the local DIM, takes ~160cs.

Harder for a beginner to understand though.

Richard

0
Richard
9/13/2016 5:19:24 PM
In article <55bde9548ebasura@invalid.addr.uk>,
   Richard Ashbery <basura@invalid.addr.uk> wrote:
> The Rosettacode site - https://rosettacode.org/wiki/Category:BBC_BASIC
> has a category dedicated to BBC BASIC. The version I am talking about
> of course is Richard Russell's excellent BBC BASIC for Windows. The
> site lists a huge resource of BASIC programs arranged in alphabetic
> order. Quite a few will work in RISC OS BASIC unmodified and others
> need some simple tweaks to make then run. This is one of the best
> resources available for beginners. It contains some superb examples of
> string algorithms based on functions (DEF FN).

> I'm assuming that Richard wrote a significant number of them.

I love this site and regularly use it as a source of inspiration for other
stuff.

I added some of the BBC BASIC sorting routines. (And also the same
routines in Cobol!)

I've still got a few I should add, just never got a round tuit.

Dave

-- 
Dave Stratford - ZFCB
http://daves.orpheusweb.co.uk/

0
Dave
9/13/2016 8:36:44 PM
On 13 Sep, Richard Ashbery wrote in message
    <55bf0e2903basura@invalid.addr.uk>:

> In article <mpro.odcw1q01fvhzi01xk.news@stevefryatt.org.uk>,
>    Steve Fryatt <news@stevefryatt.org.uk> wrote:
> > On 11 Sep, Vince M Hudd wrote in message
> >     <CNGdnQ5NNc0yNkjKnZ2dnUU78TnNnZ2d@giganews.com>:
> 
> > DEFFNreverse(A$)
> >  LOCAL B$, C%, D%
> >  B$ = STRING$(LEN(A$), " ")
> >  D% = 1
> >  FOR C% = LEN(A$) TO 1 STEP -1
> >    MID$(B$,D%,1) = MID$(A$,C%,1)
> >    D% += 1
> >  NEXT
> > =B$
> 
> > For the same test, this takes ~160cs.
> 
> To my mind it is much easier to see what the original Rosettacode is doing
> because only two string keywords LEN and MID$ are used. It may be slower
> but dead simple to understand.

Possibly. I'd argue that my version deals with the other Steve's concern
about reallocating string variables while being considerably more readable
than his solution, however.

> Steve - I know your example works but can you explain...
> MID$(B$,D%,1) = MID$(A$,C%,1)

When assigned to, LEFT$(), MID$() and RIGHT$() allow you to overwrite
specific parts of a string. In the example above, you're taking the
right-most character of the original and placing it in the left-most
position of the result. You then step one position in from each end, and
repeat...

At the start, after calling FNreverse("ABCDEFG"),

                A$="ABCDEFG" and B$="       "
after 1 cycle,  A$="ABCDEFG" and B$="G      "
after 2 cycles, A$="ABCDEFG" and B$="GF     "
and so on.

The key point is that B$ is initialised to the required length with spaces
and then always remains the same length, which means that after being
allocated there's no time wasted shuffling memory around. In the Rosetta
original, this happens instead:

                A$="ABCDEFG" and B$=""
after 1 cycle,  A$="ABCDEFG" and B$="G"
after 2 cycles, A$="ABCDEFG" and B$="GF"
and so on.

Each cycle, B$ gets one character longer, which is one of the worst things
that you can ask BBC BASIC to do.

Does it matter? Probably not (although you might be surprised how much
little performance gains can make a difference). I was responding to Steve's
suggestion that indirection was the way forward, however.

> Not sure about the + 0.5 on the end - I just deleted it.

That's probably quite important, actually. It's also a very common idiom in
BASIC, and incredibly useful in many places -- so well worth understanding.

  acc% = acc% * (row% - element%) / element% + 0.5

acc% * (row% - element%) / element% is going to be a floating point value
due to the division. Assigning it to acc% clearly turns it back into an
integer, and that's a shorthand way of saying

  acc% = INT(acc% * (row% - element%) / element% + 0.5)

HELP INT tells us that INT() "gives us the nearest integer less than or
equal to the number. So while INT(n) rounds down from n, INT(n + 0.5) rounds
n to the nearest integer.

It's probably clearest with an example:

  FOR value = 0 TO 2 STEP 0.1
    PRINT value, INT(value), INT(value + 0.5)
  NEXT value

When run, that gives us

         0         0         0
       0.1         0         0
       0.2         0         0
       0.3         0         0
       0.4         0         0
       0.5         0         1
       0.6         0         1
       0.7         0         1
       0.8         0         1
       0.9         0         1
         1         1         1
       1.1         1         1
       1.2         1         1
       1.3         1         1
       1.4         1         1
       1.5         1         2
       1.6         1         2
       1.7         1         2
       1.8         1         2
       1.9         1         2

> > And if you take into account Vince's not-unreasonable concern, and
> > assume RISC OS 5, you get this
> 
> > DEFFNreverse(a$)
> >  LOCAL b%,i%,j%,l%
> >  DIM b% LOCAL 255
> >  $b%=a$
> >  l%=LEN$b%:j%=b%+l%
> >  FOR i%=b% TO b%+l%/2
> >   j%-=1
> >   SWAP ?i%,?j%
> >  NEXT i%
> > =$b%
> 
> > which, including the local DIM, takes ~160cs.
> 
> Harder for a beginner to understand though.

That was kind of the point of my original post... ;-)

-- 
Steve Fryatt - Leeds, England

http://www.stevefryatt.org.uk/
0
Steve
9/13/2016 11:15:59 PM
In article <mpro.odgtya07al2bi01wh.news@stevefryatt.org.uk>,
   Steve Fryatt <news@stevefryatt.org.uk> wrote:
> On 13 Sep, Richard Ashbery wrote in message

[snip]

> > > DEFFNreverse(A$)
> > >  LOCAL B$, C%, D%
> > >  B$ = STRING$(LEN(A$), " ")
> > >  D% = 1
> > >  FOR C% = LEN(A$) TO 1 STEP -1
> > >    MID$(B$,D%,1) = MID$(A$,C%,1)
> > >    D% += 1
> > >  NEXT
> > > =B$
> >
> > > For the same test, this takes ~160cs.
> >
> > To my mind it is much easier to see what the original Rosettacode is doing
> > because only two string keywords LEN and MID$ are used. It may be slower
> > but dead simple to understand.

> Possibly. I'd argue that my version deals with the other Steve's concern
> about reallocating string variables while being considerably more readable
> than his solution, however.

Now I see what you're program is doing I agree.

> > Steve - I know your example works but can you explain...
> > MID$(B$,D%,1) = MID$(A$,C%,1)

> When assigned to, LEFT$(), MID$() and RIGHT$() allow you to overwrite
> specific parts of a string. In the example above, you're taking the
> right-most character of the original and placing it in the left-most
> position of the result. You then step one position in from each end, and
> repeat...

> At the start, after calling FNreverse("ABCDEFG"),

>                 A$="ABCDEFG" and B$="       "
> after 1 cycle,  A$="ABCDEFG" and B$="G      "
> after 2 cycles, A$="ABCDEFG" and B$="GF     "
> and so on.

> The key point is that B$ is initialised to the required length with spaces
> and then always remains the same length, which means that after being
> allocated there's no time wasted shuffling memory around. In the Rosetta
> original, this happens instead:

>                 A$="ABCDEFG" and B$=""
> after 1 cycle,  A$="ABCDEFG" and B$="G"
> after 2 cycles, A$="ABCDEFG" and B$="GF"
> and so on.

> Each cycle, B$ gets one character longer, which is one of the worst things
> that you can ask BBC BASIC to do.

> Does it matter? Probably not (although you might be surprised how much
> little performance gains can make a difference). I was responding to Steve's
> suggestion that indirection was the way forward, however.

Many thanks for taking time to explain this - I was in a bit of a fog
- which seems more common these days. I can see that with a very large
string this could have a significant impact on the calculation speed.
I hadn't twigged that the B$ unnecessarily 'accumulates' the
characters each time through the loop in Richard's code and your
example is a neat way of preventing this.

> > Not sure about the + 0.5 on the end - I just deleted it.

> That's probably quite important, actually. It's also a very common idiom in
> BASIC, and incredibly useful in many places -- so well worth understanding.

>   acc% = acc% * (row% - element%) / element% + 0.5

> acc% * (row% - element%) / element% is going to be a floating point value
> due to the division. Assigning it to acc% clearly turns it back into an
> integer, and that's a shorthand way of saying

>   acc% = INT(acc% * (row% - element%) / element% + 0.5)

> HELP INT tells us that INT() "gives us the nearest integer less than or
> equal to the number. So while INT(n) rounds down from n, INT(n + 0.5) rounds
> n to the nearest integer.

> It's probably clearest with an example:

>   FOR value = 0 TO 2 STEP 0.1
>     PRINT value, INT(value), INT(value + 0.5)
>   NEXT value

[snip interesting output]

So for a value of 1.9 the INT value is 1 but true value is 2. That's a
significant difference. Once again a thing I hadn't understood.

As a matter of interest it wouldn't actually make any difference in
Pascal's Triangle because the numbers are so big anyway but I take
your point and Richard was quite correct in taking it into
consideration.

Again Steve - many thanks for your explanations.

Richard

0
Richard
9/14/2016 7:57:45 PM
In message <55bfa07dc9basura@invalid.addr.uk>
 on 14 Sep 2016 Richard Ashbery  wrote:

> > > Not sure about the + 0.5 on the end - I just deleted it.
> 
> > That's probably quite important, actually. It's also a very common idiom in
> > BASIC, and incredibly useful in many places -- so well worth understanding.
> 
> >   acc% = acc% * (row% - element%) / element% + 0.5
> 
> > acc% * (row% - element%) / element% is going to be a floating point value
> > due to the division. Assigning it to acc% clearly turns it back into an
> > integer, and that's a shorthand way of saying
> 
> >   acc% = INT(acc% * (row% - element%) / element% + 0.5)
> 
> > HELP INT tells us that INT() "gives us the nearest integer less than or
> > equal to the number. So while INT(n) rounds down from n, INT(n + 0.5) rounds
> > n to the nearest integer.
> 
> > It's probably clearest with an example:
> 
> >   FOR value = 0 TO 2 STEP 0.1
> >     PRINT value, INT(value), INT(value + 0.5)
> >   NEXT value
> 
> [snip interesting output]
> 
> So for a value of 1.9 the INT value is 1 but true value is 2. That's a
> significant difference. Once again a thing I hadn't understood.
> 
> As a matter of interest it wouldn't actually make any difference in
> Pascal's Triangle because the numbers are so big anyway but I take
> your point and Richard was quite correct in taking it into
> consideration.

On the contrary, it is when the numbers get big that the rounding errors are
more likely to occur because of the limited number of bits available in the
mantissa in floating point arithmetic.  As it happens, it makes no difference
on BBC BASIC V on RISC OS because the numbers get too large for 32-bit
integers before any rounding errors come into play.

It might make a difference in BASIC VI, or it might help if you wanted to go
to very high numbers of rows by using floating point throughout the program.

The answer, of course is always supposed to be an integer. If the floating
point result is very slightly under, the +0.5 would help set it straight.

-- 
Matthew Phillips
Durham
0
Matthew
9/14/2016 10:49:21 PM
Steve Drain wrote:
> Steve Fryatt wrote:
>> But you could avoid that by doing
>>
>> DEFFNreverse(A$)
>>  LOCAL B$, C%, D%
>>  B$ = STRING$(LEN(A$), " ")
>>  D% = 1
>>  FOR C% = LEN(A$) TO 1 STEP -1
>>    MID$(B$,D%,1) = MID$(A$,C%,1)
>>    D% += 1
>>  NEXT
>> =B$
>>
>> For the same test, this takes ~160cs.
>
> Agreed. I had something very similar in my old tests, but for me the
> buffer method just shaved it. Using the MID$ pseudo-variable
> construction is often overlooked. Either beats multiple concatenations,
> especially as the target string gets longer.

I could have sworn that in my original tests I got figures similar to 
yours. I returned to look again and found that the method above, or my 
variant of it, comes out even slower than the concatenation method on my 
AMX6, with BASIC V v1.59. I cannot explain that. ;-(

0
Steve
9/16/2016 9:21:57 AM
Richard Ashbery wrote:
> To my mind it is much easier to see what the original Rosettacode is
> doing because only two string keywords LEN and MID$ are used. It may
> be slower but dead simple to understand. [...]
>
> My feeling is that Richard (the other one) wanted to keep the examples
> simple to the point where anyone with some BASIC knowledge can
> understand the code without REMs. Speed was not an issue. You can come
> back to them months in the future and still have some understanding
> what they do.

I think there is some merit in that, but my concern is that such a 
public example should not propagate poor programming techniques. 
Repeated concatenation is a poor technique in BASIC. Although it is not 
as clear, buffering a string and manipulating indirected bytes, however 
you achieve it, is a good technique that is easily available in BBC 
BASIC, but not in most others versions. I concede that the use of 
MID$()=, as in Steve Fryatt's example, should be the best choice in this 
case, except that I am now unsure of its speed - see my other post.

> Have a look at Pascal's Triangle - a single line...
> acc% = acc% * (row - element%) / element% + 0.5
> performs the calculation for all rows - this is a superb example of
> 'KISS'.

I disagree. That method might be a good choice if the task were just to 
print the Nth row of the triangle, but if you are constructing the whole 
triangle you are better following Pascal's rule and adding the elements 
from the row above. I wrote this method:

DEFPROCPascal(rows%)
  LOCAL wid%,@%,row%,num%,row%()
  DIM row%(rows%)
  wid%=3
  @%=wid%*2
  row%(1)=1
  FOR row%=1 TO rows%
   PRINT TAB(wid%*(rows%-row%));
   FOR num%=row% TO 1 STEP -1
    row%(num%)+=row%(num%-1)
    PRINT row%(num%);
   NEXT num%
  NEXT row%
  PRINT
ENDPROC

Returning to the site, I see that it is very similar to the generic 
BASIC method a little above the BBC BASIC one.

As for calculating the binomial coefficients in BBC BASIC V, an 
awareness of the increase in N! (factorial N) with N, and the limits of 
5-byte floating point numbers, leads to the fact that N! can only be 
expressed if N<=33. If a program is doing a lot of factorials, then 
constructing a look-up table is the best technique, rather than 
attempting to calculate N! with a - possibly recursive - function.

Basalt uses this for its FACT keyword to return N!, so it is very fast. 
It will also return nPr (permutations) and nCr (combinations). The 
latter are the binomial coefficients.

0
Steve
9/16/2016 9:59:33 AM
Reply: