El Perceptrón – Aprendizajes hacia la IA – Parte 1

 Nuevamente con el aprendizaje hacia la Inteligencia Artificial, para ello, uno de los tópicos a revisar son las redes neuronales artificiales, estas básicamente son una representación computacional de las redes neuronales “naturales” en términos de su comportamiento; una red neuronal está compuesta por neuronas, pero ¿Qué es una neurona?, por definición:

“Célula del sistema nervioso formada por un núcleo y una serie de prolongaciones, una de las cuáles es más larga que las demás”

300px-Neurona.svg

Podríamos decir que la función básica de la neurona es un procesamiento que se da a través de recibir un input (estímulos eléctricos), realizar un procesamiento y transmitir un resultado hacia la siguiente neurona, McCulloch  y Pitts crearon la neurona que lleva su nombre y que es una unidad de cálculo que intenta modelar el comportamiento descrito de una neurona “natural“:

neuronaa

PLANTEANDO

Si describimos esta neurona las Xi representan las entradas y las Wij representan el peso asignado a cada una de las entradas que tenemos, la sumatoria representa la neurona y el axón inicialmente sin tomar el f() sería la salida, hago esto con el fin de explicarles de la misma forma que entendí la conformación de la neurona, entonces podemos decir lo siguiente:

1
Primer acercamiento

Para todas las entradas posibles la salida Y sería la suma de cada entrada multiplicada con su ponderada, pero esta ecuación no está completa aunque si ya nos permite esbozar que una red neuronal será una aproximación a una función matemática de pesos, al ser matemática implica que podemos hacer uso de toda la matemática disponible para su resolución, al expresarlo mediante una función hemos “modelado” el comportamiento, ahora tenemos que poner a prueba nuestro modelo.

Cuando deseamos comprobar si nuestro modelo es adecuado lo primero que se hace es poner a prueba nuestro modelo y que pueda responder a las funciones lógicas más básicas, entonces:

Primera Prueba – La función NOT

Una función de ese tipo en una tabla se expresa de la siguiente forma:

2

Podemos representarla de la siguiente forma:

3

 

Cuando reemplazamos los valores a la función que hemos obtenido nos queda:

4

Entonces este primer acercamiento no es correcto y debe de modificarse, ¿Cómo debe de modificarse?, pues si observamos  seria muy conveniente el agregar un término constante b (en el gráfico es θ) por cada neurona de la siguiente forma:

6
Segundo acercamiento

Entonces se puede representar de la

5

 

Resolvemos según la tabla y obtenemos:

7

Vemos que esto nos funciona cuando hacemos uso de un NOT, ahora veamos si es posible en un OR.

Segunda Prueba – función OR

La tabla de una función lógica OR es:

8

Podemos expresarlo de la siguiente forma:

9

Reemplazando tenemos:

10.png

Tal como podemos observar vamos a obtener una contradicción en el que los pesos “W” son 1 y en la última ecuación ambos suman 2 pero el resultado es 1.

REPLANTEANDO NUEVAMENTE!!! 

Si resolvemos con las demás funciones lógicas simples veríamos que tampoco se cumple, entonces ¿Qué es a lo que se llegó?, debía de implementarse una función, a la que llamaron función no lineal, para este caso desarrollaron la función step, tal que su representación final sea la del inicio:

neuronaa

Tal que la función step es:

11

Entonces validamos la función NOT:

12

Y si cumple, ahora validemos la función OR:

13

¿Qué ocurre entonces con la función AND?

Se cumple la tabla:

14

¿Cómo podemos interpretar una función AND?, pues una AND se expresa en la negación de la función OR; tal como está nuestra función no se adapta, para ello debemos de aumentar en 2 neuronas y  de hacer un cambio en nuestro parámetro y revisar si nuestro modelo actual sigue adaptándose, entonces tomaremos el valor -0.5 para el “OR” y vemos que cumple, finalmente esto se puede graficar de la siguiente forma:

16.png

Es factible usando el mismo modelo expresarlo con una sola neurona si el valor del parámetro fuese -1.5

Tercera Prueba función XOR:

El problema que XOR a de implicar el uso de una neurona más, veamos la tabla:

15

 

Esta función se expresa de la siguiente forma:

17

Si construimos la gráfica:

18.png

 

Anuncios

Matplotlib – Generador de Gráficos en Python

Una imagen es mejor que mil palabras, es un término recurrente cuando se desea resumir o explicar algún tópico, las imágenes pueden ser solo el sujeto que hemos de cambiar por un diagrama o cuadros o gráficos, imaginemos que tenemos una cantidad considerable de datos y queremos mostrar el comportamiento que estos siguen, para ello existe la librería matplotlib, el cual es una librería para la generación de gráficos a partir de datos contenidos en listas  y es usado por lo general a través de numpy, para esta breve descripción usaremos a VSCODE como editor de código, sin más que decir. empecemos:

INSTALACIÓN E IMPLEMENTACIÓN

La instalación se realiza a través del terminal (CMD si es que tu python está dentro del path) incorporado en VSCODE con la instrucción siguiente:

pip install matplotlib

Ahora debemos de abrir un fichero y en este debemos de importar la librería, se estila que la librería sea importada de la siguiente forma:

import matplotlib.pyplot as plt

matplotlib.pyplot es una colección de funciones que asemejan al estilo de comandos que tiene MATLAB, que supongo tendrá especial significancia para aquellos que ya están familiarizados con dicho software, en lo particular yo no, pero te encontrarás con muchos tutoriales que hacen referencia a este tipo de importación.

HACIENDO UNA LÍNEA RECTA

Hacer una línea recta es muy sencillo en esta librería, pues en su forma más básica debemos de tener dos listas que representen el eje X e Y y colocarlos dentro del método plot(), plot tiene un constructor amplio, pero por el momento vamos a reducirlo a la realización de un recta simple en donde requerimos tanto los elementos de las coordenadas X e Y y una etiqueta, entonces plot hace la recta pero cuando creamos un gráfico necesitamos saber que representan cada uno de los ejes, supongamos que tenemos intenciones de presentar la relación entre los metros cuadrados de una habitación con su precio de alquiler, para ello debemos de hacer uso de los métodos xlabel() y ylabel(), los  cuáles reciben como parámetro obligatorio  la cadena de texto que representa el eje en cuestión, podemos agregar un título a nuestro gráfico con title() y la leyenda que corresponde a la recta que se toma de la etiqueta al momento de su creación con el método legend(), finalmente debemos de mostrar la gráfica, y esta se muestra con el método show(), entonces:

import matplotlib.pyplot as plt

#creamos dos listas
x=[1,2,3]
y=[5,7,9]

plt.plot(x,y,label="linea1") # creación de la recta
plt.xlabel("Metros cuadrados") #etiqueta eje X
plt.ylabel("Costo en miles de soles") #etiqueta eje Y
plt.title("Relación Costo y m2") #Agregamos un título
plt.legend() #agregamos la leyenda
plt.show() #desplegamos el gráfico
El resultados es el siguiente:
mat1.png

HACIENDO UNA DIAGRAMA DE BARRAS

Para realizar un diagrama de barras es tan sencillo, ya que solo se requiere del método bar(), como requisito debemos de indicarle la serie en el eje X y en Y, una etiqueta, todo lo demás se mantiene de forma similar:

x=[2,4,6,8,10]
y=[6,7,8,2,4]

x2=[1,3,5,9,11]
y2=[7,8,2,4,2]

plt.bar(x,y,label="Bar 1")
plt.bar(x2,y2,label="Bar 2")

plt.xlabel("x")
plt.ylabel("y")

plt.title("Gráfica de Barras")
plt.legend()
plt.show()

Así de forma sucesiva podemos hacer una serie de gráficas, personalmente no creo que requiera mayor análisis que el que implique revisar la misma API de la librería.

Matrices en Python uso de Numpy

Numpy es la librería casi por defecto cuando hemos de tratar con matrices, y específicamente en el uso de big data por su menor consumo de tiempo de procesamiento computacional dando paso a una mayor cantidad de procesamiento, entonces en esta ocasión revisaremos las operaciones con matrices que se pueden realizar:

INSTALACIÓN

En primera instancia este tutorial asume que estás usando VSCODE  y que tu sistema operativo o distribución ya tiene instalado python, abrimos el terminal incorporado de VSCODE, abrimos el terminal y hacemos la siguiente instrucción:

pip install numpy

DECLARACIÓN DE UNA MATRIZ

Cuando hemos de usar numpy debemos de importar la librería en el top del fichero, entonces:

import numpy as np

 Esto significa que todo lo relacionado a la invocación de los métodos que pertenecen a numpy lo hemos de realizar haciendo “np.nombre_metodo“, como si métodos estáticos se trataran en su sintaxis (java ¿huh?).

Ahora bien, ¿Cómo se implementa una matriz en un lenguaje de programación?, pues esta se implementa a través de los arreglos, un arreglo es una estructura de datos que nos permiten almacenar elementos que dependiendo del lenguaje pueden ser del mismo tipo o no, java por ejemplo permite los arreglos de un mismo tipo y solo de primitivos si son de tipo referenciados pues tienen otros nombres; sin embargo, python considera que los elementos que conformen un arreglo no necesariamente tienen que ser todos del mismo tipo de dato (no hacemos referencia a primitivos pues todo es un objeto en python).

Python agrupa los arreglos de la siguiente forma:

Para las matrices en numpy se organiza la estructura de forma muy similar a las listas, aunque no son lo mismo, entonces hecha esta aclaración, una matriz se define de la siguiente forma:

a=np.array([1,2,3])#1 dimensión
b=np.array([[1,2,3],[4,5,6]]) #2 dimensiones
c=np.array([[1,2,3],[4,5,6],[7,8,9]]) # 3 dimensiones

El objeto principal en numpy es ndarray el cual representa un arreglo que puede ser multidimensional y es homogéneo en términos del tipo de objeto. Una de las formas de crear una matriz se realiza con el método array, y que su constructor es de la siguiente forma:

numpy.array(objectdtype=Nonecopy=Trueorder='K'subok=Falsendmin=0)

Aunque los demás términos ya están descritos en su definición, el parámetro obligatorio es un objeto el cual tal como se ha mostrado divide sus dimensiones siguiendo una estructura tipo lista. Podemos también transformar desde listas o tuplas (bueno en esencia es un objeto ¿no?), entonces sea:

arreglo=[1,2,3,4,5,6,7,8,9]
arreglo2=(1,2,3,4,5,6,7,8,9)

x=np.array(arreglo)
y=np.array(arreglo2)

y=np.reshape(y,(3,3))
x=np.reshape(x,(3,3))

Si ingresamos una lista o tupla, esta quedará como una matriz de una sola dimensión, si deseamos dar un ordenamiento específico como una matriz de 3×3, debemos de hacer uso del método reshape:

numpy.reshape(anewshapeorder='C')

Este método nos devuelve una matriz con el ordenamiento deseado, y es tal como la hemos usado, el tipo de orden debe indicar a través de una tupla, en nuestro caso de (3,3). Dicho esto como parte básica para la creación de las matrices, vamos a realizar las operaciones con ellas.

OPERACIONES BÁSICAS

Sean 2 matrices de 2×2 A y B que las obtenemos a través de listas, pero vamos a generarlo todo en una sola línea:

a=[1,2,3,4,]
b=[7,8,9,10]

a=np.reshape(np.array(a),(2,2))
b=np.reshape(np.array(b),(2,2))

La suma entonces:

c=b+a
print(c)

La resta:

c=b-a

Podemos hacer que todos los elementos de la matriz se eleven a un exponente determinado de la siguiente forma:

c=b**exponente
c=np.power(b,exponente)

Multiplicación

Las matrices tienen una particularidad al momento de la multiplicación, ya que siguen la forma de filas por columna, para realizarla podemos hacerlo de dos formas:

c=np.dot(a,b) #recibe las 2 matrices a multiplicar
d=a@b

La División

¿Por qué no tomamos la división?, pues por teoría la división de una matriz no es una operación que se realice como con los números reales, una división en una matriz se puede determinar a través de la multiplicación con la inversa de la matriz que estaría en el denominador, es decir:

A.B-1

Podemos obtener la inversa de una matriz a través del método inv, el cual pertenece a la subclase linalg, inv recibe como parámetro a la matriz  y devuelve su matriz inversa, entonces:

e=np.linalg.inv(b)

Ahora bien haciendo uso de las matrices de ejemplo a y b:

f=np.dot(a,np.linalg.inv(b))

DETERMINANTE DE UNA MATRIZ 

El determinante de una matriz podemos hallarlo haciendo uso del método det, que tiene como parámetro la matriz cuadrada que se desea hallar su determinante (no olvidar que el determinante siempre es un escalar y nunca un vector):

determinante=np.linalg.det(a)

MATRIZ TRANSPUESTA

La transpuesta de una matriz es la transformación en que las filas pasan a las columnas y viceversa, para realizar la transpuesta debemos de usar el método transpose, este es un método asociado directamente a la matriz, entonces:

g=a.transpose()

Por lo pronto es todo lo que podemos observar de las operaciones con matrices

 

Java desde Cero – Estructura de Control de Flujo – Bucles 2

Anteriormente:

Ya hemos revisado el bucle FOR, en esta ocasión vamos revisar la estructura de control de flujo While, tal como en la introducción mencionamos los bucles While son del tipo indeterminado, y es indeterminado ya que no se sabe cuántas veces se ejecutará ya que estas estructuras responden a una condición booleana, condición que deberá ser verdadera para que la ejecución continúe y falsa para que se detenga, su estructura es de la siguiente forma:

while (condición) {
     sentencias
}

Existen algunas observaciones respecto a while, puede ser que nuestra condición sea falsa con lo cual nunca ha de ejecutarse el while, o puede ser que sea verdadera y no exista un mecanismo que cambie dicha condición con lo cual la iteración de while será infinita, dicho esto debemos de tener especial cuidado cuando definamos la condición, sobre esta última observación, ¿Dónde conviene tener un bucle infinito? pues por lo general es un recurso que se emplea mucho en el desarrollo de los videojuegos y que se ejecutan hasta un cierre del mismo, pero mientras este cierre no se ejecute conviene mucho que todas las demás funcionalidades estén en ejecución, como el estar re-dibujando constantemente el canvas, si te encuentras en una situación que amerita su implementación simplemente puedes hacer esto:

while (true) {
     sentencias
}

No hay mucho que decir, así que veamos un ejemplo para visualizar el como trabaja esta estructura de control de flujo. Supongamos que tenemos  un número al azar entre 0 y 100, y tenemos que adivinar el número, tal que nuestro programa si en caso no acertemos nos de información de si el número que hemos ingresado es muy alto o muy bajo respecto al número que estamos buscando, cuando por fin acertemos el programa nos dará una felicitación, nos dirá que número era y cuántas veces hemos intentado hasta hallar el número.

import java.util.Scanner;

public class Bucles_2 {

  public static void main(String[] args) {

    int numero_buscado=(int)(Math.random()*100);
    boolean no_acerto=true;
    Scanner entrada=new Scanner(System.in);
    //System.out.println(numero_buscado);
    System.out.println("Bienvenido al juego");
    int intentos=0;

    while(no_acerto==true) {
      System.out.println("Ingrese un número");
      int variable=entrada.nextInt();
      if(variable>numero_buscado) {
        System.out.println("El número es muy alto");
        intentos++;
      }else if(variable<numero_buscado) {
        System.out.println("El número es muy bajo");
        intentos++;
      }else {
        System.out.println("Acertaste!");
        intentos++;
        no_acerto=false;
      }
    }
    entrada.close();

    System.out.println("El número buscado era: "+numero_buscado+" y lo obtuviste con un total de "+intentos+" intentos");

}

}

Revisamos un poco lo desarrollado, de arriba hacia abajo, tal como es el flujo natural de ejecución en Java, bueno, lo primero que hemos creado es el número aleatorio, este número aleatorio lo hemos obtenido con el uso del método estático de random de la clase Math del paquete java.lang, este método nos retorna un número aleatorio entre 0 y 1 y de tipo double, para obtener el número entre 0 y 100 basta que multipliquemos el valor que nos retorna por 100, ahora bien dado que un tipo double es esencia un decimal, nosotros vamos a restringir los resultados a valores de tipo entero, para lo cual debemos de realizar una conversión o casteo y por ello hacemos uso de (int) para tales fines.

Luego creamos la condición que estará en el while, en la línea siguiente definimos que dado que el usuario ha de ingresar datos a través del teclado, necesitamos capturarlos y esto lo hacemos a través de una instancia de la clase Scanner, finalmente creamos un contador de intentos; ahora bien, empieza la iteración dado que la condición es true, se le consulta por un número al usuario, se captura el número con la instancia de Scanner y se castea a un entero con el método nextInt(), y se evalúa en los condicionales si es mayor o es menor, o si en caso de no ser alguna de ellos, podemos tener la certeza de que es el número que estamos buscando y detenemos la iteración haciendo que la variable booleana cambie a false; en todos los componentes del condicional hacemos que los intentos se le suma una unidad aún incluso si acertamos se puede contabilizar como un intento.

No olvidemos jamás de cerrar el flujo de entrada de datos, haciendo uso del método close de la clase Scanner. Finalmente hacemos impresión de los resultados y nuestro programa habrá finalizado

Algoritmo de Regresión Lineal – Aprendizajes hacia la IA

La inteligencia artificial es algo que ya está en los comentarios académicos del día a día, está vinculada cuando se revisa el hacia donde van las tecnologías y  la rama específica a la que nos dedicamos, y es que definitivamente todo ha de estar involucrado en un futuro (esperemos que cercano) con la inteligencia artificial, yo, soy estudiante de ingeniería industrial, bien que mal entiendo por mis cursos de carrera que mi profesión básicamente se trata de tomar una buena decisión sobre qué hacer para responder a la gran interrogante de ¿Cuánto voy a ganar?, ese cuánto está determinado por las tomas de decisiones que se realicen para la consecución de maximizar dicho objetivo, una toma de decisión está influenciada por una infinidad de datos que nosotros delimitamos dada nuestras limitantes biológicas de análisis, pero imaginemos que tuviéramos un consejero que no tuviera esas limitantes de análisis y que nos pueda brindar información o conclusiones que realmente ponderen la evaluación entre una opción u otra o incluso agregar alguna desconocida en la toma de una decisión, esto es una de los principales objetivos de la inteligencia artificial, claro que tiene muchos más pero este es uno de ellos, y es el que se alinea mejor a mi profesión, supongo que tú al leer esto, tendrás que encontrar la significancia y el valor ponderado de la inteligencia artificial en tu carrera.

Ahora bien, mi especialidad en tópicos de programación se ha decantado por lo general hacia el desarrollo de plataformas web y proyectos varios, pero jamás sobre la inteligencia artificial, este el primer post de muchos en el cual intento crear mi propio True Path sobre la IA, esperando que con ello pueda ayudarte en construir tu propio camino.

REGRESIÓN LINEAL

Entonces el tema que nos atañe en esta publicación es la regresión lineal, un tópico que está demás decir en ingeniería siempre se aborda en distintos cursos que tengan que ver con la evaluación de datos como lo es la estadística. Para entender la regresión lineal vamos a realizarlo con un ejemplo; supongamos que nos tenemos que mudar (país, provincia, distrito sea cual sea el de tu comodidad), al mudarnos nosotros deseamos evaluar dónde mudarnos y empezamos la recolección de datos, decidimos que el costo de la habitación que hemos de usar está en función del área que la compone, hacemos una revisión y obtenemos los siguientes resultados.

regresion1

Este acto de definir la relación entre una variable independiente y dependiente para una representación de la realidad en función de relaciones se denomina modelar o establecer un modelo, cuando observamos nuestra gráfica, podemos intuir que podemos trazar una línea recta que atraviese la mayoría de puntos o que al menos esté lo más cercano a ellos.

regresion2

Y esto que acabamos de dibujar es un modelo, este modelo nos permite predecir que dado una cantidad de metros cuadrados de una habitación este tendrá un valor promedio correspondiente, ahora esto se le denomina un modelo de regresión lineal simple.

Nosotros sabemos que una recta se define como:

Y=w0+w1x

Tal que w0 representa al valor en la cual la recta corta al eje Y y w1 que es la pendiente, la pendiente que representa la inclinación de la recta es la relación que existe entre las variables de entrada X y las variables de salida Y; sin embargo, la realidad resulta ser mucho más compleja; el costo de una habitación no solo está restringido a las dimensiones en metros cuadrados, sino por ejemplo al X2=tipo de barrio en el que se encuentra, X3=cercanías a establecimientos y muchas otras variables más, cuando esto ocurre, y ocurre, nos encontramos ante un modelo de regresión lineal múltiple:

Y=w0+w1x1+w2x2+...+wnxn

En dicha circunstancias, ya no se trata de ubicar la recta para los datos bidimensionales sino del hiperplano que mejor se adapte a la nube de puntos, tal que cada una de las dimensiones representa uno de los atributos.

La forma más adecuada de representar nuestros resultados no es a través de ecuaciones como:

Y1=w0+w1x11+w2x12+w3x13  ...

Y2=w0+w1x21+w2x22+w3x23  ...

Y3=w0+w1x31+w2x32+w3x33  ...

.

.

Sino de forma matricial, donde cada columna es cada una de las características que hemos considerados (tipo de barrio, cercanías a establecimientos, etc.) es decir los datos de entrada y cada fila representa el valor de cada una de las mediciones, podemos llamar a dicha matriz como X, entonces:

regresion4

Así como existen los valores de entrada cada una de las mediciones de las filas de X, tendrá como salida un valor Y, el cual también podemos representar mediante una matriz:

regresion5

Esto ocurre de forma similar con los parámetros :

regresion6

Haciendo uso de la multiplicación de matrices, debemos de multiplicar la matriz X por la matriz transpuesta de W  y obtendremos la matriz Y:

Y=XWt

Lo cual al programarlos resultan más eficientes ya que el computador se entiende mejor con matrices, ahora bien para fines de comprensión vamos a restringir el post a una dimensión, entonces, Si tenemos que el costo de la habitación está relacionado directamente a la cantidad de metros cuadrados de la habitación, entonces nuestro modelo puede ser representado a través de una recta, pero ¿Cómo determinamos cuál es la mejor recta?, uno de los métodos que nos permite obtener la mejor recta es el método de los Mínimos Cuadrados,

MÉTODO DE MÍNIMOS CUADRADOS

entonces sea una función polinomial de la siguiente forma:

Y=a0+a1x+a2x2+...+anxn

Y que podemos representarla de la siguiente forma:

regresion7

Lo que vamos hallar son los residuos o también llamado el error, este residuo es la diferencia que existe entre los puntos de los datos obtenidos y el dato pronosticado por nuestra función, entonces podemos decir que en x1 el valor teórico es y(x1) y un valor experimental y1, y el residuo r1 será:

r1=y1-y(x1)

Podemos generalizar haciendo:

ri=yi-y(xi)

Entonces obtenemos el cuadrado:

regresion8

¿Por qué el cuadrado?, este residuo que estamos hallando podemos interpretarlo como el error del modelo en una variable de entrada (X), elevando al cuadrado estamos penalizando con mayor intensidad aquellos elementos que estén más alejados a nuestro modelo.

Ahora obtenemos la suma de todos los residuos, donde obtendremos un coste total del error, recordemos que el método busca obtener la combinación óptima de parámetros:

regresion9.png

Pero recordemos que y(xi) es la función polinomial, entonces reemplazando tenemos:

regresion10

Ahora nosotros estamos buscando la minimización del coste del error, sabemos que el valor mínimo de una función podemos hallarlo haciendo cero en su derivada, entonces hallemos la derivada de D respecto a cada uno de los parámetros, esta derivación es conocida como derivadas parciales.

regresion11.png

Donde igualamos a cero a cada uno de los resultados parciales:

regresion12

Entonces, volvamos a nuestro modelo de regresión lineal simple  en el que nuestro modelo está representado por la recta:

Y(xi)=w0+w1xi

Y si los datos experimentales son Yobtenemos la sumatoria de residuos:

regresion13

Desarrollamos D y obtenemos:

regresion15

Sabemos que la solución se encontrará en una cantidad n+1 de ecuaciones, de donde obtenemos las derivadas parciales:

regresion14

regresion16

De donde despejamos y obtenemos tal que N sea el total de elementos (ayudas de sumatorias):

regresion17

Ahora despejando w de la primera ecuación en función  de wy reemplazando en la segunda ecuación obtenemos el valor de w1, luego ese valor reemplazamos en la primera ecuación y nos queda:

regresion18

 

Y bueno, esto es lo que tenemos por el momento, cuando tenemos datos reales, podemos incluso someterlo a una matriz y hacer su resolución de forma más sencilla, pues imagina que fueran muchos más atributos.

Java desde Cero – Estructura de Control de Flujo – Bucles 1

Cuando hacemos uso de un programa existen o lo creamos podemos observar que existen operaciones que se han de repetir, por ejemplo imaginemos que nuestro programa tenga que imprimir en consola el conteo de 1 a 100, si lo hiciéramos de forma convencional tendríamos que:

System.out.println(1);
System.out.println(2);
System.out.println(3);
System.out.println(4);
...

Esto resulta ineficiente, al ser una operación que es repetitiva debería poder realizarse a través de una estructura de control de flujo, y estos son los bucles, los bucles también llamados iteradores,  permiten la ejecución reiterada de una sentencia o sentencias, ahora bien, los bucles pueden ser de dos tipos, determinados o indeterminados, los determinados se definen básicamente porque conocemos cuántas veces se han de repetir las operaciones (o cuántas iteraciones se han de realizar) mientras que los indeterminados no sabemos con exactitud cuando han de finalizar ya que dependen de una condición booleana (verdadera o falsa) para continuar o finalizar su ejecución. Java posee 3 estructuras de control de flujo de ejecución que son bucles, estos son la estructura For, While y Do While, vamos realizar una revisión del bucle “For“.

La estructura de un bucle for es la siguiente:

for (inicialización; finalización; incremento) {
       sentencias
}
  • Inicialización: Es una expresión, es de donde ha de iniciar el conteo de las iteraciones, podemos utilizar una variable que ya ha sido declarada e inicializada previamente o podemos hacerlo en esta sección (por ejemplo iniciamos en que a=1).
  • Finalización: Es una expresión booleana que se evalúa su condición de verdadero o falso en cada iteración en función a sí el valor de inicialización ya alcanzó un valor final específico (por ejemplo evaluamos si a <100) y mientras no se haya alcanzado dicho valor las iteraciones han de continuar.
  • Incremento: Es invocada luego de la iteración y posterior evaluación, aquí se define la política de incremento del valor de inicialización (por ejemplo hacemos que a tenga un incremento de 1 en 1 o podemos hacer que vaya de 2 en 2).

Nuestro anterior objetivo era el conteo del 1 al 100, entonces esto en la estructura “for” se implementa de la siguiente forma:

for (int i=0;i<100;i++) {
       System.out.println(i);
}

Observemos que hemos declarado e inicializado la variable “i” en la estructura, recuerda que en java siempre debes definir el tipo de dato, un aspecto a tomar en cuenta es que  el alcance de la variable “i” solo estará circunscrito a la estructura y no existe más allá de ella, sé que aún no hemos hablado del alcance de una variable, pero por el momento piensa en el alcance como la existencia de una variable en un programa, con esto quiero decir que fuera de la estructura la variable “i” no existe y podría marcar un error si es que pretendemos hacer uso de ella. Luego definimos que su terminación será cuando “i” ya no cumpla la condición de ser menor que 100, finalmente establecemos la política de incremento que está dada por un aumento de “i” de 1 en 1.

Ahora bien, en Java la inicialización donde se define la variable, no se puede hacer por fuera, si no nosotros hiciéramos:

int i=0;
for ( i; i < 10; i++) {
   System.out.println(i);
}

Esto nos marcaría un error; para poder hacer uso de una variable que ya está definida, lo que debemos de hacer es dejar el espacio en blanco de su inicialización:

int i=0;
for ( ; i < 10; i++) {
   System.out.println(i);
}

Hecha esta salvedad, veamos un ejemplo en el que le preguntamos al usuario que se ejecute un conteo la cantidad de veces que el desee  y que el defina la política de incremento.

import java.util.Scanner;

public class Bucles_1 {

public static void main(String[] args) {
  Scanner entrada=new Scanner(System.in);

  System.out.println("¿Cuántos números desea contar?");
  int cantidad=entrada.nextInt();
  System.out.println("¿Desde dónde desea iniciar?");
  int inicio=entrada.nextInt();
  System.out.println("¿De cuánto en cuánto desea avanzar?");
  int avance=entrada.nextInt();
  entrada.close();

  for(int i=0;i<cantidad;i++) {
    System.out.println(inicio);
    inicio+=avance;
  }
  }

}

¿Qué hemos hecho?, hemos importado la clase Scanner y hemos hecho las consultas a través de la consola, cada entrada de teclado que responde a las preguntas, se almacena en las variables, nos interesa exactamente la cantidad de veces que se ha de iterar, el cómo se avance y de donde se inicie es casi por así decirlo que será implementado mediante un artilugio, luego de ello implementamos la estructura FOR hacemos que se imprima el primer valor que se ha registrado y luego hacemos que se incremente en función del avance que se ha requerido.

El bucle FOR también puede ser usado con cadenas de texto, es decir las cadenas de texto pueden ser iterados a través  de su longitud, la longitud está determinada por la cantidad de caracteres o espacios en blanco que existan dentro de las comillas que la contienen, por ejemplo: “hola” tiene una longitud de 4 ya que son 4 caracteres que la componen, para determinar la longitud de una cadena que es de la Clase String, debemos hacer uso de uno de sus métodos que se define como length. Entonces podemos implementarlo de la siguiente forma, vamos a hacer que se imprima cada uno de los caracteres de la cadena “hola”, para ello también haremos uso del método chartA(index) que nos devuelve el caracter del indice indicado, debemos saber que la cadena si bien es cierto su longitud es de 4 su índice siempre inicia desde el valor cero, es decir que el índice está yendo de 0 a 3 tal que el índice 0 es “h”, 1 es “o” y así sucesivamente, entonces:

String saludo="hola";
for(int i=0;i<saludo.length();i++) {
    System.out.println(saludo.charAt(i));
}

De este modo, hemos visto las posibilidades del uso del bucle for.

 

 

 

 

Java desde Cero -Estructura de Control de Flujo – Switch

Vamos a revisar el segundo condicional de Java, y este es Switch el cual es una estructura de selección múltiple, la siguiente figura ilustra el ejemplo perfectamente:

switch-statement-flowchart

Si lo observamos con detenimiento veremos que es una expresión de condicionales anidados o que al menos puede ser reemplazado por ellos haciendo que su eso no sea de carácter obligatorio cuando nos encontramos en una situación similar, esto provoca que su uso sea menos; sin embargo, como una estructura del lenguaje es necesario explicarlo ya que aunque pueda ser sustituida en ocasiones brinda claridad en la implementación del código. Esta estructura de control de flujo solo puede evaluar números enteros o todo aquello que se pueda llevar a un entero; es decir, no puede evaluar cadenas, sí puede evaluar caracteres y los tipos enumerados, también sufre la restricción de solo evaluar valores concretos de la expresión y no intervalos  ni expresiones compuestas.

La estructura de Switch, está compuesta por múltiples “case” que es donde se evalúa la condición, un break por cada case que detendrá el flujo por switch y retornará al flujo anterior con las sentencias ya ejecutadas dentro de la opción que ha cumplido la condición y por un default que es opcional y que se ejecutará cuando no haya opción alguna que cumpla la condición.

“Hagamos un ejemplo de su uso, por ejemplo una calculadora ( aunque solo itere una sola vez), le pediremos al usuario que ingrese una opción a través de la consola tal que si es 1 entonces será una suma, 2 será una resta, 3 multiplicación y  4 una división“.

Para la entrada de datos por teclado debemos de hacer uso de la clase Scanner y crear una instancia del mismo, luego debemos de realizar la consulta creando un menú tal como se ha propuesto, además de ello debemos de crear dos variable de tipo double (ya que nuestra división podría terminar en decimales y no se podría realizar un adecuado tratamiento de formato con los tipo int), entonces:

package clases;
import java.util.Scanner;
public class Control_switch {

public static void main(String[] args) {
  Scanner entrada= new Scanner(System.in);
  System.out.println("Ingrese una operación \n 1 -Suma \n 2 -Resta \n 3 -Multiplicación \n 4 -División");
  int opcion=entrada.nextInt();
  double a, b;
  //continua con el switch
}}

Observamos que solo hemos declarado las variables a y b mas no las hemos inicializado, recordemos que según el flujo de ejecución toda variable debe ser declarada e inicializada antes de su uso, así que debemos de asegurarnos de ello para no tener saltos de error, otro aspecto a observar es el uso de “\n” esta sintaxis produce un salto de línea, y nos resulta útil en lugar de estar usando demasiados println.

Ahora debemos de implementar la estructura switch, recordemos que la condición (que será un número entero) recorrerá cada uno de los casos hasta encajar en alguno de ellos, en todas las operaciones (suma, resta, multiplicación y división) haremos uso de la instancia de Scanner para solicitar el ingreso de datos y almacenarlos en las variables a y b respectivamente; y al momento de la impresión es donde hemos de ejecutar la operación que se haya elegido; sin embargo, existe un detalle con la opción de división, en la división nosotros vamos a restringir que la salida del resultado sea a dos decimales, ya que podríamos tener un periódico puro o un número bastante inmenso en la parte decimal y no sería elegante, para poder redondear la salida del dato debemos darle formato, entonces debemos de usar el método printf que ya hemos visto anteriormente, entonces tenemos:

switch (opcion) {
  case 1:
     System.out.println("Ingrese el primer número");
     a=entrada.nextInt();
     System.out.println("Ingrese el segundo número");
     b=entrada.nextInt();
     System.out.println("La suma es: "+(a+b));
     break;
 case 2:
     System.out.println("Ingrese el primer número");
     a=entrada.nextInt();
     System.out.println("Ingrese el segundo número");
     b=entrada.nextInt();
     System.out.println("La resta es: "+(a-b));
     break;
  case 3:
     System.out.println("Ingrese el primer número");
     a=entrada.nextInt();
     System.out.println("Ingrese el segundo número");
     b=entrada.nextInt();
     System.out.println("La multiplicación es: "+(a+b));
     break;
  case 4:
     System.out.println("Ingrese el primer número");
     a=entrada.nextInt();
     System.out.println("Ingrese el segundo número");
     b=entrada.nextInt();
     System.out.print("La división es: ");;
     System.out.printf("%1.2f",(a/b));
     break;
  default:
     System.out.println("No ha elegido alguna de las opciones válidas");
     break;
}
entrada.close();

Luego de finalizada las operaciones no olvidemos en cerrar el flujo de datos, nota en la división que hemos dado el formato adecuado a dos decimales, pero para que todo aparezca en una sola línea hemos usado print sin el salto de línea.