DIM giving number too big

Discussions about the BBC BASIC language, with particular reference to BB4W and BBCSDL
jgharston
Posts: 37
Joined: Thu 05 Apr 2018, 14:08

DIM giving number too big

Post by jgharston »

I must be having a brain fart, I can't see what's going wrong (out of tea error?).

I've just installed BBC BASIC for SDL 1.40a on a new tablet (Galaxy Tab, Android 13), and running some existing code fails. I've isolated it to:

DIM mem% 65535
Number too big

Doing some checks reveals the heap is high up in memory compared to my other tablet and on Windows:
>PRINT ~HIMEM
EDB08C00
>PRINT ~LOMEM
EBB08D4A
>PRINT HIMEM-LOMEM
33554102
>*HEX64
>PRINT ~LOMEM
EBB08D4A
>mem%=LOMEM
Number too big
>mem%%=LOMEM
>PRINT ~mem%%
EBB08D4A

Is the DIM thinking it's trying to allocate memory at a negative location or something? It's not running into 64-bit addresses requiring %% variables.
Richard Russell
Posts: 272
Joined: Tue 18 Jun 2024, 09:32

Re: DIM giving number too big

Post by Richard Russell »

jgharston wrote: Fri 01 Nov 2024, 23:45 DIM mem% 65535
Number too big
DIM (used this way) allocates memory from the heap, the value it returns in the specified variable is a pointer (or address, if you prefer). Hence the variable must be of a type which can hold an arbitrary pointer, which in practice means either a suffixless variable or a 64-bit integer variable:

Code: Select all

      DIM mem 65535
      DIM mem%% 65535
It may be instructive to see what value is returned in your specific circumstances:

Code: Select all

      *HEX 64
      DIM mem%% 65535
      PRINT ~mem%%
I would expect that to confirm that the value it was trying to return in mem% was too big for a 32-bit integer.

If you are writing portable code, using the suffixless variable mem might be preferable, because whilst not all versions of BBC BASIC support 64-bit integers they all* should be able to store a pointer in such a variable.

* Matrix Brandy cannot hold an arbitrary 64-bit integer in a suffixless variable, but I think it should be able to hold any valid x86-64 pointer.
jgharston
Posts: 37
Joined: Thu 05 Apr 2018, 14:08

Re: DIM giving number too big

Post by jgharston »

>DIM MEM 65535:PRINT ~MEM
EBB08D5B
>DIM MEM%% 65535:PRINT ~MEM%%
EBB18D6C
>DIM MEM% 65535:PRINT ~MEM%
Number too big

(quit and restart)
*HEX64
>DIM MEM 65535:PRINT ~MEM
EBB08D5B
>DIM MEM%% 65535:PRINT ~MEM%%
EBB18D6C
>DIM MEM% 65535:PRINT ~MEM%
Number too big

(quit and restart)
*HEX32
>DIM MEM 65535:PRINT ~MEM
EBB08D5B
>DIM MEM%% 65535:PRINT ~MEM%%
EBB18D6C
>DIM MEM% 65535:PRINT ~MEM%
Number too big

Nothing is more than 32 bits, but are more than 31 bits. On my LG4 Android smartphone the values are 431D56, etc.

Changing all references of mem% to mem would be a huge job, as it would also require changing loads of other variables that reference mem%, such as err%=mem%+&FF00:base%=mem%+&100 ... load%=mem%!(r%(2)) ... src%=mem%?r%(7) etc, and rewriting loads of libraries $(mem%+X%)=FNdis(mem%?(X%+2),mem%!(X%+4)) etc.
Richard Russell
Posts: 272
Joined: Tue 18 Jun 2024, 09:32

Re: DIM giving number too big

Post by Richard Russell »

jgharston wrote: Sat 02 Nov 2024, 15:38 Nothing is more than 32 bits
Yes it is, with the qualifier that it must be a valid signed 32-bit number:

Code: Select all

*HEX64
>DIM MEM 65535:PRINT ~MEM
EBB08D5B
That's hexadecimal &00000000EBB08D5B which is not in the range of valid positive 32-bit numbers &0000000000000000-&000000007FFFFFFF nor of the negative 32-bit numbers &FFFFFFFF80000000-&FFFFFFFFFFFFFFFF.

Only when considered to be an unsigned 32-bit number is it in range, but BBC BASIC has no unsigned 32-bit data type!
Changing all references of mem% to mem would be a huge job
Within a single program (i.e. source code unit) it's a trivial global search-and-replace operation, which any half-decent IDE can do in a couple of seconds.

Admittedly if you have many files which need changing then it could indeed be a big job, in which case your option is not to change it and accept that your program isn't compatible with 64-bit platforms. There's no 'magic' that can make a 64-bit platform allocate memory only in the range that can be represented by a signed 32-bit address.

We should be grateful that Acorn was so forward-looking that they supported 32-bit integers from the start, even though there were probably no computers that needed a 32-bit address then. I think we can forgive them for not anticipating the need for 64-bit addresses in 1981!
Richard Russell
Posts: 272
Joined: Tue 18 Jun 2024, 09:32

Re: DIM giving number too big

Post by Richard Russell »

Richard Russell wrote: Sat 02 Nov 2024, 16:45 Only when considered to be an unsigned 32-bit number is it in range, but BBC BASIC has no unsigned 32-bit data type!
Traditionally (by which I mean the original Kemeny & Kurtz BASIC of 1964) numeric variables were not typed at all, there was just one numeric data type represented by a suffixless variable name, capable of holding either a floating-point number or an integer. My view has always been that this is how BASIC should have remained, and there are indeed some 'modern' BASICs which still adhere to this tradition, for example Liberty BASIC.

I know that the potential value of having multiple numeric data types is that it can reduce the storage requirements, especially of arrays. For example in BB4W and BBCSDL the array number(999) occupies 10000 bytes whereas the array number%(999) occupies only 4000 bytes, a worthwhile saving which becomes even more important with larger arrays.

So Acorn can be forgiven for including an integer data type in BBC BASIC, but life would have been easier in some respects if they hadn't. If there had been just one numeric type the problem of a 32-bit integer variable no longer being able to contain a pointer wouldn't have occurred, and there would have been no need to introduce 64-bit integers.

But we are where we are. At least, fortunately, we are in the position that every version of BBC BASIC (I think) can hold an arbitrary pointer in a suffixless numeric variable. This might not have been the case, had for example Acorn chosen to use a 32-bit floating-point format rather than 40-bits. Or had the x86-64 architecture not been limited to a 48-bit signed memory address.
jgharston
Posts: 37
Joined: Thu 05 Apr 2018, 14:08

Re: DIM giving number too big

Post by jgharston »

Richard Russell wrote: Sat 02 Nov 2024, 16:45
jgharston wrote: Sat 02 Nov 2024, 15:38 Nothing is more than 32 bits
Yes it is, with the qualifier that it must be a valid signed 32-bit number:
I thought it might be that, but I'm used to integers being able to reference 32-bit quantities regardless of what they are.

A work-around which looks workable is something like:
IF thing THEN
DIM mem%% memsz%:IF !(4+^mem%%) THEN PROCexit("Can't access 64-bit memory")
mem%=0:!^mem%=!^mem%%
ELSE
DIM mem% memsz%
ENDIF

Richard Russell wrote: Sat 02 Nov 2024, 16:45We should be grateful that Acorn was so forward-looking that they supported 32-bit integers from the start, even though there were probably no computers that needed a 32-bit address then.
Being able to reference more than just 64K needs 32-bit integers, and file sizes, even in 1981, are very easy to get past 64K.
Richard Russell
Posts: 272
Joined: Tue 18 Jun 2024, 09:32

Re: DIM giving number too big

Post by Richard Russell »

jgharston wrote: Sat 02 Nov 2024, 17:57 I'm used to integers being able to reference 32-bit quantities regardless of what they are.
Not in any version of BBC BASIC I know. Even in Sophie's original 6502 BASIC this results in an error (2^32 - 1 is the valid unsigned 32-bit number &00000000FFFFFFFF):

Code: Select all

> A = 2^32 - 1
> A% = A
Too big
A work-around which looks workable is something like:
DIM mem%% memsz%:IF !(4+^mem%%) THEN PROCexit("Can't access 64-bit memory")
I'm not sure what that is trying to achieve, but it will call PROCexit even in the case of a perfectly valid address at the top of memory which can be represented as a signed-32-bit number (I think all 64-bit processor architectures can allocate memory both at the bottom and the top of the valid pointer address range).
Being able to reference more than just 64K needs 32-bit integers, and file sizes, even in 1981, are very easy to get past 64K.
Acorn could have used 16-bit integer variables, many contemporary BASICs did. That wouldn't have limited file sizes or any other uses of larger numeric values since regular 'floating point' variables can contain any arbitrary integer value from -2^32 to +2^32 without loss, which encompasses all signed and unsigned 32-bit values.
jgharston
Posts: 37
Joined: Thu 05 Apr 2018, 14:08

Re: DIM giving number too big

Post by jgharston »

Hmmm... This is going to need another pot of tea...

DIM mem%% memsz%:mem%=0:!^mem%=!^mem%% (edited for conciseness)
...
esc%=&FF00:err%=&FF01
...
mem%?esc%=0
BANG!

That should be accessing location
00000000EBB08D5B
000000000000FF00 +
-----------------------
00000000EBB17D5B

but I bet it's ending up accessing a "negative" address.
FFFFFFFFEBB08D5B sign extended
000000000000FF00 +
-----------------------
FFFFFFFFEBB17D5B
jgharston
Posts: 37
Joined: Thu 05 Apr 2018, 14:08

Re: DIM giving number too big

Post by jgharston »

Richard Russell wrote: Sat 02 Nov 2024, 18:34
jgharston wrote: Sat 02 Nov 2024, 17:57 A work-around which looks workable is something like:
DIM mem%% memsz%:IF !(4+^mem%%) THEN PROCexit("Can't access 64-bit memory")
I'm not sure what that is trying to achieve, but it will call PROCexit even in the case of a perfectly valid address at the top of memory which can be represented as a signed-32-bit number (I think all 64-bit processor architectures can allocate memory both at the bottom and the top of the valid pointer address range).
An initial thought for a test for mem%% being outside the range &0000000000000000-&00000000FFFFFFFF by testing bit32-bit63 of mem%%.
Last edited by jgharston on Sat 02 Nov 2024, 18:59, edited 1 time in total.
Richard Russell
Posts: 272
Joined: Tue 18 Jun 2024, 09:32

Re: DIM giving number too big

Post by Richard Russell »

jgharston wrote: Sat 02 Nov 2024, 18:37 That should be accessing location
00000000EBB08D5B
000000000000FF00 +
-----------------------
00000000EBB17D5B
No, it "should be" (and is) accessing the location:

Code: Select all

FFFFFFFFEBB08D5B
000000000000FF00 +
----------------
FFFFFFFFEBB17D5B
We've already ascertained that mem% can contain only signed 32-bit values.