If you had an Apple II, it was common in BASIC to reference memory locations above the 32K point by using a negative number. For example, if you wanted to click the speaker you would PEEK/POKE -16336 or if you wanted to enter the Apple II monitor, a CALL -768. Respectively, those would be 49200 ($C030) and 64568 ($FC38).

On the Commodore 64 by contrast, it was common to reference similar memory locations by their absolute value, e.g. the background color could be retrieved with a PEEK(53281) and many SYS calls were documented with non-negative numbers.

Given that many of the 8-bit BASIC implementations were derived from a common Microsoft code base, it is curious why the two conventions were used. I would have thought that it was perhaps something as simple as that a few cycles would be saved by specifying the negative number (or not, depending on who was right), but then again the negative sign introduces an additional character to process and also that big about common heritage.

What was the reason for the two conventions?

  • 1
    signed / unsigned types maybe? – Jean-François Fabre Jan 29 '20 at 13:34
  • 9
    "the negative sign introduces an additional character to process": that would only be the case if they were stored as text. Often BASIC was tokenised (e.g. 1 byte to represent a command, rather than one byte per letter in the displayed text representation of that command). Similarly integers could be stored in binary (e.g. two bytes to represent 32767 rather than 5 bytes to represent each of the decimal digits). The signing is just a convention - i.e. two-byte numbers can represent either 0 to 65535 or -32768 to + 32767 equally well. – Michael MacAskill Jan 29 '20 at 22:29
  • @MichaelMacAskill: Microsoft-derived BASIC implementations like Applesoft store numbers as text. – supercat Jan 30 '20 at 3:13
  • 2
    The Amstrad CPC allowed both signed and unsigned 16 bit integers. Memory could be PEEKed and POKEd with integers from -32768 to 65535, with a large overlap of values. – CJ Dennis Jan 30 '20 at 10:17
  • Underneath BASIC, the Branch instructions (on the 6502 CPU in the Apple II and Commodore 64 you mention) use negative numbers, to indicate relative branching to a memory address lower than the current instruction. This could be considered a precedence for their use in some flavours of BASIC, especially for CALL. – Kaz Jan 31 '20 at 10:14

The difference between Applesoft BASIC and the other Microsoft 6502 BASIC derivatives can be explained by the fact that Applesoft BASIC was not the first BASIC for the Apple II; the first was Apple II Integer BASIC, in turn derived from Apple I BASIC, which had been independently created by The Woz. Integer BASIC supported only 16-Bit signed integers as a numeric data type, so no positive numbers beyond 215-1 = 32767 decimal = $7FFF hex were available, necessitating the use of negative numbers for higher addresses.

When Apple adapted the Microsoft 6502 BASIC core to their machines to quickly meet the demand for a floating-point capable BASIC, they did some changes to the code base to somewhat increase source code compatibility with the (very different) Integer BASIC core. One of them was that they allowed (but no longer required) the use of negative numbers to represent addresses beyond 32767. It was probably just inertia that kept people using the old notation with negative numbers, that and the fact that e.g. CALL -151 for entering the monitor was easier to remember than the now equally valid CALL 65385.

Commodore, on the other hand, used the Microsoft 6502 BASIC code pretty much as-is for their early PET models and also for the VIC-20 and the C64.

  • 6
    Inertia is a good word here. I like it, and it makes perfect sense. Apple II users were simply accustomed to -151 from Integer BASIC - as well as Apple employee, which moved this over to Applesoft manuals. It's safe to assume noone ever thought about changing this. – Raffzahn Jan 29 '20 at 20:51

In some BASICs integers were signed 16-bit values, so there was no integer higher than 32767. Thus, if you wanted a 16-bit value of $FFFF in an integer variable,you'd have to specify it as -1. You can see this in Commodore 64 BASIC V2:




That said, the C64 SYS didn't actually take an integer parameter; it appears to have taken a positive floating point number and done some conversion on it. (Or perhaps it didn't use the internal integer or FP formats at all.) Thus, not only can you call it with positive values higher than 32767, such as SYS 64738 to reset the machine, but you can't call it with negative numbers, such as SYS -798, as you could with CALL on the Apple II.

I very much doubt any of this was much about saving a few processing cycles; BASIC was so slow that anybody that concerned about performance would be moving at least part of his code to machine language, anyway. But especially without modern tooling a BASIC was a large program that was difficult to write, so developers would often take whatever convenient shortcuts came to hand based on what routines were available elsewhere in the code.

  • MS-BASIC could have almost certainly been made a lot faster if it had treated a floating-point value whose exponent byte was zero as a signed integer, and included function so that values that could be processed as signed integers, would be (with those that couldn't being performed on freshly-converted floats). – supercat Jan 30 '20 at 0:09

Long story short: some BASICs have "two-byte signed integers" all around, so they can work only with numbers between -32768 and +32767. Other BASICs have their own format of numbers (e.g. Sinclair's ZX Spectrum BASIC - it uses 5 bytes to store a simple integer, so it can be -65535..65535).

In the second case, it is up to the BASIC interpreter developer, which kind of number allows for PEEK, POKE and similar commands (e.g. SYS). There are some design decisions: convert FP to INT, or use only two-byte INT? Convert the negative number to 65536+x, or let it be? The reasons were quite subtle: shorter code, easy manipulating, lazy developer, human error, deadline upcoming, etc.

  • 1
    ZX Spectrum BASIC used 5 bytes to store a floating-point value, unless the first byte was zero, in which case the next three bytes were a sign-extended 17-bit integer, with interesting behaviour for -65536 which was supposed to be represented in floating point, but certain functions would try to use it anyway. – Neil Feb 1 '20 at 11:42

Because Microsoft BASIC didn't support hexadecimal constants until Revision 5 in 1981, and so early derivatives (Commodore, Applesoft, …) didn't either . It would have been more convenient and clearer to use the &h notation (or &, as used in BBC and Locomotive BASICs) had it been available.

  • Many programs could have been easier to write, more compact, and faster-starting with the aid of a "stuff-hex" function that would accept an address and a string containing an even number of characters, interpret pairs of characters as hex bytes, and place them in memory. It seems curious that, if nothing else, magazine editors didn't standardize on a "stuff-hex" function that could be poked into memory using a read-data loop, allowing all of the other data a program needed to be stuffed from hex strings rather than read as individual digits. – supercat Feb 3 '20 at 0:05
  • COMPUTE! kind of did with [MLX](en.wikipedia.org/wiki/MLX_(software%29) listings – scruss Feb 12 '20 at 0:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.