Saturation arithmetic

for discussion of bbc basic for windows/sdl, brandy and more
Post Reply
Deleted User 9295

Saturation arithmetic

Post by Deleted User 9295 »

I've been trying to work out a way of performing saturation arithmetic using whole-array operations in BBC BASIC (which is potentially much faster than looping through each element individually). This is the best I've managed to come up with, it takes an input array a%() containing values in the range -98300 to +98300 and saturates them to the range -32767 to +32767 (appropriate for 16-bit signed audio, for example):

Code: Select all

      t%() = a%() DIV &8000 
      t%() -= t%() DIV 2   
      t%() *= &7FFF
      a%() AND= t%() - 1
      a%() OR= t%()
This is between 3 and 5 times faster than a naïve FOR...NEXT loop, depending on the distribution of the data, but the benefit would be even greater if it could be simplified. I can't see any opportunity for doing that, but maybe a different set of eyes will spot something I've missed.
User avatar
TobyLobster
Posts: 618
Joined: Sat Aug 31, 2019 7:58 am
Contact:

Re: Saturation arithmetic

Post by TobyLobster »

Shouldn't this line

Code: Select all

a%() AND= t%() - 1 
be

Code: Select all

a%() AND= t%()
since (I think) the t% array contains either -&7fff, 0, or &7fff at this point?
I can't see anything faster though.
Deleted User 9295

Re: Saturation arithmetic

Post by Deleted User 9295 »

TobyLobster wrote: Mon Mar 15, 2021 12:23 pm Shouldn't this line

Code: Select all

a%() AND= t%() - 1 
be

Code: Select all

a%() AND= t%()
No. If you omit the - 1 you end up ANDing and ORing a%() with the same value, which can't work! That's easily seen in the t%() = 0 case (i.e. no saturation/clipping is required) when what you want to do is to AND a%() with &FFFFFFFF and OR it with &00000000 because that's the 'no change' condition.
User avatar
TobyLobster
Posts: 618
Joined: Sat Aug 31, 2019 7:58 am
Contact:

Re: Saturation arithmetic

Post by TobyLobster »

You are right that I'm wrong!

I'm now trying to follow the code through - suppose we have an input value in the a%() array of &8000:

Then "t%() = a%() DIV &8000" sets t%() to 1
Then "t%() -= t%() DIV 2" sets t%() to 1 still (since t%() DIV 2 is zero).
Then "t%() *= &7FFF" sets t%() to &7FFF

but then "a%() AND= t%() - 1" is ANDing with &7FFE which can't be right?

What am I missing?
Deleted User 9295

Re: Saturation arithmetic

Post by Deleted User 9295 »

TobyLobster wrote: Mon Mar 15, 2021 3:17 pm What am I missing?
The order of the AND and OR matters! In the specific example you gave, the input is &8000, it is first ANDed with &7FFE (giving zero) and then ORed with &7FFF (giving &7FFF) which is the correct answer.

You say ANDing with &7FFE "can't be right" but why not? The only requirement in that case is that the AND should zero bit 15 (changing &8000 to &0000) and ANDing with any value from &0000 to &7FFF will achieve that.

I've tested the code with every input value from -98300 to +98300 and it gives the correct result for every one:

Code: Select all

      DIM a%(9), t%(9)
      FOR I% = -98300 TO +98300
        a%() = I%

        t%() = a%() DIV &8000
        t%() -= t%() DIV 2
        t%() *= &7FFF
        a%() AND= t%() - 1
        a%() OR= t%()

        CASE TRUE OF
          WHEN I% < -32767: IF a%(0) <> -32767 STOP
          WHEN I% > +32767: IF a%(0) <> +32767 STOP
          OTHERWISE: IF a%(0) <> I% STOP
        ENDCASE
      NEXT
      PRINT "Tests completed successfully"
User avatar
TobyLobster
Posts: 618
Joined: Sat Aug 31, 2019 7:58 am
Contact:

Re: Saturation arithmetic

Post by TobyLobster »

Ah, thank you! For some reason my brain didn't click on this. You are right of course.
Deleted User 9295

Re: Saturation arithmetic

Post by Deleted User 9295 »

Given the importance of the whole-array operators in BBC BASIC (one of its most powerful features in my opinion) is there an online reference to the sorts of things you can do with them? I'm thinking of examples like solving simultaneous equations, curve fitting, 3D rotations, lighting calculations etc. which can typically be done much more quickly using array arithmetic than any other way in BASIC.

One thing I regularly want to do is to calculate the RMS (Root Mean Square) value of a set of numbers, but I always seem to have to work it out from scratch each time. If there's a handy place I could go to find these standard routines it would save time. For the record (and while I remember) this is the RMS calculation:

Code: Select all

      RMS = MOD(array()) / SQR(DIM(array(),1) + 1)
User avatar
cardboardguru
Posts: 239
Joined: Fri Mar 09, 2018 10:26 pm
Contact:

Re: Saturation arithmetic

Post by cardboardguru »

Seems like they'd be useful for implementing a particle system.
Deleted User 9295

Re: Saturation arithmetic

Post by Deleted User 9295 »

cardboardguru wrote: Tue Mar 16, 2021 6:02 pm Seems like they'd be useful for implementing a particle system.
Indeed. If you've seen my adaptation of David Williams' prizewinning Tyoob game the particles making up the 'tube' do use BBC BASIC's whole-array operations - without them I could never have animated it in BASIC. The in-browser version is here, but with the overhead of Web Assembly it needs a fast PC for good results. If you have a Mac you can't run the browser version in Safari (although you can in Vivaldi) in which case use the native version instead.
Post Reply

Return to “modern implementations of classic programming languages”