1. Diseño procedimental: algoritmos
1.1. Índice de masa corporal
Diseño algorítmico en pseudocódigo usando los ocho tipos de instrucciones (en español):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Procedimiento Clasificar personas por índice de masa corporal:
Repita mientras hayan datos
Clasifique una persona por índice de masa corporal
Procedimiento Clasificar una persona por índice de masa corporal:
Leer masa, altura en cm
Imprimir masa, altura en cm
Si la masa es válida y la altura en cm es válida entonces
Crear altura en metros como altura en cm / 100
Crear imc como masa / (altura en metros)^2
Crear estado nutricial como el resultado de clasificar indice de masa corporal
Imprimir imc, estado nutricional
De lo contrario
Imprimir "invalid data"
Función Es la masa válida:
Retorne la masa > 0 y la masa es <= 1000
Función Es la altura válida:
Retorne la altura > 0 y la altura es <= 300
Función Clasificar indice de masa corporal:
Si imc < 18.5 entonces
Retorne "underweight"
Si imc < 25 entonces
Retorne "normal"
Si imc < 30 entonces
Retorne "overweight"
Retorne "obese"
Diseño con diagramas de flujo:
1.2. PseInt
PseInt es un intérprete de pseudocódigo que puede ejecutarlo, diagramarlo, y exportarlo a lenguajes de programación. Sólo soporta programas interactivos y no en lote. Ejemplo del índice de masa corporal en esta notación.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
Proceso Clasificar_personas_por_índice_de_masa_corporal // snake_case
Repetir // keywords
Clasificar_una_persona_por_índice_de_masa_corporal
Imprimir "¿Desea clasificar otra persona? [sN]"
Leer continuar
Hasta Que continuar <> "s" Y continuar <> "S" // < >
FinProceso // CamelCase
SubProceso Clasificar_una_persona_por_índice_de_masa_corporal
Escribir "Masa (kg): "
Leer masa
Escribir "Altura (cm): "
Leer altura_en_cm
Imprimir masa, " ", altura_en_cm
Si Es_la_masa_válida(masa) Y Es_la_altura_válida(altura_en_cm) Entonces
Definir altura_en_m Como Real
altura_en_m <- altura_en_cm / 100
imc <- masa / (altura_en_m * altura_en_m)
estado_nutricional <- Clasificar_indice_de_masa_corporal(imc)
Imprimir imc, " ", estado_nutricional
SiNo
Imprimir " invalid data"
Fin Si
FinSubProceso
Funcion resultado <- Es_la_masa_válida(masa)
resultado <- masa > 0 Y masa <= 1000
FinFuncion
// altura_en_cm debe estar en centimetros
Funcion resultado <- Es_la_altura_válida(altura_en_cm)
resultado <- altura_en_cm > 0 Y altura_en_cm <= 300
FinFuncion
Funcion estado_nutricional <- Clasificar_indice_de_masa_corporal(imc)
Si imc < 18.5 Entonces
estado_nutricional <- "underweight"
SiNo
Si imc < 25 entonces
estado_nutricional <- "normal"
SiNo
Si imc < 30 entonces
estado_nutricional <- "overweight"
SiNo
estado_nutricional <- "obese"
FinSi
FinSi
FinSi
Fin Funcion
Funcion resultado <- f(x) // < -
resultado <- x * (x - 1) / 2 // := <-
FinFuncion // 2 * f(3)
2. Sistemas numéricos
2.1. Acumuladores
Las computadoras evolucionan de las calculadoras mecánicas. De la Pascalina se preserva el concepto de acumulador. Es un espacio de la memoria que almacena los dígitos de un número. A diferencia de los humanos, los números en la computadora no pueden tener una cantidad infinita de dígitos, por lo que se trata de una arimética de precisión fija. El siguiente ejemplo suma dos números en una cantidad de dígitos fija.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// Fixed-point precision arithmetic
Algoritmo n_digits_adder10
Leer cantidad_digitos
// Leer los dos numeros como textos
Leer numero1,numero2
// Imprimir numero1 + numero2
// Sacar los digitos de los dos numeros y ponerlos en arreglos
Dimension arr1[cantidad_digitos]
pos_arr <- cantidad_digitos
Para pos_texto<-Longitud(numero1) Hasta 1 Con Paso -1 Hacer
// Imprimir Sin Saltar Subcadena(numero1, pos, pos), ","
digito <- ConvertirANumero(Subcadena(numero1,pos_texto,pos_texto))
arr1[pos_arr] <- digito
pos_arr <- pos_arr-1
FinPara
// Imprimir
Para indice<-1 Hasta cantidad_digitos Hacer
Escribir arr1[indice],',' Sin Saltar
FinPara
// TODO: Eliminar la redundancia de codigo
Dimension arr2[cantidad_digitos]
pos_arr <- cantidad_digitos
Para pos_texto <- Longitud(numero2) Hasta 1 Con Paso -1 Hacer
// Imprimir Sin Saltar Subcadena(numero1, pos, pos), ","
digito <- ConvertirANumero(Subcadena(numero2,pos_texto,pos_texto))
arr2[pos_arr] <- digito
pos_arr <- pos_arr-1
FinPara
// Imprimir
Escribir '' // Separar con un cambio de linea
Para indice <- 1 Hasta cantidad_digitos Hacer
Escribir arr2[indice],',' Sin Saltar
FinPara
// Hacer la suma
Dimension resultado[cantidad_digitos]
acarreo <- 0
Para indice <- cantidad_digitos Hasta 1 Con Paso -1 Hacer
suma <- arr1[indice] + arr2[indice] + acarreo
resultado[indice] <- suma MOD 10
acarreo <- trunc(suma/10)
FinPara
// resultado[1] <- acarreo
// Imprimir
Escribir '' // Separar con un cambio de linea
Para indice <- 1 Hasta cantidad_digitos Hacer
Escribir resultado[indice],',' Sin Saltar
FinPara
FinAlgoritmo
Si el resultado de la suma ocupa más dígitos, los acumuladores anteriores los descartan, lo que provoca una povoca un fenómeno llamado desbordamiento (overflow). Eso nunca ocurre en la matemática humana. Para simular la matemática humana, se pueden crear acumuladores de más dígitos, siempre y cuando se disponga de suficiente memoria en la máquina, lo que genera una aritmética de precisión arbitraria.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// Arbitrary precision arithmetic (software)
Algoritmo n_digits_adder10
Leer cantidad_digitos
// Leer los dos numeros como textos
Leer numero1,numero2
// Imprimir numero1 + numero2
// Sacar los digitos de los dos numeros y ponerlos en arreglos
Dimension arr1[cantidad_digitos]
pos_arr <- cantidad_digitos
Para pos_texto <- Longitud(numero1) Hasta 1 Con Paso -1 Hacer
// Imprimir Sin Saltar Subcadena(numero1, pos, pos), ","
digito <- ConvertirANumero(Subcadena(numero1,pos_texto,pos_texto))
arr1[pos_arr] <- digito
pos_arr <- pos_arr-1
FinPara
// Imprimir
Para indice<-1 Hasta cantidad_digitos Hacer
Escribir arr1[indice],',' Sin Saltar
FinPara
// TODO: Eliminar la redundancia de codigo
Dimension arr2[cantidad_digitos]
pos_arr <- cantidad_digitos
Para pos_texto<-Longitud(numero2) Hasta 1 Con Paso -1 Hacer
// Imprimir Sin Saltar Subcadena(numero1, pos, pos), ","
digito <- ConvertirANumero(Subcadena(numero2,pos_texto,pos_texto))
arr2[pos_arr] <- digito
pos_arr <- pos_arr-1
FinPara
// Imprimir
Escribir '' // Separar con un cambio de linea
Para indice <- 1 Hasta cantidad_digitos Hacer
Escribir arr2[indice],',' Sin Saltar
FinPara
// Hacer la suma
Dimension resultado[cantidad_digitos + 1]
acarreo <- 0
Para indice <- cantidad_digitos Hasta 1 Con Paso -1 Hacer
suma <- arr1[indice] + arr2[indice] + acarreo
resultado[indice + 1] <- suma MOD 10
acarreo <- trunc(suma/10)
FinPara
resultado[1] <- acarreo
// Imprimir
Escribir '' // Separar con un cambio de linea
Para indice <- 1 Hasta cantidad_digitos + 1 Hacer
Escribir resultado[indice],',' Sin Saltar
FinPara
FinAlgoritmo
En las computadoras modernas, la aritmética de precisión arbitraria es provista no por el hardware sino por el software, lo que la hace en el orden de miles de veces más lenta. Un ejemplo es el lenguaje de programación Python, que la incorpora en el lenguaje para números enteros, pero no para números reales.
3. Python
3.1. Entrada y salida
Instrucciones de tipo 1 y 2: leer e imprimir
1
2
3
4
5
6
7
# 1. Read values
line = input("Your name: ")
# 2. Print/Write values
print('Hi ', line, '!', sep='', end='')
# print(line, end='')
# print('!')
print()
3.2. Conversiones de tipo
Python convierte un valor de un tipo de datos a otro usando la notación tipo(valor)
. Los tipos primitivos son:
-
chr
: carácter (ej.: una letra) -
str
: texto (ej.: una o varias letras) -
int
: entero de precisión fija o arbitraria, con o sin signo. -
float
: doble precisión flotante (IEEE-754 de 64 bits)
Debe usarse try/except
si un valor no puede convertirse de un tipo de datos a otro.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
text = None
text = input('Number: ')
try:
text = int(text)
text = 2 * text
print(text)
except ValueError:
pass
# print(text, 'is not a fixed number')
try:
real = float(text)
print(2 * real)
except ValueError:
pass
# print(text, 'is not a floating point number')
print(2 * text)
# 2*10 + 0 = 20
# 20 * 10 + 5 = 205
# Python data types:
# bool: {False, True}
# int: {fixed two-complement + arbitrary precision}
# float: IEEE 754 (double)
# str: Unicode text
# None:
3.3. Condicionales y ciclos
Los ciclos son como los condicionales, sólo que, los condicionales ejecutan la instrucción sólo una vez si la condición es verdadera. En cambio los ciclos se mantienen ejecutando el bloque de instrucciones mientras la condición sea verdadera.
Hay tres tipos de ciclos:
-
Ciclos por contador cuando se sabe la cantidad de repeticiones de antemano.
-
Ciclos por condición, cuando no se sabe la cantidad de repeticiones de antemano.
-
Ciclos por colección, cuando se quiere recorrer todos los elementos de una colección (ejemplo, arreglos).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
try:
while True:
# Read the dimensions of the square
size = int(input("Tamaño: "))
if size == 0:
break
if size > 0 and size <= 20:
# For each line
for row in range(size):
# Print a line
for column in range(size):
print("*", end="")
print()
else:
print("Tamaño debe estar entre 1 y 20")
except ValueError:
print("Tamaño inválido")
3.4. Subrutinas (funciones)
Las subrutinas son bloques se código a los que se les da un nombre, y se pueden invocar desde varios lugares del programa. Permiten reutilizar código, modularizarlo, y hacerlo más legible.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
def print_line(column_count):
for column in range(column_count):
print("*", end="")
print()
def print_square(size):
# For each line
for row in range(size):
# Print a line
print_line(size)
def main():
while True:
try:
# Read the dimensions of the square
size = int(input("Tamaño: "))
if size == 0:
break
if size > 0 and size <= 20:
print_square(size)
else:
print("Tamaño debe estar entre 1 y 20")
except ValueError:
print("Tamaño inválido")
main()
3.5. Arreglos (vectores)
En Python se puede tener una colección de varios valores llamada arreglo o vector (que en terminología Python se llama lista). Un arreglo es como un conjunto de celdas numeradas de forma única. El número que identifica una celda se llama índice. En cada celda se puede guardar lo que se quiera, como un número, un texto, otro arreglo, o dejarla vacía.
1
2
3
4
5
6
7
8
9
10
nombres_1digito = ["cero", "uno", "dos", "tres", "cuatro", "cinco", "seis", "siete", "ocho", "nueve"]
# print(nombres_1digito[3])
while True:
digito = int(input()) # "Digito: "
if (digito >= 0 and digito < len(nombres_1digito)):
print(digito, ': ', nombres_1digito[digito], sep='')
else:
break
Si no se hacen preguntas interactivas al usuario si no que se supone los datos vienen en la entrada con un formato preestablecido, se tiene un programa en lote. Tiene la ventaja de que se puede redireccionar la entrada y la salida para tomar los datos de un archivo en lugar del teclado.
1
2
3
4
5
6
7
8
9
10
nombres_1digito = ["cero", "uno", "dos", "tres", "cuatro", "cinco", "seis", "siete", "ocho", "nueve"]
# print(nombres_1digito[3])
while True:
digito = int(input()) # "Digito: "
if (digito >= 0 and digito < len(nombres_1digito)):
print(digito, ': ', nombres_1digito[digito], sep='')
else:
break
Supóngase que los datos se escriben en un archivo tests/input001.txt
:
1
2
3
4
5
6
7
8
9
8
8
8
2
3
4
5
0
91
Se puede invocar al programa en Python para que tome estos datos en la entrada estándar sin tener que escribirlos manualmente en el teclado. A esto se le llama redireccionar la entrada estándar con el operador <
en la línea de comandos. Es válido tanto en Unix como MS-DOS:
$ python3 arrays.py < tests/input001.txt
8: ocho
8: ocho
8: ocho
2: dos
3: tres
4: cuatro
5: cinco
0: cero