DEF FN: Todo sobre las FuNciones definidas por el usuario. Este texto reune todas mis notas sobre la sentencia DEF y las instrucciones relacionadas con la misma, ya sea existentes en otros BASICs o en el Basic Sinclair, asi como sus equivalentes y diferencias en el ZX SPECTRUM. Todos los lenguajes de programación tienen su librería de funciones así como la posibilidad de definir o crear por parte del usuario las suyas propias y así incrementar la librería. Y tras lo dicho paso a... FuNciones en Fortran En FORTRAN un subprograma puede ser ya sea una subrutina o una función, siendo la unica diferencia fundamental que el nomre de un subprograma función es considerado una variable a la cual se le asigna un valor y la otra es el modo en que son invocadas. La sintaxis completa es: {tipo} FUNCTION nombre (parametros) donde: tipo = INTEGER - la función opera o deiuelve valores enteros solamente REAL - define la función exclusivamente como real LOGICAL - la función es creada para valores lógicos DOUBLE PRECISION - la función definida es de doble precisión COMPLEX - para valores complejos Ejemplo: C EJEMPLO 10.7 FUNCTION SUMA(N,X) REAL X(100) SUMA=0 DO 6 I=1,N SUMA=SUMA+X(I) RETURN END FuNciones en Pascal En PASCAL una cabecera de función tiene la sigte. forma sintáctica> function () : ; Ejemplo: FUNCTION TG(Z:REAL):REAL; BEGIN TG=SIN(Z)/COS(Z) END FuNciones en Algol En ALGOL se obtiene mediante la declaración de un procedimiento funcional. Y su sintaxis es: {tipo} procedure nombre (parámetros) donde: tipo = integer, real, boolean Ejemplo: REAL PROCEDURE TAN(T);REAL T; TAN :=SIN(T)/COS(T); FuNciones en ADA En el lenguaje ADA, la especificación de una función comienza con la palabra reservada FUNCTION, y sus parámetros (de haberlos) deben tener el modo IN (especificado ya sea implicita o explicitamente). Ejemplo: FUNCTION signo (x:INTEGER) RETURN INTEGER IS BEGIN IF x>0 THEN RETURN +1; ELSEIF x<0 THEN RETURN -1; ELSE RETURN 0; END IF; END signo; FuNciones en LOGO En el lenguaje LOGO se define una función como un subprocedimiento TO añadiendole la primitiva OUTPUT antes del END o en alguna parte dentro del código fuente. Ejemplos: TO TANGENTE :ARGUMENTO OUTPUT (SIN (:ARGUMENTO)/COS (:ARGUMENTO)) END En los primeros BASICs Como se vio en los ejemplos anteriores, la mayoría de lenguajes de programación usa la instrucción FUNCTION y todas son generalmente multilínea al igual que las subrutinas y procedimientos, pero en el caso del BASIC... Basic Darmouth 1964 sintaxis: DEF FNnombre(x)=exp donde: DEF - breve por DEFINE (definir), es la sentencia de definición propiamente dicha FN - breve por FuNction, prefija siempre al nombre de la función a crear nombre - una letra en la original versión Darmouth x - un único argumento numérico ( no se aceptan más o habrá error ) exp - expresión matemática válida como la definición real de la función Ejemplo: DEF FNL(X)=LOG(X)/LOG(10) El dilema es a la hora de añadirle más parámetros, lo que nos lleva a la única solución: 10 DEF FNL(X)=SQR(X*X + Y*Y) 20 LET Y=30 30 LET S1= FNX(40) Esta es la sentencia de definición de funciones de usuario creada para la primera versión del Basic Darmouth y que ofrecàia hasta 26 posibles funciones nuevas a definir. En la realidad, el nombre era considerado de 3 caracteres siendo los dos primeros precisamente "FN". Sería también la que poseerían los BASICs de Apple, Commodore, Dragon y Tandy. La única diferencia está en el nombre. Tanto en Basic Applesoft como en el de Commodore, el nombre es de 2 caracteres, siendo el primero por fuerza una letra y el segundo otra letra o un dígito. Oric acepta una sola letra como nombre y un solo parámetro como hace el Darmouth. Atari no parece tener esta implementación en su Basic, ni siquiera un equivalente. Darmouth versión 1968 sintaxis: DEF FNnombre{({x})}=exp donde: x = opcional o uno o más argumentos separados por comas Ejemplos: 10 DEF FNA = 3.1416*R^2 20 DEF FNB(X,Y) = 3*X*Y - Y^3 30 DEF FNC(X,Y,Z,W) = FNB(X,Y)/FNB(Z,W) BASIC 1972 sintaxis: DEF FNnombre{$}(x{$})=exp{$} donde: x = opcional o uno o más argumentos de tipo ya sea numéricos o alfanuméricos exp= expresión valida de tipo arimético o de maejo de cadenas Ejemplo: DEF FNC$(X$,Y$) =X$+Y$ Esta versión de DEF ya acepta la creación de funciones de cadena además de las ya clásicas de aritmética. Solo algunas versiones como el Basic de Acorn, Amstrad o el de Sinclair incluido en el Spectrum poseen este DEF extendido. Amstrad no limita el nombre a una sola letra como es el caso del Spectrum. FuNciones multilineas sintaxis: DEF FNnombre(parámetros) ... rutina de la función a definir ... FNEND Esta versión de DEF fue incluida en la versión 68 de Darmouth, pero no fue implementada por la mayoría de BASICs para los 8 bits, excepto en los BASICs estructurados. BBC Basic sintaxis: DEF FNnom [(paráms)] ... rutina de la función a definir ... = exp Ejemplo: 100 DEF FNscalar_product(A(),B()) 110 REM ** Both arrays must have a dimension of 1 ** 120 IF DIM(A()) <> 1 OR DIM(B()) <> 1 THEN 130 PRINT "Vectors required" 140 =0 150 ENDIF 160 REM ** Both arrays must be the same size ** 170 IF DIM(A(),1) <> DIM(B(),1) THEN 180 PRINT "Vectors must be of same size" 190 =0 200 ENDIF 210 REM ** Create a temporary array of the same size ** 220 LOCAL C() 230 DIM C(DIM(A(),1)) 240 REM ** Multiply the corresponding elements and place in C() ** 250 C() = A()*B() 260 REM ** Finally sum all the elements of C() ** 270 =SUM(C()) Nota: el Basic BBC requiere que todas las funciones definidas sean puestas al final del programa, despues de la sentencia END. QL Super Basic sintaxis: DEFine FUNCtion identificador {(parámetros)} {LOCAL variables} ... rutina de la función a definir ... RETurn {exp} END DEFine Ejemplo: 130 DEFine FUNCtion sino (abs,ord) 140 IF abs*2 + ord*2 <=36 150 THEN sino=1 160 ELSE sino=0 170 END IF 190 RETurn 200 END DEFine Quick Basic sintaxis: DEF FN nombre (parámetros) ... rutina de la función a definir ... {EXIT DEF} FN nombre= exp END DEFine Ejemplo: DEF FNfactorial (k) total= 1 FOR I=1 TO k total= total*I NEXT I FNfactorial= total END DEF En el ZX Spectrum sintaxis: DEF FN nombre{$} ([x{$}]) = exp{$} donde: nombre - una sola letra a lo Darmouth, más el signo $ si es de cadena x - opcional o uno o más argumentos de tipo ya sea numéricos o alfanuméricos exp - expresión valida de tipo aritmético o de manejo de cadenas Ejemplo: 10 DEF FN s(x)=x*x 20 PRINT FN s(2),FN s(3+4) En el ZX81 El Basic del ZX81 carece de la instrucción DEF FN, pero puede ser simulada mediante VAL y una cadena conteniendo la función a definir por el usuario. El ejemplo de la función definida en el Spectrum se converiría entonces en el ZX81 así: 10 LET X$="X*X" 12 LET X=3+4 20 PRINT VAL X$ FuNciones recursivas Se dice que un procedimiento, subrutina o función es recursivo cuando este puede llamarse a sí mismo dentro de la propia rutina. Ejemplo - Super Basic: 130 DEFine FUNCtion fact (k) 140 IF k=0 OR k=1 THEN 150 fact=1 160 ELSE 170 fact=k*fact(k-1) 180 END IF 190 RETurn 200 END DEFine Multilineas y recursión en el Spectrum Ya que el Spectrum carece de la definición de funciones multilinea, solamente nos queda una alternativa: reemplazar la función con subrutinas, o en el caso del Beta Basic o Mega Basic, usar procediemientos. En el caso del Beta Basic 3 o 4, podemos hacer que el procedimiento devuelva un valor por REFerencia. En el caso del Mega Basic o Laser Basic, el valor solo puede ser devuelto mediante una variable genérica o global. No importa cual se elija, es posible combinarlo con DEF FN para mejores resultados. Convirtiendo el ejemplo de Basic BBC a BetaBasic: 100 DEF PROC scalar, REF A(), REF B(),REF p 110 REM ** Ambos arreglos deben tener dimension 1 ** 120 IF LENGHT(1,"A(") <> 1 OR LENGHT(1,"B(") <> 1 THEN PRINT "Vectores requeridos": LET p=0: GOTO 280 160 REM ** Ambos arreglos deben ser del mismo tama~o ** 170 IF LENGHT(1,"A(") <> LENGHT(1,"B(") THEN PRINT "Vectores deben ser del mismo tama~o": LET p=0: GOTO 280 210 REM ** Crea una matriz temporal del mismo tama~o ** 220 LOCAL C() 230 DIM C(LENGHT(1,"A(")) 240 REM ** Multiplica los elementos correspondientes los pone en C() ** 250 LET C(1) = A(1)*B(1) 260 REM ** Finally sum all the elements of C() ** 270 LET p=C(1) 280 END PROC Mediante uso de subrutinas El ejemplo de factorial del QuickBasic se convierte en: 10 LET k=10: GOSUB 110 20 PRINT FN f() 30 STOP 100 DEF FN f()=factorial 110 LET total= 1 120 FOR I=1 TO k 130 LET total= total*I 140 NEXT I 150 LET factorial= total 160 RETURN Ahora, el ejemplo de factorial recursivo del SuperBasic pasa a ser... 10 INPUT k: GOSUB 100 20 PRINT FN f() 30 STOP 100 DEF FN f()= factorial 110 LET factorial= 1 120 IF k=1 THEN RETURN 130 LET factorial= FN f()*K 140 LET k=k-1 150 GOSUB 120 160 RETURN Otro ejemplo mediante subrutina recursiva - el programa potencia: 10 INPUT x,n: GOSUB 100 20 PRINT FN p() 30 STOP 100 DEF FN p()= potencia 110 LET potencia= 1 120 IF n=0 THEN RETURN 130 LET potencia= x*FN p() 140 LET n=n-1 150 GOSUB 120 160 RETURN Nota: aunque DF FN puede ser puesto en cualquier parte del programa, elegí ponerlo al comienzo de las subrutinas a modo de indicar el inicio de las mismas, incluso si para el interprete es innecesario, pero se ve como una DEF multilinea en el Spectrum. FuNciones del Beta Basic al Basic Sinclair. A continuación y para cerrar, una colección de 52 funciones definidas por el usuario, las cuales fueron publicadas originalmente en ingles en el foro de WORLD OF SPECTRUM en su sección BASIC... Un total of 52 nuevas funciones pueden ser añadidas al BASIC Sinclair; 26 funciones numericas (A-Z) y 26 de cadena (A$-Z$). Debido a la estructura interna del BASIC Sinclair, el mejor lugar para colocar estas funciones es en la linea 0. Esto previene que la linea sea accidentalmente editada o borrada y también nos da el máximo posible de velocidad (en un Spectrum sin Interface I, la linea 1 puede ser convertida en linea 0 con POKE 23756,0). Aquellas funciones que sean las máas complicadas o más frequentemente llamadas deberían tener la más alta prioridad; por ejemplo, MOD debería normalmente ertar primero. Hasta donde ha sido posible, las sigtes. funciones son compatibles o parcialmente compatibles con sus equivalentes en Beta BASIC. Algunas de las funciones numericas han sido restringidas pra tratar con números de 8-bits (0-255) mientras sus equivalentes Beta BASIC pueden manejar hasta números de16-bits. Esto es debido a que tratar con números de 16-bits en BASIC puede resultar tortuousamente lento. Las funciones recursivas son posibles, pero no serán usadas en orden de permitir que se puedan compilar con HiSoft BASIC. [i]hex4$[/i] = 4 digit hex string ("0000"-"FFFF") [i]posint8[/i] = 8-bit positive integer (0-255) [i]posint16[/i] = 16-bit positive integer (0-65535) [i]string1[/i] = non-null 1 character string [i]string2[/i] = 2 character string AND(posint8,posint8) 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 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) BIN(string) DEF FN B(b$)=VAL(CHR$ 196+b$) DEC(hex4$) 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") DEG(number) DEF FN G(n)=n/PI*180 DPEEK(address) DEF FN P(a)=PEEK a+256*PEEK (a+1) FREE() DEF FN F()=65536-USR 7962 ITEM() 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) MAX(number,number) DEF FN M(x,y)=(x+y+ABS (x-y))/2 MIN(number,number) DEF FN Q(x,y)=(x-y+ABS (x+y))/2 MOD(number,number) DEF FN V(x,y)=x-y*INT (x/y) NOT(posint8) 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)) NUMBER(string2) DEF FN N(c$)=256*CODE c$(1)+CODE c$(2) OR(posint8,posint8) 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) RAD(number) DEF FN R(n)=n/180*PI RNDM(number) DEF FN r(n)=INT (RND*(n+1)) TIME() DEF FN Z()=FN M(65536*PEEK 23674+256*PEEK 23673+PEEK 23672,65536*PEEK 23674+256*PEEK 23673+PEEK 23672) XOR(posint8,posint8) 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) BIN$(posint8) 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$ INT FN V(FN V(FN V(FN V(FN V(FN V(FN V (b,128),64),32),16),8),4),2) CHAR$(posint16) DEF FN C$(n)=CHR$ INT (n/256)+CHR$ (n-INT (n/256)*256) HEX$(posint16) 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) LEFT$(string,number) DEF FN L$(s$,l)=S$( TO l) LOWER$(string1) DEF FN L$(l$)=CHR$ (CODE l$)+(32 AND CODE l$>64 AND CODE l$<92)) MID$(string,number,number) DEF FN M$(s$,s,l)=s$(s TO s-1+l) RIGHT$(string,number) DEF FN R$(s$,l)=s$(LEN s$+1-l TO LEN s$) TIME$(number) 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) UPPER$(string1) DEF FN U$(u$)=CHR$ (CODE u$)-(32 AND CODE u$>96 AND CODE u$<124)) (c)2020 (2021) zx_if1@hotmail.com