Calculando notas en C++ • Se desea escribir un programa en C++ que calcule la nota final de una asignatura • Esta nota final se calcula como Vectores en C++ 0.2*Examen1 + 0.4*Examen2 + 0.4*prom. Tareas • Queremos conocer la nota final con 3 décimas de precisión Programación Orientada a Objeto Ing. Civil en Telecomunicaciones Calculando notas en C++ Calculando notas en C++ #include <iostream> #include <string> // Solicita las notas de las tareas cout << "Ingrese las notas de sus tareas, terminando con Ctrl-D: "; // Indica que el programa usara estos objetos // Esto puede ser reemplazado por using namespace std; using std::cin; using std::cout; using std::endl; using std::string; // Contador y sumatoria de las notas int contador = 0; double suma = 0; int main() { // Solicita el nombre del alumno cout << "Ingrese su nombre: "; string nombre; cin >> nombre; cout << "Hola, " << nombre << "!" << endl; // Ciclo de lectura while (cin >> temp) { ++contador; suma += temp; } // Solicita las notas de los examenes cout << "Ingrese las notas de sus examenes: "; double examen1, examen2; cin >> examen1 >> examen2; Comando using • En el programa usamos varias veces los objetos std::cin, std::cout, std::endl, std::string std::cin indica al compilador que toda referencia a cin es a std::cin Permite abreviar el nombre del objeto // Variable auxiliar double temp; // Escribe el resultado cout << "Su nota final es " << 0.2*examen1 + 0.4*examen2 + 0.4*suma/contador << endl; return 0; } Entrada de datos encadenada y fin de archivo • Declaración using • Podemos ahorrar trabajo usando el comando using namespace std; Al igual que se encadenan salidas de datos a cout, se pueden encadenar entradas de datos desde std::cin cin >> examen1 >> examen2 El programa espera que se ingresen 2 datos antes de continuar • Entrada de datos termina ante fin de archivo © 2015 Mario Medina C. O su equivalente ASCII, Control-D 1 Precisión de resultados Precisión de resultados • Ejemplo anterior no fija la precisión del resultado #include <iomanip> Es necesario usar los manipuladores de flujo setprecision() y fixed() Necesario incluir <iomanip> • Además, vamos a usar la función miembro cout.precision() para obtener la precisión actual para luego restaurarla // Escribe el resultado streamsize prec = cout.precision(); cout << "Su nota final es " << fixed << setprecision(3) << 0.2*examen1 + 0.4*examen2 + 0.4*suma/contador << setprecision(prec) << endl; fixed y setprecision(3) imprime 3 dígitos significativos Precisión actual se almacena en objeto de tipo streamsize Calculando notas en C++ Calculando la mediana • Ahora, en vez de usar el promedio de las tareas, se quiere usar la mediana de las notas • Qué es la mediana? • Suponiendo que la lista Q tiene N notas ordenadas • N impar: mediana es el elemento Q(N – 1)/2 “El elemento del medio” de una lista El valor de una lista que deja el mismo número de datos antes y después que él Aquel valor que divide al conjunto en dos partes iguales Mediana de 3.4, 4.5, 5.6, 6.1, 6.9 es 5.6 • N par: mediana es el promedio de los elementos QN/2 y Q(N – 1)/2 Mediana de 3.4, 4.5, 5.6, 5.8, 6.1, 6.9 es 5.7 Calculando la mediana Lectura de datos a un vector • Para calcular la mediana de una lista de notas, todas las notas deben estar a mano • Almacenar los datos en un vector • Declaración de vector de tipo double • Función miembro push_back() agrega elemento al final del vector Clase de C++ que almacena una secuencia de datos del mismo tipo Acceso via subíndices en forma similar a C Varía su tamaño en forma dinámica sin necesidad de solicitar memoria al S. O. Funciones miembros para tareas comunes © 2015 Mario Medina C. // Vector de notas vector<double> notas; double temp; while (cin >> temp) { notas.push_back(temp); } 2 Cálculo de la mediana • Cálculo de la mediana usando el operador ?: del C Variable mid contiene tamaño del vector/2 double mediana; mediana = (size%2 == 0) ? (notas[mid] + notas[mid - 1])/2 : notas[mid]; Cálculo de la mediana • Almacenar tamaño del vector en una variable typedef vector<double>::size_type vec_size; vec_size size = notas.size(); if (size == 0) { cout << endl << "Debe ingresar al menos una nota. Intente de nuevo " << endl; return 1; Qué pasa si vector está vacío? notas[mid – 1] falla Vector no valida rango de acceso } Comando typedef Cálculo de la mediana • Tamano de un vector de double es un entero de tipo vector<double>::size_type • Comando typedef permite definir nuevo nombre para ese tipo de dato • Cálculo de la mediana requiere que los datos estén ordenados en forma nodecreciente typedef vector<double>::size_type vec_size; De esta forma, se escribe menos y se evitan errores La interpretacion de typedef es hecha por el compilador Calculando la mediana en C++ (I) #include #include #include #include #include <algorithm> <iomanip> <iostream> <string> <vector> // Indica que programa usara objetos de biblioteca estandar using namespace std; int main() { // Solicita el nombre del alumno cout << "Ingrese su nombre: "; string nombre; cin >> nombre; cout << "Hola, " << nombre << "!" << endl; © 2015 Mario Medina C. Para eso, usaremos función sort() de la biblioteca de algoritmos de C++ sort(notas.begin(), notas.end()); Declarada en <algorithm> Sus argumentos son iteradores al primer y último elemento del vector a ordenar Calculando la mediana en C++ (II) // Solicita las notas de los examenes cout << "Ingrese las notas de sus examenes: "; double examen1, examen2; cin >> examen1 >> examen2; // Solicita las notas de las tareas cout << "Ingrese sus tareas, terminando con ^D: "; vector<double> notas; double temp; // Vector de notas // Variable auxiliar // Ciclo de lectura while (cin >> temp) { notas.push_back(temp); } 3 Calculando la mediana en C++ (III) // Verificar que se ingresaron notas typedef vector<double>::size_type vec_size; vec_size size = notas.size(); if (size == 0) { cout << endl << "Debe ingresar al menos una nota. “ << "Intente de nuevo " << endl; return 1; } // Ordenar las notas sort(notas.begin(), notas.end()); Calculando la mediana en C++ (IV) // Escribe el resultado // Almacena la precision actual para no perderla streamsize prec = cout.precision(); cout << "Su nota final es " << fixed << setprecision(3) << 0.2*examen1 + 0.4*examen2 + 0.4*mediana << setprecision(prec) << endl; return 0; } // Calcular la mediana vec_size mid = size/2; double mediana; mediana = (size%2 == 0) ? (notas[mid] + notas[mid - 1])/2 : notas[mid]; Más sobre vector() Inicializacion mediante listas • En vez de usar if (size == 0) {, podría haberse usado la función miembro datos.empty(), que retorna un valor booleano true si el vector está vacío • El estándar garantiza que los elementos de un vector están almacenados en forma contigua en memoria • Función miembro data() retorna un puntero al primer elemento del vector (C++11) • En C++, es posible inicializar variables mediante asignacion o mediante listas Inicializacion de vectores via listas Inicializadores de objetos via listas • C++03 tenia inconsistencias en la inicialización de vectores mediante listas • En C++11, las siguientes inicializaciones son válidas int vect[5] = {0, 1, 2, 3, 4}; // valido vector<int> vec[5] = {0, 1, 2, 3, 4}; // No! • C++11 permite inicializar vectores de la STL mediante listas Todas las clases estándar de STL ya incluyen double d1 = 2.3; d2 = {4.5}; double d3 {6.7}; double • Inicializacion mediante listas previene errores de conversion y truncado int int i1 = 2.3; // Codigo valido i2 {2.3}; // Genera error int j{}; // Inicializado a 0 int *p{}; // Inicializado a nullptr vect1[5] {0, 1, 2, 3, 4}; vector<int> vect2 {5, 6, 7, 8, 9}; vector<string> nombres {“Pedro”, “Juan”, “Diego”}; esta funcionalidad en C++11 © 2015 Mario Medina C. 4 Tipo de dato auto Ejemplos de tipo de dato auto • Tipo de dato auto hace que el compilador infiera el tipo de una variable de su inicialización • Tipo de dato auto vector<double>::size_type size = notas.size(); size = notas.size(); puede escribirse como auto Compilador deduce que size tiene tipo std:: vector<double>::size_type auto auto auto auto x y z t = = = = 5; 5.5; y; “H”; // x tiene tipo int // y tiene tipo double // z tiene tipo double // t tiene tipo // const char * vector<int> v[5]; auto b = v[0]; // b tiene tipo int Recorriendo un vector Recorriendo un vector usando rangos • Forma estandar de recorrer un vector • Ejemplo anterior saca una copia de cada elemento y luego la descarta • Para no sacar la copia, o para modificar el contenido, se puede usar una referencia int v[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; for (auto i = 0; i != 10; i++) cout << v[i] << endl; • Recorriendo un vector usando un rango for (auto x : v) // Para todo x en v cout << x << endl; Saca una copia de cada elemento en x y luego la descarta for (auto y : {10, 21, 32, 43, 54, 65}) cout << y << endl; © 2015 Mario Medina C. int v[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; for (auto& x : v) // Modifica el vector ++x; for (auto x : v) // Imprime 1 a 10 cout << x << endl; 5