Archivo de la categoría: MATLAB

Los lenguajes de programación más solicitados en 2021

Los lenguajes de programación más solicitados en 2021

La programación de ordenadores sigue siendo un campo con interesantes salidas laborales. Esto es especialmente cierto en el campo de la Ingeniería Civil, por tratarse de un sector consumidor de muchos recursos informáticos. Actualmente existen más de 700 lenguajes de programación activos. Este artículo hablará sobre los lenguajes más demandados en el año 2021, según distintas fuentes.

Con la excepción de los lenguajes dedicados a la programación de bases de datos, la mayoría de los índices miden la importancia de los lenguajes en su uso general, no dentro de un campo específico. Es por ello, que los lenguajes cuya utilización se da principalmente dentro de un campo concreto, salen penalizados, y su posición en los índices generales no muestra realmente su posición si se considerara solo su prevalencia en dicho campo.

Es el caso de MATLAB-Octave, cuyo uso está restringido al ámbito científico. Uno de los índices más prestigiosos es el índice TIOBE, basado en las búsquedas en internet referentes a los diferentes lenguajes. El índice TIOBE del mes de octubre de 2021 indica que MATLAB ocupa la posición 13 entre los lenguajes más utilizados. Esto supone un incremento de uso respecto de octubre de 2020, cuando ocupaba la posición 15.

En todos los índices, las primeras posiciones están copadas por Python, Java y las diferentes variantes del C: C, C++ y C#. Son sin duda los lenguajes más utilizados para programación general. Java, que venía siendo el más utilizado durante muchos años, ha cedido la primera posición en favor de Python y C. Cualquiera de ellos es una buena opción para profundizar en la programación. Si nos limitamos al ámbito científico, tal vez Python ofrece, a día de hoy, una combinación de recursos y facilidad de uso que lo convierten en la opción más atractiva.

Es significativa la evolución del lenguaje Fortran. Hace muchos años era el lenguaje científico por excelencia. De hecho, era el lenguaje que se estudiaba en la Escuela de Caminos allá por los años 80 y 90 del siglo pasado. Más tarde, Fortran perdió importancia y pasó a ser un lenguaje muy minoritario. Las mejoras aportadas en las útimas versiones, junto con su rapidez de ejecución y su enfoque científico han hecho que vuelva a ser un lenguaje muy utilizado. En el citado índice TIOBE de octubre de 2021, ocupa la posición 18 entre los lenguajes más utilizados, ascendiendo a esta posición desde la posición 37 que ocupaba el año pasado.

En el último artículo que dediqué a los lenguajes más utilizados, hablaba de Rust y Go. Los sigo considerando dos lenguajes muy interesantes y con mucho futuro. En el índice TIOBE de octubre 2021, Go ocupa la posición 12 y Rust la 26. Son lenguajes fundamentalmente dedicados a la programación de sistemas. Como opción laboral, son de los que mejores sueldos ofrecen a los programadores. Les seguiremos la pista para ver su evolución. Seguro que seguirán dando que hablar en el futuro.

Es muy interesante la encuesta anual de Stack Overflow, que ofrece respuestas a numerosas preguntas acerca del perfil de los lenguajes de programación y de los propios programadores.

A continuación se ofrece una lista de enlaces a algunos índices y a artículos comentando los distintos índices:

Stack Overflow Developer Survey 2021
TIOBE Index
The most in-demand programming languages of 2021 by TNW
Most in Demand Programming Languages 2021 by Merehead
GitHub Top Programming Languages
Top Programming Languages 2021 by IEEE Spectrum

Operadores relacionales y vectores

Los operadores relacionales son:

 <   <=   >   >=   ==   ~=

En general, operan un número con otro número y devuelven como resultado un valor lógico: verdadero (1) o falso (0). Designando por ☸ a un operador relacional cualquiera, se podría expresar como:

numero ☸ numero ☛ logical [1,0]

En vez de un número, podría tratarse de una expresión que devuelva un resultado numérico.

Los operadores relacionales también pueden operar con vectores. Se pueden dar dos circunstancias: operar un vector con un escalar u operar dos vectores. En ambos casos, los operadores relacionales siempre operan el vector elemento a elemento. Para poder aplicar un operador relacional a dos vectores, los vectores tienen que ser del mismo tamaño. El resultado es siempre otro vector del mismo tamaño que el del operando y con componentes del tipo logical (verdadero o falso). Cada componente del vector será el resultado de aplicar el operador relacional a la componente correspondiente del operando. Algunos ejemplos servirán para entenderlo:

V = [1 -1 0 -2 2]

V < 0 ☛ [0 1 0 1 0]

V <= 0 ☛ [0 1 1 1 0]

W = [1 0 0 -2 1]

V ~= W ☛ [0 1 0 0 1]

Se puede utilizar un operador relacional para extraer determinadas componentes de un vector. El resultado será un subvector con las componentes que cumplen la condición:

V = [1 -1 0 -2 2]

V(V>0) ☛ [1 2]

Siguiendo el mismo esquema, se puede utilizar una expresión relacional para sustituir el valor de determinadas componentes de un vector, como se hace en el siguiente ejemplo:

V = [1 -1 0 -2 2]

V(V>0)=100 ☛ [100 -1 0 -2 100]

Un poco más complicado sería sustituir el valor de determinadas componentes por otro valor basado en el de la propia componente. Un ejemplo podría ser multiplicar por -1 las componentes negativas de un vector, para hacerlas positivas:

V = [1 -1 0 -2 2]

V(V<0) = -1 * V(V>0) ☛ [1 1 0 2 2]

Como se ha visto, los operadores relacionales proporcionan algunas herramientas peculiares al operar con vectores. Dichas herramientas es conveniente dominarlas y entenderlas a la perfección. En la siguiente imagen se resumen las cuatro situaciones mencionadas:

Santiago Higuera (26 de septiembre de 2021)

El problema del cero exacto en computación


La manera en la que los computadores tratan los números reales da lugar a algunas paradojas que es conveniente tener en cuenta para no cometer errores. Los ordenadores no operan con números reales, sino con unos números denominados de coma flotante. Por ejemplo en Octave y Matlab se utiliza el formato numérico denominado double  para representar los números reales,. El formato double permite operar números con hasta 15 decimales significativos. Esto hace que, en el caso de los números reales que tengan un número de decimales mayor que 15, el valor utilizado por el formato double sea una aproximación al número truncada a 15 decimales.

Números reales con más de 15 decimales significativos hay infinitos, en particular todos los números irracionales y los números racionales como el 1/3 o el 1/7, que tienen un número infinito de decimales. En todas las operaciones que realicemos con el ordenador en las que intervenga alguno de estos números, los resultados serán aproximados, no exactos.

Históricamente ha habido algunas catástrofes producidas por no considerar adecuadamente estas aproximaciones que realizan los ordenadores. Así sucedió en el caso de la explosión del  cohete Arianne 5 poco después del despegue o en el fallo de una batería de misiles Patriot que no pudo interceptar un misil SCUD disparado por las tropas iraquíes durante la guerra del Golfo [1 y 2].

Una situación concreta en la que hay que tener cuidado y que se da habitualmente en los problemas que se hacen en el curso es la de comprobar si el resultado de una operación entre números reales es igual a cero. El problema de comprobar si dos números reales son iguales es equivalente al anterior, pues comprobar si x es igual a y es equivalente a comprobar si (x-y) es igual a cero.  En general es incorrecto hacer la comparación if x==0′ o la comparación ‘if x==y’.Se puede comprobar con el siguiente ejemplo realizado en la consola de Octave:

Operando con números reales,  la comprobación (y-2)==0 debería arrojar un resultado verdadero y, en cambio, arroja un resultado falso. La raíz cuadrada de 2 es un número irracional y, por tanto, el valor utilizado por el ordenador es una aproximación. Si se utiliza el formato largo para mostrar los números en pantalla se podrá comprender lo que está pasando:

Se puede ver que la diferencia (y-2) es un valor muy pequeño, pero no exactamente cero.

Hay muchos ejemplos, algunos con operaciones aparentemente sencillas. El lector puede comprobar que al sumar 1/3 + 4/3 + 1/3 no se obtiene exactamente 2, como se muestra en la siguiente figura:

Para actuar de manera controlada en estas situaciones se puede utilizar un valor umbral, que se suele denominar tolerancia, para  comparar si determinada cantidad es cero. Lo que se hace es comprobar si la cantidad es menor en valor absoluto que el valor umbral utilizado. Si así sucede, se considera que dicha cantidad es cero.  Por ejemplo, si se toma como valor umbral de la tolerancia 1e-10, se podría hacer la siguiente comparación:

El valor umbral utilizado para la tolerancia dependerá del problema concreto. Por ejemplo, si se está trabajando en un problema de altitudes del terreno medidas en metros para una obra pública, puede ser suficiente considerar que un milímetro es la cantidad más pequeña a considerar, con lo que la tolerancia en ese caso podrá ser 1e-3 . En otros casos será necesario utilizar valores menores o mayores. Cuando se trate en el curso la resolución de ecuaciones no lineales se podrán ver algunos ejemplos.

Octave y Matlab proporcionan una constante denominada eps , que corresponde a la precisión de la máquina, y que depende del ordenador utilizado. El épsilon de la máquina es el número decimal más pequeño que, sumado a 1, la computadora nos arroja un valor diferente de 1, es decir, que no es redondeado. En el computador que hemos probado, el valor de eps es:

Este valor no nos sirve para utilizarlo como tolerancia, hay que  utilizar valores de la tolerancia seleccionados adecuadamente y que se adapten bien al problema concreto. Se puede comprobar que, en el ejemplo de la raíz de 2, el valor de la constante eps sería menor que el error que se comete y, por tanto, la comprobación seguiría arrojando valores erróneos:

[1]   http://www-users.math.umn.edu/~arnold/disasters/ariane.html

[2] https://www.xataka.com/historia-tecnologica/dia-que-misil-mato-a-28-soldados-porque-sistema-defensa-antimisiles-ignoro-error-0-000000095-segundos

Santiago Higuera (Noviembre, 2017 – Revisión en septiembre de 2021)

Este artículo se publica de manera simultánea en el blog Matemata https://blogs.upm.es/matemata/

Repaso de conceptos básicos programando un juego sencillo

En este artículo se va a utilizar la programación del clásico juego de adivinación de un número, para repasar conceptos básicos de programación en el lenguaje m de MATLAB y Octave.

El programa seleccionará un número entero aleatorio entre 0 y 100 y pedirá al usuario que lo adivine. En cada intento, el programa informará al usuario si el número que ha tecleado es demasiado alto o demasiado bajo respecto al elegido por el ordenador. Cuando el usuario acierte el número, el ordenador le informará de ello.

El programa es relativamente sencillo, pero permite afianzar los conocimientos acerca de:

  • Generación de números aleatorios
  • Entrada de datos por teclado
  • Validación de las entradas de datos
  • Asignación de variables
  • Bucles while
  • Sentencias break y continue
  • Bifurcaciones if
  • Salidas simples por pantalla

A continuación se muestra el listado de la primera versión del programa. Se analizará cada apartado y, posteriormente, se indicará cómo mejorar algunos aspectos del programa:

En esta versión del programa, en primer lugar se hace un clear, para borrar la memoria, y a continuación se genera un número entero aleatorio en el intervalo cerrado [1, 100]. La figura siguiente resume las dos fórmulas usuales para generar números aleatorios: la primera genera un número decimal aleatorio en el intervalo abierto (A, B). La segunda fórmula genera un número entero aleatorio en el intervalo cerrado [A, B]:

mde

El programa sigue con un bucle while de los denominados infinitos: al hacer while 1, el bucle se ejecutará de manera indefinida hasta que encuentre una sentencia break, que fuerce la salida del bucle.

Dentro del bucle, en cada iteración, el programa solicita un número al usuario mediante una sentencia input(), y se lo asigna a la variable x. A continuación se utiliza una bifurcación del tipo if…elseif…else…end para determinar la respuesta del programa al usuario. Si el número tecleado por el usuario no es el correcto, se le informa si es demasiado alto o demasiado bajo. Si el usuario acierta, se le informa de ello, y se sale del bucle con la sentencia break, alcanzando el final del programa.

El lector debe observar que, para informar de número alto o bajo, es suficiente utilizar una sentencia disp(), mostrando en pantalla una cadena de caracteres. En cambio, para informar del acierto, como se quiere utilizar una cadena de caracteres junto con el valor de la variable n, se utiliza la sentencia fprintf().

El programa funciona, como puede comprobar el lector. Pero, ¿qué pasa si el usuario no teclea un número cuando se le solicita, y se limita a pulsar la tecla INTRO? El lector puede comprobar que, en ese caso, el programa da el resultado como correcto e informa de que se ha acertado, mostrando además el número correcto.

¿Por qué pasa esto? Si se analiza en detalle la sentencia if, se puede comprobar que si el número no es mayor ni es menor que el elegido por el ordenador, la respuesta se da por buena. En este caso, al no teclear ningún número, la variable x está vacía, y no es mayor ni menor que el resultado, con lo que se sale del bucle por la rama else.

Este tipo de circunstancias es habitual en los programas, por lo que siempre que hay una entrada de datos a un programa es muy importante hacer la comprobación de que la entrada de datos ha sido correcta.

Para comprobar si el usuario ha dejado la respuesta vacía, se puede utilizar la función isempty(), que devuelve un 1 (verdadero), si la variable está vacía. Con esto, se podría forzar al programa a repetir el input(), si la variable respuesta está vacía:

Si el usuario deja la variable x vacía, la sentencia continue fuerza que se vuelva al inicio del bucle while, iniciando otra iteración, y volviendo a ejecutar la sentencia input(). El lector puede corregir el programa y comprobar que se resuelve el problema de respuesta vacía.

La respuesta vacía no es la única respuesta incorrecta. El usuario, por error o por malicia, podría teclear un número que no fuera entero, por ejemplo un número decimal. Para detectar esta circunstancia se puede utilizar la función fix(), que devuelve la parte entera de un número decimal. Si la expresión fix(x) no es igual a x, entonces el valor tecleado no es entero. En ese caso, se puede hacer como antes, y forzar el reinicio del bucle. El código corregido quedaría así:

Se podría forzar al usuario a teclear un número no menor que 1 ni mayor que 100, aunque en este caso no se ha considerado que sea importante.

¿Y qué sucede si el usuario teclea una cadena de caracteres, en vez de teclear un número? En ese caso, Octave o MATLAB interpretarán la cadena de caracteres como el nombre de una variable o como una instrucción válida. Si el nombre de variable es correcto, por ejemplo, si se responde ‘PI‘, el programa interpretará la respuesta como un número decimal y actuará en consecuencia, volviendo a pedir el valor x. También se podría teclear una operación válida, por ejemplo, 20+10. En ese caso, se ejecutará la operación y se asignará el resultado a la variable x. Si se teclea una cadena que no se corresponda con un nombre de variable existente, o una instrucción válida, el programa fallará.

Una manera de gestionar esto es leer el dato del usuario como si fuera una cadena de caracteres, y luego convertirlo en número, de la siguiente forma:

Observe el lector que se añade un segundo parámetro ‘s‘ al input(), para forzar la lectura como cadena de caracteres, y luego se convierte dicha cadena en numero mediante la función str2num(). De esta forma, si la cadena no da lugar a un número, la variable x quedará vacía y se volverá a pedir el valor.

El problema puede ser si se teclea un comando válido. De hecho, en las entradas de datos, suelen estar algunos de los agujeros de seguridad más importantes que suelen aprovechar los hackers. Como muestra,el lector puede probar a teclear como respuesta clear, o surf(peaks), o, en plan hacker, pruebe a teclear exit(). Estas tres respuestas son relativamente inocuas, pero si nuestro programa se llama, por ejemplo, adivina1.m y respondemos con delete(‘adivina1.m’), el programa se borrará del directorio y perderemos todo el trabajo. Si el lector quiere probarlo, es conveniente hacer primero una copia del programa con otro nombre, para no perder el trabajo. Se podrían hacer cosas mucho más graves que simplemente borrar un fichero. Estas respuestas en forma de instrucciones a ejecutar por el software se conocen como ‘code injection‘, y es un bug realmente peligroso. El lector puede consultar el artículo al respecto de la Wikipedia:

https://en.wikipedia.org/wiki/Code_injection

La función str2num() evalua la expresión entrecomillada, antes de asignarla a la variable x. Si la expresión tecleada es maliciosa, se produce el problema. Se puede utilizar la función str2double(), que no evalua la expresión tecleada, y es por tanto segura frente al problema del code injection, aunque también nos impide teclear expresiones válidas. El código sería el siguiente:

Si el lector ha llegado hasta aquí, habrá podido comprobar que la codificación de programas aparentemente simples admite muchos matices. También será consciente de lo importante que es el checking de las entradas de datos en todos los programas.

Dada la fecha en la que va a aparecer publicado este artículo, no puedo por menos que desear feliz navidad a todos los lectores.

Nota: Estos problemas de code injection en sentencias de asignación directa o con str2num(), están parcialmente filtrados en MATLAB. No así en Octave. En cualquier caso, se puede probar a responder en MATLAB system(‘del adivina1.m’), que en Windows borrará el fichero en cuestión. A través de la instrucción system() que ejecuta directamente órdenes del sistema operativo se pueden introducir todo tipo de códigos maliciosos.

(Santiago Higuera. 23 diciembre 2020)