DEF FN compiled by Andrew Owen formatting, statistics & alternative versions by Jim Grimwood * History 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). 1$ = non-null 1 character string 2$ = 2 character string d8 = 8-digit decimal integer (0-99999999) h4$ = 4 digit hex string ("0000"-"FFFF") i8 = 8-bit positive integer (0-255) i16 = 16-bit positive integer (0-65535) A ROM bug, mentioned on http://www.nonowt.com/magfold/articfol/bugs_in.html states: 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 logically will hold as the 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. Contents length mem time (sec) recursive alternative * 1 AND (i8,i8) A 940 84 1.94 238 837 1.88 * 2 BIN (a$) B 29 36 0.000005 * 3 BIN$ (i8) B$ 405 129 0.84 66 629 0.32 * 4 CHAR$ (i16) C$ 58 20 0.02 * 5 DEC (h4$) D 240 20 0.04->0.06 108 226 0.58 * 6 DEG (n) G 25 14 0.000005 * 7 DPEEK (a) P 37 20 0.000005 * 8 EVEN/ODD (a,b) E 78 22 0.02 * 9 FREE () F 28,92 0.000005,0.02 * 10 HEX$ (i16) H$ 401 69 0.44 125 507 0.48 * 11 ITEM () T 124 bug 0.22 154 7195varies * 12 LEFT$ (a$,n) L$ 28 12 0.000005 * 13 LOWER$ (1$) W$ 59 1byte 0.000005 111 any$ 0.02 * 14 MAX (n,o) M 40 16 0.02 * 15 MAX$ (a$,b$) A$ 44 24 0.000005 * 16 MID$ (a$,n,o) M$ 47 10 0.000005 * 17 MIN (n,o) Q 40 10 0.02 * 18 MIN$ (a$,b$) Q$ 44 20 0.000005 * 19 MOD (n,o) V 30 16 0.000002 * 20 NOT/CPL (i8) N 647 90 1.1 106 584 1.24 * 21 NUMBER (2$) U 48 16 0.000002 * 22 OR (i8,i8) O 1110 88 2.66 238 837 1.88 * 23 RAD (n) R 25 16 0.000002 * 24 RNDM (n) I 28 10 0.02 * 25 RIGHT$ (a$,n) R$ 43 10 0.000005 * 26 STRING$ (a$,n) S$ 77 482 0.1 * 27 TIME () Z 130 26 0.12 * 28 TIME$ (n) T$ 375 113 0.56 175 1036 0.82 * 29 UPPER$ (1$) U$ 60 1byte 0.000002 111 any$ 0.02 * 30 XOR (i8,i8) X 1030 82 2.64 238 837 1.88 RELATED FUNCTIONS AND (i8,i8), NOT (i8), OR (i8,i8), XOR (i8,i8) BIN (a$), BIN$ (i8), DEC (h4$), HEX$ (i16) CHAR$ (i16), NUMBER (2$) DEG (n), RAD (n) DPEEK (a), FREE (), ITEM () EVEN (a,b), ODD (a,b), MOD (n,o), RNDM (n) LEFT$ (a$,n), MID$ (a$,n,o), RIGHT$ (a$,n), STRING$ (a$,n) LOWER$ (1$), UPPER$ (1$) MAX (n,o), MAX$ (a$,b$), MIN (n,o), MIN$ (a$,b$) TIME (), TIME$ (n) AND (i8,i8): depends on FN v() and FN e(a,0 or 1) 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(y,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) 3010 REM *LOAX: a=d8; b=d8; c: 0=OR, 1=AND, 2=XOR; d=number of bits 3011 REM max.bits = 27 (99999999 = %101111101011110000011111111) 3012 DEF FN l(a,b,c,d) =(2^(INT (c/10)) AND (a-INT (a/2)*2)+(b-INT (b/2)*2) AND (a-INT (a/2)*2)+(b-INT (b/2)*2)<>c-INT (c/10)*10) +VAL (("FN l(INT (a/2),INT (b/2),c+10,d)+" AND c"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") 3050 REM *HEX2DEC: h$=h7$ ($5F5E0FF = 99999999) 3051 DEF FN d(h$)=16^(LEN h$-1)*(CODE h$-48-(7 AND CODE h$>64)) +VAL (("FN d(h$(2 TO))+" AND LEN h$>1)+"0") DEG (n) 6 DEF FN G(n)=n/PI*180 DPEEK (a) 7 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**(n,/**0**/ or 1) ( or **ODD**(n, 0 or /**1**/)) 8 DEF FN e(a,b)=((a/2 = INT(a/2)) AND NOT b)+((a/2<>INT(a/2)) AND b) FREE () 9 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$ (i16): depends on FN v() 10 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) 3100 REM *DEC2HEX: a=d8 3101 DEF FN h$(a)=VAL$ (("FN h$("+STR$ INT (a/16)+")+""" +CHR$ (FN v(a,16)+48+(7 AND FN v(a,16)>9)) +"""" AND a) +("""""" AND NOT a)) ITEM () 11 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) 3110 REM ITEM: 3111 DEF FN t(a,b,c$) =VAL (("FN t(a+1+(5 AND b=14), PEEK a, (c$ AND NOT VAL c$)+(e$ AND VAL c$))" AND (c$=d$ OR NOT VAL c$) AND b<>13) +("a" AND (c$=e$ AND VAL c$ OR b=13)) ) 3112 LET da=FN p(23639)+(PEEK FN p(23639)<>44): LET db=PEEK da: LET d$="b=228": LET e$="b<>228 AND b<>44 AND b<>32": LET a$=(d$ AND db<>44)+(e$ AND db=44): LET item=FN t(da,db,a$) LEFT$ (a$,n) 12 DEF FN L$(s$,l)=S$( TO l) LOWER$ (1$) 13 DEF FN W$(l$)=CHR$ ((CODE l$)+(32 AND CODE l$>64 AND CODE l$<92)) 3130 REM LOWER: a$=any$ 3131 DEF FN w$(a$)=CHR$ (CODE a$+(32 AND a$>="A" AND a$<"[")) +VAL$ (("FN w$("""+a$(2 TO)+""")" AND LEN a$>1) +("""""" AND LEN a$=1)) MAX (n,o) 14 DEF FN M(x,y)=(x+y+ABS (x-y))/2 MAX$ (a$,b$) 15 DEF FN A$(x$,y$)=(x$ AND x$>y$)+(y$ AND y$>=x$) MID$ (a$,n,o) 16 DEF FN M$(s$,s,l)=s$(s TO s-1+l) MIN (n,o) 17 DEF FN Q(x,y)=(x-y+ABS (x+y))/2 MIN$ (a$,b$) 18 DEF FN Q$(x$,y$)=(x$ AND x$c-INT (c/10)*10) +VAL (("FN l(INT (a/2),INT (b/2),c+10,d)+" AND c1)) TIME () 27 DEF FN Z()=FN M(65536*PEEK 23674+256*PEEK 23673+PEEK 23672 ,65536*PEEK 23674+256*PEEK 23673+PEEK 23672) TIME$ (n) 28 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) 3280 REM TIME$: n=anyn; t=1,800,000; d=10 3281 DEF FN t$(n,t,d) =STR$ INT (n/t)+(":" AND d=6 AND t>500) +VAL$ (("FN t$(" +STR$ (n-INT (n/t)*t)+"," +STR$ (t/d)+"," +STR$ (d-4+(8 AND d=6)) +")" AND t>=500) +("""""" AND t<500)) UPPER$ (1$) 29 DEF FN U$(u$)=CHR$ ((CODE u$)-(32 AND CODE u$>96 AND CODE u$<124)) 3290 REM UPPER: a$=any$ 3291 DEF FN u$(a$)=CHR$ (CODE a$-(32 AND a$>="a" AND a$<"{")) +VAL$ (("FN u$("""+a$(2 TO)+""")" AND LEN a$>1) +("""""" AND LEN a$=1)) XOR (i8,i8): depends on FN v() 30 DEF FN X(x,y)=(128 AND INT (x/128)<>INT (y/128)) +( 64 AND INT (FN V(x,128)/64)<>INT (FN V(y,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) 3010 REM *LOAX: a=d8; b=d8; c: 0=OR, 1=AND, 2=XOR; d=number of bits 3011 REM max.bits = 27 (99999999 = %101111101011110000011111111) 3012 DEF FN l(a,b,c,d) =(2^(INT (c/10)) AND (a-INT (a/2)*2)+(b-INT (b/2)*2) AND (a-INT (a/2)*2)+(b-INT (b/2)*2)<>c-INT (c/10)*10) +VAL (("FN l(INT (a/2),INT (b/2),c+10,d)+" AND c