The DEF FN (DEFine FuNction) command can be used to add a total of 52 new functions to Sinclair BASIC; 26 numeric functions (A-Z) and 26 string functions (A$-Z$).

Owing to the internal structure of Sinclair BASIC, the best place to store these functions is in line 0. This prevents the line being accidentally edited or deleted and also gives the maximum possible speed (on a standard Spectrum with no Interface I attached, line 1 can be converted into line 0 with POKE 23756,0).

The more complicated or frequently called functions should be given the higher priority; for example, the MOD function should normally occur first.

Where possible, the following functions are compatible or partially compatible with their Beta BASIC equivalents. Some of the numeric functions are restricted to dealing with 8-bit numbers (0-255) while their Beta BASIC equivalents can handle 16-bit numbers. This is because dealing with 16-bit numbers in BASIC would be tortuously slow. Recursive functions can be constructed, but are avoided where possible (in order to permit compilation with HiSoft BASIC).

hex4$ = 4 digit hex string ("0000"-"FFFF") posint8 = 8-bit positive integer (0-255) posint16 = 16-bit positive integer (0-65535) string1 = non-null 1 character string string2 = 2 character string

A ROM bug, mentioned on


The FN error (from ZX Computing Monthly - Toni Baker)

When a user-defined function is evaluated the value of the system variable (CH_ADD) which stores the address of the next character to be interpreted, is saved on the machine stack instead of in one of the dynamic variables such as (X_PTR) during the evaluation of the function. This means that any user-defined function which causes the BASIC program area to move up or down in memory will cause error report C; Nonsense in BASIC. This is not normally possible, but exceptions can occur if the DEF FN statement contains the function USR, and could also conceivably happen with the function INKEY#X. To avoid this bug you must ensure that any machine code subroutine which is called by a DEF FN statement does not disturb the BASIC program area (e.g. it is impossible to define a function FN D (X,Y) which would delete BASIC lines X to Y inclusive without also manipulating the machine stack).

Keep this remark in mind especialy with DEF FN x()=USR adress or with creating a channel.

The characters used here are used as example but in some cases DEF FN can depend on other DEF FN when they are nested. This makes them more readable and in some cases faster. So if you copy them have a good look.

The EVEN(number, 0 or 1) can save a lot of space since it checks the last BIT of a number so:

the last bit-check of the AND FN logicly will hold as last part

(1 AND INT FN V(FN V(FN V(FN V(FN V(FN V(FN V(x,128),64),32),16),8),4),2)+INT FN V(FN V(FN V(FN V(FN V(FN V(FN V(y,128),64),32),16),8),4),2)=2)

which is replaced with

(1 AND FN e(x,1) + FN e(y,1)=2)

since it is in fact a Bit_0 check which is an ODD or EVEN check. This saves calculating time as well as space.

The characters used so far in this Wiki are:



AND(posint8,posint8): depends on FN v() and FN e(a,0 or 1)

DEF FN A(x,y)=(128 AND INT (x/128)+INT (y/128)=2)+(64 AND INT (FN V(x,128)/64)+INT (FN V(x,128)/64)=2)+ (32 AND INT (FN V(FN V(x,128),64)/32)+INT (FN V(FN V(y,128),64)/32)=2)+(16 AND INT (FN V(FN V(FN V(x,128),64),32)/16)+INT (FN V(FN V(FN V(y,128),64),32)/16)=2)+(8 AND INT (FN V(FN V(FN V(FN V(x,128),64),32),16)/8)+INT (FN V(FN V(FN V(FN V(y,128),64),32),16)/8)=2)+(4 AND INT (FN V(FN V(FN V(FN V(FN V(x,128),64),32),16),8)/4)+INT (FN V(FN V(FN V(FN V(FN V(y,128),64),32),16),8)/4)=2)+(2 AND INT (FN V(FN V(FN V(FN V(FN V(FN V(x,128),64),32),16),8),4)/2)+INT (FN V(FN V(FN V(FN V(FN V(FN V(y,128),64),32),16),8),4)/2)=2)+(1 AND FN e(x,1)+FN e(y,1)=2)


DEF FN B(b$)=VAL(CHR$ 196+b$)

BIN$(posint8) : depends on FN v() and FN e(a,0 or 1)

DEF FN B$(b)=STR$ INT (b/128)+STR$ INT (FN V(b,128)/64)+STR$ INT (FN V(FN V(b,128),64)/32)+STR$ INT (FN V(FN V(FN V(b,128),64),32)/16)+STR$ INT (FN V(FN V(FN V(FN V(b,128),64),32),16)/8)+STR$ INT (FN V(FN V(FN V(FN V(FN V(b,128),64),32),16),8)/4)+STR$ INT (FN V(FN V(FN V(FN V(FN V(FN V(b,128),64),32),16),8),4)/2)+STR$ e(b,1)


DEF FN C$(n)=CHR$ INT (n/256)+CHR$ (n-INT (n/256)*256)


DEF FN D(h$)=(CODE h$(1)-48-7*(h$(1)>"9"))*4096+(CODE h$(2)-48-7*(h$(2)>"9"))*256+(CODE h$(3)-48-7*(h$(3)>"9"))*16+CODE h$(4)-48-7*(h$(4)>"9")


DEF FN G(n)=n/PI*180


DEF FN P(a)=PEEK a+256*PEEK (a+1)

The companion DPOKE command can be implemented as follows:

POKE address,number-INT(number/256)*256:POKE address+1,INT(number/256)

EVEN(number, 0 or 1) ( or ODD(number, 0 or 1) )

DEF FN e(a,b)=((a/2 = INT(a/2)) AND NOT b)+((a/2<>INT(a/2)) AND b)


DEF FN F()=65536-USR 7962

or if you're using a custom ROM which doesn't have the free-mem routine:

DEF FN F()=(PEEK 23731*256)+PEEK 23730-((PEEK 23654*256)+PEEK 23653)-110

HEX$(posint16): depends on FN v()

DEF FN H$(n)=CHR$ (INT (n/4096)+7*(INT (n/4096)>9)+48)+CHR$ (INT (FN V(n,4096)/256)+7*(INT (FN V(n,4096)/256)>9)+48)+CHR$ (INT (FN V(FN V(n,4096),256)/16)+7*(INT (FN V(FN V(n,4096),256)/16)>9)+48)+CHR$ ((FN V(FN V(FN V(n,4096),256),16))+7*(INT FN V(FN V(FN V(n,4096),256),16)>9)+48)


DEF FN T()=(1 AND PEEK (1+FN P(23639))=34)+(2 AND PEEK (FN P(23639))>13 AND PEEK (1+FN P(23639))>34)


DEF FN L$(s$,l)=S$( TO l)


DEF FN W$(l$)=CHR$ ((CODE l$)+(32 AND CODE l$>64 AND CODE l$<92))


DEF FN M(x,y)=(x+y+ABS (x-y))/2


DEF FN A$(x$,y$)=(x$ AND x$>y$)+(y$ AND y$>=x$)


DEF FN M$(s$,s,l)=s$(s TO s-1+l)


DEF FN Q(x,y)=(x+y-ABS (x+y))/2


DEF FN Q$(x$,y$)=(x$ AND x$<y$)+(y$ AND y$<=x$)


DEF FN V(x,y)=x-y*INT (x/y)

NOT(posint8): depends on FN v()

DEF FN N(n)=(128 AND ABS (INT (n/128)-1))+(64 AND ABS (INT (FN V(n,128)/64)-1))+(32 AND ABS (INT (FN V(FN V(n,128),64)/32)-1))+(16 AND ABS (INT (FN V(FN V(FN V(n,128),64),32)/16)-1))+(8 AND ABS (INT (FN V(FN V(FN V(FN V(n,128),64),32),16)/8)-1))+(4 AND ABS (INT (FN V(FN V(FN V(FN V(FN V(n,128),64),32),16),8)/4)-1))+(2 AND ABS (INT (FN V(FN V(FN V(FN V(FN V(FN V(n,128),64),32),16),8),4)/2)-1))+(1 AND ABS (INT (FN V(FN V(FN V(FN V(FN V(FN V(FN V(n,128),64),32),16),8),4),2)-1))


DEF FN U(c$)=256*CODE c$(1)+CODE c$(2)

OR(posint8,posint8): depends on FN v()

DEF FN O(x,y)=(128 AND INT ((x/128) OR INT (y/128)=1))+(64 AND INT ((FN V(x,128)/64) OR INT (FN V(x,128)/64)=1))+(32 AND INT ((FN V(FN V(x,128),64)/32) OR INT (FN V(FN V(y,128),64)/32)=1))+(16 AND INT ((FN V(FN V(FN V(x,128),64),32)/16) OR INT (FN V(FN V(FN V(y,128),64),32)/16)=1))+(8 AND INT ((FN V(FN V(FN V(FN V(x,128),64),32),16)/8) OR INT (FN V(FN V(FN V(FN V(y,128),64),32),16)/8)=1))+(4 AND INT ((FN V(FN V(FN V(FN V(FN V(x,128),64),32),16),8)/4) OR INT (FN V(FN V(FN V(FN V(FN V(y,128),64),32),16),8)/4)=1))+(2 AND INT ((FN V(FN V(FN V(FN V(FN V(FN V(x,128),64),32),16),8),4)/2) OR INT (FN V(FN V(FN V(FN V(FN V(FN V(y,128),64),32),16),8),4)/2)=1))+1 AND INT (FN V(FN V(FN V(FN V(FN V(FN V(FN V(x,128),64),32),16),8),4),2) OR INT FN V(FN V(FN V(FN V(FN V(FN V(FN V(y,128),64),32),16),8),4),2)=1)


DEF FN R(n)=n/180*PI


DEF FN I(n)=INT (RND*(n+1))


DEF FN R$(s$,l)=s$(LEN s$+1-l TO LEN s$)


DEF FN S$(i,i$)=i$+VAL$ """""+FN s$(i-1,i$)"( TO 2+(12 AND i<>1))


DEF FN Z()=FN M(65536*PEEK 23674+256*PEEK 23673+PEEK 23672,65536*PEEK 23674+256*PEEK 23673+PEEK 23672)


DEF FN T$(n)=STR$ INT (n/1800000)+STR$ INT (FN V(n,1800000)/180000)+":"+STR$ INT (FN V(FN V(n,1800000),180000)/30000)+STR$ INT (FN V(FN V(FN V(n,1800000),180000),30000)/3000)+":"+STR$ INT (FN V(FN V(FN V(FN V(n,1800000),180000),30000),3000)/500)+STR$ INT (FN V(FN V(FN V(FN V(FN V(n,1800000),180000),30000),3000),500)/50)


DEF FN U$(u$)=CHR$ ((CODE u$)-(32 AND CODE u$>96 AND CODE u$<124))

XOR(posint8,posint8): depends on FN v()

DEF FN X(x,y)=(128 AND INT (x/128)<>INT (y/128))+(64 AND INT (FN V(x,128)/64)<>INT (FN V(x,128)/64))+(32 AND INT (FN V(FN V(x,128),64)/32)<>INT (FN V(FN V(y,128),64)/32))+(16 AND INT (FN V(FN V(FN V(x,128),64),32)/16)<>INT (FN V(FN V(FN V(y,128),64),32)/16))+(8 AND INT (FN V(FN V(FN V(FN V(x,128),64),32),16)/8)<>INT (FN V(FN V(FN V(FN V(y,128),64),32),16)/8))+(4 AND INT (FN V(FN V(FN V(FN V(FN V(x,128),64),32),16),8)/4)<>INT (FN V(FN V(FN V(FN V(FN V(y,128),64),32),16),8)/4))+(2 AND INT (FN V(FN V(FN V(FN V(FN V(FN V(x,128),64),32),16),8),4)/2)<>INT (FN V(FN V(FN V(FN V(FN V(FN V(y,128),64),32),16),8),4)/2))+1 AND INT FN V(FN V(FN V(FN V(FN V(FN V(FN V(x,128),64),32),16),8),4),2)<>INT FN V(FN V(FN V(FN V(FN V(FN V(FN V(y,128),64),32),16),8),4),2)

This article began as a thread in the World of Spectrum Sinclair BASIC forum.

Community content is available under CC-BY-SA unless otherwise noted.