Funciones personalizadas
La posibilidad de implementar nuestras propias funciones es una de las características más ricas de una hoja de calculo.
Para todo este capitulo asumimos que no tienes problemas con la implementación de formulas y funciones en Calc, es muy útil, que tengas muy claro, que las funciones siempre devuelven un valor, aún y cuando éste sea un error, que estas pueden o no necesitar argumentos, que los argumentos son de un tipo y el valor devuelto puede ser de otro.
Por ejemplo, supongamos las triviales formulas para obtener el diámetro, el perímetro y el área de un circulo
Donde:
- r = radio
- D = Diámetro
- A = Área
- P = Perímetro
En Calc, suponiendo que el radio este en la celda A2 las formulas serían.
Diámetro = A2 * 2
Perímetro = PI() * A2 * 2
Área= PI() * POTENCIA(A2;2)
En OOo Basic, estas funciones podrían quedar así:
Option Explicit 'Función para obtener el diámetro de un circulo Function DiametroCirculo( Radio As Single ) As Double DiametroCirculo = Radio * 2 End Function 'Función para obtener el perímetro de un circulo Function PerimetroCirculo( Radio As Single ) As Double Const PI As Single = 3.1416 PerimetroCirculo = Radio * 2 * PI End Function 'Función para obtener el área de un circulo Function AreaCirculo( Radio As Single ) As Double Const PI As Single = 3.1416 AreaCirculo = PI * Radio ^ 2 End Function
Estas funciones, se usan exactamente igual que cualquier otra función de Calc, es decir, escribiendo su nombre correctamente y pasándole los argumentos correctos. Observa la siguiente imagen, donde estamos calculando estos valores, por los dos métodos, con formulas y funciones incorporadas de Calc, y con nuestras funciones personalizadas.
La forma como establecemos los argumentos y el valor devuelto de la función, no te son desconocidos, los hemos venido usando a lo largo de los temas vistos, la diferencia, es que, ahora, solo “llamábamos” a las funciones desde otras macros, ahora, las estamos usando desde la hoja de calculo.
Pero las funciones personalizadas son mucho más versátiles, nota como en las tres formulas, usamos el mismo argumento, solo el radio, podemos crear nuestra función para que nos devuelva el valor deseado de los tres, simplemente pasándole un segundo argumento para indicarlo.
'Función para devolver un dato de un círculo 'QueDato puede tener los valores ' 1 = Diámetro ' 2 = Perímetro ' 3 = Área Function Circulo( Radio As Single, QueDato As Byte ) As Double Const PI As Single = 3.141592 Dim dTmp As Double Select Case QueDato Case 1 dTmp = Radio * 2 Case 2 dTmp = Radio * 2 * PI Case 3 dTmp = PI * Radio ^ 2 End Select Circulo = dTmp End Function
Cuando le pasas un argumento a una función desde una hoja de calculo (generalmente una referencia a una o varias celdas), lo que realmente toma la función es el valor de estas celdas. Las funciones personalizadas, tienen las mismas consideraciones presentes en las funciones incorporadas de Calc, principalmente, las relacionadas con el correcto paso de argumentos y el tipo de valor devuelto.
Nuestro siguiente ejemplo también es muy simple, vamos a obtener el área de un triángulo, cuya formula es.
Donde:
- b = Base
- h = Altura
- A = Área
Nuestra función para calcular el área, quedaría así.
'Función para calcular el área de un triángulo Function AreaTriangulo( B As Single, H As Single ) As Double AreaTriangulo = (B * H) / 2 End Function
El asunto cambia bastante cuando lo que conocemos son la longitud de los lados del triángulo, para estos casos, usamos la famosa formula de Herón.
Donde:
- a, b y c = son los lados del triángulo
- S= Semiperímetro, es decir, el perímetro entre dos
- A= Área
Como función.
'Función para calcular el área de un triángulo 'con la formula de Herón Function AreaTrianguloHeron( a As Single, b As Single, c As Single ) As Double Dim S As Double S = ( a + b + c ) / 2 AreaTrianguloHeron = Sqr( S*(S-a)*(S-b)*(S-c) ) End Function
Por supuesto, no solo puedes manejar números como argumentos, en el siguiente ejemplo, usamos una fecha como argumento, el planteamiento es el siguiente; se contrato un servicio anual, queremos mostrar en otra celda, el número de días que faltan para renovar el servicio, no importa el número de años que lleva contratado, solo queremos saber cuantos días faltan para la próxima renovación, una primera aproximación sería.
- Celda A2 = Fecha de contratación
- Celda B2 = Días que faltan para renovar
La formula de la columna B es:
=FECHA(SI(FECHA(AÑO(HOY());MES(A2);DÍA(A2))>HOY();AÑO(HOY());AÑO(HOY())+1);MES(A2);DÍA(A2))-HOY()
Esta formula ya es un poco más compleja, nos pide un poco más de esfuerzo para comprenderla, pero es un buen ejemplo de lo que hay que hacer cuando queremos hacer una función personalizada, es decir, tenemos que tener muy claro que es lo que queremos obtener y que datos de origen tenemos, en este caso, solo tenemos una fecha, la fecha de contratación del servicio, ¿que es lo que haces para saber cuantos días faltan para la renovación?, cuidado, no es una pregunta ligera, recuerda que el trabajo de programador, es resolver problemas, y los problemas, entre más sencillos, son más fáciles de resolver, así que, tomate con calma la respuesta de la pregunta. En la solución de la función comentamos paso a paso la respuesta.
'Función para saber cuantos días faltan para renovar Function DiasParaRenovar( FechaInicial As Date ) As Integer Dim FechaActual As Date Dim iDiferencia As Integer 'Lo primero que necesitamos es tener la misma fecha inicial 'mismo día y mes, pero con el año actual, observa como obtenemos 'el año actual, la función Now, devuelve la fecha actual, con Year obtenemos el año FechaActual = DateSerial( Year(Now()), Month(FechaInicial), Day(FechaInicial) ) 'El siguiente paso, es saber si esta fecha actual, es mayor o menor al día de hoy If FechaActual < Now() Then 'Si es menor, significa que la renovación ya paso, por lo que se tiene 'que aumentar un año a la fecha actual para obtener la correcta de renovación FechaActual = DateSerial( Year(Now())+1, Month(FechaInicial), Day(FechaInicial) ) End If 'Restamos la fecha futura con el día de hoy, para saber cuantos días faltan 'Usamos Fix para eliminar las horas y evitar el redondeo iDiferencia = FechaActual - Fix(Now()) 'Asignamos el resultado DiasParaRenovar = iDiferencia End Function
Comparando, aquí es bastante notable la comodidad de una función personalizada:
=FECHA(SI(FECHA(AÑO(HOY());MES(A2);DÍA(A2))>HOY();AÑO(HOY());AÑO(HOY())+1);MES(A2);DÍA(A2))-HOY()
=DIASPARARENOVAR(A2)
En nuestro siguiente ejemplo, tenemos como argumentos números y regresamos un texto, la tarea es mostrar el valor de un ángulo, configurado correctamente, por ejemplo: 125º 45' 35, lo que logramos con la siguiente función.
'Función para dar formato a valores sexagesimales Function AnguloFormateado( Gra As Integer, Min As Byte, Seg As Byte ) As String Dim sTmp As String sTmp = Str(Gra) & "º " & Str(Min) & "' " & Str(Seg) & "''" AnguloFormateado = sTmp End Function
Observa como estamos regresando una cadena (String). Tu tarea es hacer la operación inversa, a partir de la cadena, regresar cualquiera de los tres valores, grados, minutos o segundos, según el argumento pasado, te pongo el esqueleto de la función y tú la desarrollas.
'Función para devolver un valor de una ángulo 'El argumento QueValor, puede tomar los valores ' 1 = Devuelve los grados ' 2 = Devuelve los minutos ' 3 = Devuelve los segundos Function DatoAngulo( Angulo As String, QueValor As Byte ) As Integer 'Esta es tú tarea End Function
Otro ejemplo donde tenemos como argumento un número (Byte) y regresamos una cadena (String), es el siguiente.
'Función para convertir un número en texto Function NumeroTexto( Num As Byte ) As String Dim sTmp As String Select Case Num Case 0 : sTmp = "Cero" Case 1 : sTmp = "Uno" Case 2 : sTmp = "Dos" Case 3 : sTmp = "Tres" Case 4 : sTmp = "Cuatro" Case 5 : sTmp = "Cinco" Case 6 : sTmp = "Seis" Case 7 : sTmp = "Siete" Case 8 : sTmp = "Ocho" Case 9 : sTmp = "Nueve" End Select NumeroTexto = sTmp End Function
¿Y para que crees que sirve eso?..., exactamente, para hacer la famosa función que convierte números a letras, sumamente útil y muy usada en áreas administrativas, te invito a que intentes desarrollarla, dada la extensión de la misma, no la incluimos aquí, pero si en los archivos de ejemplo que acompañan a este libro.
Hasta ahora, todos los argumentos que le hemos pasado a nuestras funciones, han sido celdas individuales, pero también puedes pasarle rangos de celdas, donde, lo único que tienes que tener en cuenta, es que los valores de este rango, los tomará como una matriz de dos dimensiones, nuestra versión de la función SUMA, es la siguiente.
'Función para sumar los valores de un rango Function SumarRango( Rango ) As Double Dim dTmp As Double Dim co1 As Long, co2 As Long 'Iteramos en la primer dimensión de la matriz For co1 = LBound( Rango,1 ) To UBound( Rango,1 ) 'Iteramos en la segunda dimensión de la matriz For co2 = LBound( Rango,2 ) To UBound( Rango,2 ) 'Vamos sumando los valores dTmp = dTmp + Rango( co1, co2 ) Next co2 Next co1 'Asignamos el resultado SumarRango = dTmp End Function
Observa como no establecemos el tipo del argumento Rango, esto es por que, al ser una matriz, esta, forzosamente tiene que ser tipo variante (Variant). Veamos un ejemplo practico donde pasamos como argumento un rango de celdas. En topografía, se puede calcular el área de un terreno o de cualquier poligonal cerrada cualquiera, donde se cuenta con sus coordenadas, por varios métodos, uno de ellos se llama por “Productos Cruzados”, cuyo algoritmo, espero sea bastante claro en la siguiente imagen.
En la celda D214, tenemos el calculo del área, pero usando todo el desarrollo del método, en la celda D216 (en rojo), tenemos el mismo resultado, pero usando la función mostrada en la celda D218, cuyo código es el siguiente.
'Función para obtener el área de un polígono irregular 'por medio de coordenadas y el método de productos cruzados Function AreaPoligono( Rango ) As Double Dim Suma1 As Double Dim Suma2 As Double Dim co1 As Long 'Calculamos las suma de los productos cruzados For co1 = LBound( Rango,1 ) To UBound( Rango,1 ) - 1 Suma1 = Suma1 + Rango(co1,1) * Rango(co1+1,2) Suma2 = Suma2 + Rango(co1+1,1) * Rango(co1,2) Next co1 'Asignamos el resultado AreaPoligono = Abs(Suma1 - Suma2) / 2 End Function
Muy importante, observa que para acceder a la segunda dimensión de la matriz, estamos empezando en 1, no se cual sea la razón de que al acceder a los valores de un rango de celdas por medio de una función, el limite inferior sea siempre 1 (por ahora), es la única excepción que me he encontrado con el uso de matrices, recuérdalo.
Si tienes dudas acerca de lo aquí explicado, tienes algún problema con AOO, o quieres ampliar la información, no dudes en dirigirte al Foro Oficial en español de Apache OpenOffice para Macros y API UNO |