[C con Clase] Hijo, comprueba tu división con esto.

marcelinux marcelinator en gmail.com
Mar Oct 7 22:26:11 CEST 2014


Hola a todos.
Ya os habréis dado cuenta de que vervose es un "gazapo", pero cumplió su misión.
He implementado una nueva versión de la división.
Esta vez he creado una clase que simula una hoja cuadriculada donde se "pintará" la división.
Para eso ya he usado dos archivos (definición y declaración), más el archivo con el main().
Para la próxima versión, controlaré que sólo se permita introducir números.
La siguiente, admitirá las cantidades como argumentos del programa.
Más adelante, usaré la función ldiv(num,denom) en lugar de las de la clase Division, GetCociente y GetResto.
La última debería ser con una interfaz gráfica.
Ni que decir tiene que agradeceré cualquier crítica o referencia para mejorar, tanto el código como los conceptos que he manejado.

Os pego los tres archivos y el resultado del ejemplo.
Como lo he hecho en ubuntu, el comando de compilación ha sido:
g++ -odividete_v3 dividete_v3.cpp division_v3.cpp

[Archivo division_v3.h]
/* Clase Division
 * Versión 3
 * Declaración
 */
#ifndef DIVISION_V3_H
#define DIVISION_V3_H

#define MAX_CIFRAS 9
#define NUM_FILAS 15
#define NUM_COLUMNAS 20

class Division
{
	public:
		Division(long numerador, long denominador);
		long BajaLaCifraSiguiente();
		long GetCociente(long num);
		long GetResto(long num);
		void DibujaLaDivision();	// Dibuja el enunciado de la división en la hoja
		void Pinta();				// Muestra la hoja con la división completa
		int GetNumeroDeCifras(long numero);
	private:
		// miembros
		// Son char para simular la colocación de cada cifra en su posición
		char m_dividendoChar[MAX_CIFRAS];
		long m_divisor;
		char m_divisorChar[MAX_CIFRAS];
		char m_cocienteChar[MAX_CIFRAS];
		char m_restoChar[MAX_CIFRAS];
		int m_cifra;
		int m_fila;
		char m_cuadricula[NUM_FILAS][NUM_COLUMNAS];	// Simula una página cuadriculada
};

#endif	// DIVISION_V3_H


[Archivo division_v3.cpp]
/* Clase Division
 * Versión 3
 * Definición
 */
#include "division_v3.h"

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <math.h>

using namespace std;

#undef verbose

Division::Division(long numerador, long denominador) 
{
	for(int i = 0; i < MAX_CIFRAS; i++)
	{
		m_dividendoChar[i] = ' ';
		m_divisorChar[i] = ' ';
		m_cocienteChar[i] = ' ';
		m_restoChar[i] = ' ';
	}
	m_dividendoChar[MAX_CIFRAS] = 0;
	m_divisorChar[MAX_CIFRAS] = 0;
	m_cocienteChar[MAX_CIFRAS] = 0;
	m_restoChar[MAX_CIFRAS] = 0;
	m_divisor = denominador;
	sprintf(m_dividendoChar, "%ld", numerador);
	sprintf(m_divisorChar, "%ld", denominador);
	m_cifra = 0;
	m_fila = 0;
	for(int f = 0; f < NUM_FILAS; f++)
		for(int c = 0; c < NUM_COLUMNAS; c++)
			m_cuadricula[f][c] = ' ';
}

long Division::BajaLaCifraSiguiente()
{
	char c[MAX_CIFRAS];
	sprintf(c, "%c", m_dividendoChar[m_cifra]);
	#ifdef verbose
		cout << "\nBajaLaCifraSiguiente obtiene '" << m_dividendoChar[m_cifra] << "'";
	#endif
	#ifdef verbose
		cout << "\nBajaLaCifraSiguiente añade   '" << c << "'";
	#endif
	strncat(m_restoChar, c, 1);
	#ifdef verbose
		cout << "\nBajaLaCifraSiguiente y queda '" << m_restoChar << "'";
	#endif
	long restoTemp = atol(m_restoChar);
	#ifdef verbose
		cout << "\nBajaLaCifraSiguiente convertida a long " << restoTemp;
	#endif
	m_fila++;
	#ifdef verbose
		cout << "\nBajaLaCifraSiguiente va a la fila " << m_fila;
	#endif
	for(int col = 0; col <= m_cifra; col++)
		m_cuadricula[m_fila][col] = m_restoChar[col];
	#ifdef verbose
		Pinta();
	#endif
	return restoTemp;
}

long Division::GetCociente(long numerador)
{
	long cocienteTemporal = numerador / m_divisor;
	#ifdef verbose
		cout << '\n' << numerador << " entre " << m_divisor << " es " << cocienteTemporal;
	#endif
	char s[MAX_CIFRAS];
	sprintf(s, "%ld", cocienteTemporal);
	strncat(m_cocienteChar, s, 1);
	#ifdef verbose
		cout << "\nCociente combinado:" << m_cocienteChar;
	#endif
	long cociente = atol(m_cocienteChar);
	return cociente;
}

long Division::GetResto(long numerador)
{
	long resto = numerador % m_divisor;
	int cifrasResto = GetNumeroDeCifras(resto);
	#ifdef verbose
		cout << "\nEstoy en la cifra " << m_cifra;
	#endif
	sprintf(m_restoChar, "%*ld", m_cifra + 1, resto);
	#ifdef verbose
		cout << "\nrestoChar queda: '" << m_restoChar << "'";
	#endif
	m_cifra++;
	return resto;
}

void Division::DibujaLaDivision()
{
	#ifdef verbose
		cout << "Dibuja divisorChar:" << m_divisorChar;
	#endif
	int posicion = NUM_COLUMNAS - MAX_CIFRAS;
	for(int c = 0; c < posicion; c++)
		if(m_dividendoChar[c] >= '0')
			m_cuadricula[0][c] = m_dividendoChar[c];
	m_cuadricula[0][posicion] = '|';
	for(int c = 0; c < posicion; c++)
		if(m_divisorChar[c] >= '0')
			m_cuadricula[0][posicion+2+c] = m_divisorChar[c];
	m_cuadricula[1][posicion] = 'L';
	for(int c = posicion+1; c < NUM_COLUMNAS; c++)
		m_cuadricula[1][c] = '_';
	m_fila = 1;
}

void Division::Pinta()
{
	int posicion = 2 + (NUM_COLUMNAS - MAX_CIFRAS);
	for(int c = 0; c < MAX_CIFRAS; c++)
		if( (m_cocienteChar[c] >= '0') && (m_cocienteChar[c] <='9') )
			m_cuadricula[2][c + posicion] = m_cocienteChar[c];

	for(int f = 0; f < NUM_FILAS; f++)
	{
		cout << endl;
		for(int c = 0; c < NUM_COLUMNAS; c++)
			cout << m_cuadricula[f][c];
	}
	cout << endl << endl;
}

int Division::GetNumeroDeCifras(long numero)
{
	int cifras = int(log10(numero)) + 1;
	/* Gracias Steven
	 * Definitivamente, las matemáticas no son mi fuerte.
	 */
	return cifras;
}



[Archivo dividete_v3.cpp]
/* Proyecto: dividete. Comprobar una división en modo texto.
 * Versión 3
 * Autor   : Marcelino Gisbert
 * Objetivo: El alumno introducirá el dividendo y el divisor.
 *           La aplicación calculará el número de cifras del dividendo y las del denominador.
 *           Se repetirán tantas divisiones enteras con las cifras del denominador
 *           para ir construyendo la división tal y como se haría a mano.
 *           Se mostrará en una rejilla a modo de papel cuadriculado.
 * TODO
 *           Debo resolver el inconveniente de introducir letras en lugar de números.
 *           Para probar, me ceñiré al ejemplo.
 *           En la versión 3, probaré el formateo de la entrada.
 *           También se implementará una versión que acepte las cantidades como parámetros
 *           de main.
 *
 * Ejemplo:
 *           Dado el dividendo: 35437
 *           Y el divisor.....: 283
 *           El proceso sería :
 *           Se escribe el dividendo (hasta 19 cifras)
 *           A continuación, el divisor tras su "separador"
 *           En la siguiente línea cerramos el operador de división.
 *           Quedaría así:
 *           35473              | 283
 *                              L____________________

 *           Obtener el número de cifras de 35437: 5
 *           Se baja una cifra hasta que se pueda dividir.
 *           Primero el 3
 *           Se divide y se obtiene el resto de la división entera: 3
 *           Se baja la cifra siguiente: el 5.
 *           Se añade al resto anterior: 35.
 *           Se divide y se obtiene el resto: 35.
 *           Se baja la cifra siguiente: el 4.
 *           Se añade al resto anterior: 354.
 *           Se divide y se obtiene cociente (1) y el resto (71).
 *           Se baja la cifra siguiente: el 3.
 *           Se añade al resto anterior: 713.
 *           Se divide y se obtiene el cociente (2) y el resto (147).
 *           Se baja la cifra siguiente: el 7.
 *           Se añade al resto anterior: 1477.
 *           Se divide y se obtiene el cociente (5) y el resto (62).
 *           Acabaron las cifras del dividendo.
 *           El resultado se ve escalonado: cociente 125, resto 62.
 */

#include <iostream>

#include "division_v3.h"

using namespace std;

void MuestraAyuda()
{
	cout << "\n\nHijo, comprueba tu división." << endl;
	cout << "Lo ha hecho papá para que ganes tiempo en tus deberes." << endl;
	cout << "No para que hagas trampa ;-)" << endl;
	cout << "Funciona así:" << endl;
	cout << "Primero te pediré el dividendo." << endl;
	cout << "\tDebes escribir un número mayor o igual a 0." << endl;
	cout << "\tSi escribes un cero, se termina." << endl;
	cout << "Después te pediré el divisor." << endl;
	cout << "Entonces iré escribiendo la división como lo harías tú en papel." << endl;
	cout << "Bueno, más o menos :-)" << endl;
	cout << "Vale. ¡Vamos allá!" << endl;
}

long GetDividendo()
{
	long numerador = 0;
	cout << "Dame el dividendo (Recuerda que 0 es para terminar)" << endl;
	cin >> numerador;
	return(numerador);
}

long GetDivisor()
{
	long denominador = 0;
	cout << "Dame el divisor (no puede ser 0)" << endl;
	cin >> denominador;
	return(denominador);
}

int main()
{
	MuestraAyuda();
	long numerador = 1, denominador = 1;
	while( numerador = GetDividendo() )
	{
		if(numerador)
		{
			if( denominador = GetDivisor() )
			{
				Division *pagina = new Division(numerador, denominador);
				pagina->DibujaLaDivision();
				#ifdef verbose
					pagina->Pinta();
				#endif
				int cifrasNumerador = pagina->GetNumeroDeCifras(numerador);
				for(int cifra = 0; cifra < cifrasNumerador; cifra++)
				{
					long numSiguiente = pagina->BajaLaCifraSiguiente();
					long cocParcial = pagina->GetCociente(numSiguiente);
					long resParcial = pagina->GetResto(numSiguiente);
				}
				// Al bajar la cifra siguiente a la última es
				// cuando se coloca en la cuadrícula.
				pagina->BajaLaCifraSiguiente();
				pagina->Pinta();
				delete pagina;
			}
		}
		cout << endl ;
	}
	return 0;
}


[Resultado]
marcelinux en HP:~/ds$ g++ -odividete_v3 dividete_v3.cpp division_v3.cpp
marcelinux en HP:~/ds$ ./dividete_v3


Hijo, comprueba tu división.
Lo ha hecho papá para que ganes tiempo en tus deberes.
No para que hagas trampa ;-)
Funciona así:
Primero te pediré el dividendo.
	Debes escribir un número mayor o igual a 0.
	Si escribes un cero, se termina.
Después te pediré el divisor.
Entonces iré escribiendo la división como lo harías tú en papel.
Bueno, más o menos :-)
Vale. ¡Vamos allá!
Dame el dividendo (Recuerda que 0 es para terminar)
35437
Dame el divisor (no puede ser 0)
283

35437      | 283    
           L________
3            00125  
35                  
354                 
 713                
 1477               
   62              

__________________________________________________________________
Programador, ávido de conocimiento y algo testarudo.
Gracias a todos los que comparten. Espero poder devolver el favor.


Más información sobre la lista de distribución Cconclase