Serie ficheros virtuales 

 

 

C Ficheros Virtuales

 

 

 

A.II Ejemplos

 

 

 

A.II.5 Cuadre de sumas y redondeos

 

  A.II.5.1 Presentación

  A.II.5.2 Interfaz

  A.II.5.3 Las estructuras de soporte de la implementación

  A.II.5.4 Implementación del interfaz PSRRCR y de los servicios de la DLL SRRCR

 

 

                                                                                                    _______

 

 

A.II.5.1 Presentación

 

Al sumar cantidades redondeadas y compararlas con la suma redondeada original pueden aparecer diferencias. Si es imperativo cuadrar estas diferencias se debe promocionar o postergar alguna cantidad redondeada para que las sumas coincidan.

 

Esta promoción o postergación debe hacerse de forma justa, los elementos con decimales más cercanos superiormente a 0,500 serán los postergables y los elementos inmediatamente inferiores a 0,500 los promocionables. Además, deben elegirse primero los más cercanos y tener en cuenta que los elementos una vez promocionados ya no deben entrar de nuevo en el proceso de selección.

 

Esta técnica no es adecuada para importes contables, pues las diferencias deben llevarse en una cuenta específica, pero si lo es para reglas de asignación a epígrafes.

 

Veamos un ejemplo concreto:

 

            Importe

Importe

     Ítem

 Origen  Redondeado Ajustado

Origen   Redondeado Ajustado

       01

 721,488    721       722 *

390,728     391        391

       02

 165,532    166       166

753,044     753        753

       03

 810,450    810       810

723,411     723        723

       04

 57,283     57        57

407,727     408        408

       05

 933,622    934       934

767,113     767        767

       06

 468,978    469       469

355,632     356        355 *

       07

 824,488    824       824

378,704     379        379

       08

 9,491      9        10 *

77,761      78         78

       09

 791,406    791       791

772,820     773        773

       10

 660,817    661       661

519,547     520        519 *

 

 

Sumas        5.443,555  5.442     5.444

5.146,487   5.148      5.146

 

 

Diferencia                  1,555    -0,445

-1,513      0,487

 

 

Redondeo     5.444      5.442     5.444

5.146       5.148      5.146

 

 

Diferencia                2         0

-2          0

 

 

Ajuste                              2

-2

 

En la primera muestra, la suma origen difiere en 1,555 de la suma de redondeos, por lo que habrá que promocionar 2 cantidades, las más próximas a 0,5 inferiormente.

 

En la segunda muestra, la suma origen difiere en -1,513 de la suma de redondeos, por lo que habrá que postergar 2 cantidades, las más próximas a 0,500 superiormente.

 

Las cantidades ajustadas se presentan marcadas con un *.

 

 

Tras el ajuste, la suma redondeada origen y la suma de las cantidades redondeadas y ajustadas coinciden.

 

                                                                                                   _______

 

A.II.5.2 Interfaz

 

Veamos ahora la imagen completa de una muestra generada por el interfaz Psrrcr

 

 

 

 

 

La resolución del problema es sencilla disponiendo de una base de datos que resuelva la cuestión del orden involucrado, que es la parte implícitamente compleja del tema.



Se presentará una solución en C, sin embargo conviene comentar que la solución en ILE-RPG tiene una codificación más sencilla ya que de un lado la separación de enteros y decimales es más fácil, y de otro la definición de la estructura de soporte puede hacerse más sencilla.

 

                                                                                                   _______

 

 

A.II.5.3 Las estructuras de soporte de la implementación

 

Las estructuras de soporte del fichero virtual base de la resolución del problema viene dada como

 

 

 

SRRCRDS.h: Estructuras del servicio de reorganización de sumas

 

 

 

 

// Ds de claves de acceso a los términos de la matriz a ajustar en redondeos

 

struct sDK // Estructura de claves de acceso a nodos (i,j)

{

 long li; // Indice i del nodo (Fila)

 long lj; // Indice j del nodo (Columna)

};

 

 

// Ds de claves de enlace origen

 

static struct sDK00 // Estructura de claves de enlace origen

// (Identificación ítem i en origen)

{

 long lk1; // Clave 1 enlace origen

 long lk2; // Clave 2 enlace origen

           // ... Ampliar según se precise

char EOR; // Marca de fin de estructura

} DK00;

 

 

// Ds de claves de acceso alternativo (j,i)

 

struct sDK01 // Estructura de claves de acceso a nodos (j,i)

{

 long lj; // Indice j del nodo

 long li; // Indice i del nodo

};

 

 

 

 

 

// Ds claves del lógico para lectura de ítems a promocionar superiormente

 

struct sDK02 // Lógico s/promocionables en cada columna (decimales > 0.5)

{

 long lj;    // Indice j del nodo

 long lDeci; // parte decimal inversa de promocionables (9's - decimales ítem)

 long li;    // Indice i del nodo

 char EOR;   // Marca de fin de estructura

             // Se incluye para eludir anomalías en la respuesta de sizeof, tal

             // como se explica en el capítulo de estructuras

};

 

 

// Ds claves del lógico para lectura de ítems a postergar inferiormente

 

struct sDK03 // Lógico s/postergables en cada columna (decimales < 0.5)

{

 long lj;    // Indice j del nodo

 long lDeci; // parte decimal elementos postergables (decimales < 0.5)

 long li;    // Indice i del nodo

 char EOR;   // Marca de fin de estructura

};

 

 

// Ds claves del lógico para lectura de ítems por clave de enlace origen

 

struct sDK04 // Lógico s/identificación origen

{

 struct sDK00 DK00; // Identificación ítem i en origen

 long lj;  // Indice j del nodo

 long li;  // Indice i del nodo (Redundante, previene DK00 nula)

 char EOR; // Marca de fin de estructura

};

 

 

 

 

 

// Ds datos del fichero virtual de soporte de la matriz a ajustar en redondeos

 

struct sDD // Estructura de datos de a ajustar en redondeos

{

 double dImpo;     //Importe original

 double dEnteOr;   //Parte entera de la cantidad original

 long lDeciOr;     //Parte decimal de la cantidad original

 double dImpr;     //Importe redondeado a miles con 3 decimales

 double dEnteRdOr; //Parte entera de la cantidad original redondeada a miles con 3 decimales

 long lDeciRdOr;   //Parte decimal de la cantidad original redondeada a miles con 3 decimales

 double dEnteRROr; //Parte entera de la cantidad original redondeada2 a miles con 0 decimales

 double dEnteRRAj; //Parte entera de la cantidad ajustada redondeada2 a miles con 0 decimales

};

 

 

 

 

 

// Ds del fichero virtual resultante para ajuste de la matriz de sumas

 

static struct sDsKD

{

 struct sDK DK;     // Clave principal (ij)

 struct sDK01 DK01; // Clave alternativa (ji)

 struct sDK02 DK02; // Clave secundaria(promocionables)

 struct sDK03 DK03; // Clave secundaria(postergables)

 struct sDK04 DK04; // Clave enlace origen ("i"j)

 struct sDD DD;     // Datos

} DSRSUM;

 

 

 

                                                                                                     _______

 

 

A.II.5.4 Implementación del interfaz PSRRCR y de los servicios de la DLL SRRCR

 

Una codificación de uso de los servicios de resolución de problema se presenta en el programa de muestra Psrrcr.

 

Psrrcr generará muestras aleatorias de series de importes como la presentada arriba, que se reordenarán utilizando los servicios de la DLL SRRCR que se relacionan a continuación:

 

 

long SRRCR_CHAIN(int i, int j, void *pDSRSUM);

 

Recupera 1 ítem del conjunto reorganizado de importes

 

 

short int SRRCR_ERASE(void);

 

 

Elimina la base de datos virtual soporte de proceso

 

long SRRCR_NEW(void);

 

Crea la base de datos virtual soporte de proceso

 

 

short int SRRCR_REORGANIZE(int M, int N);

 

Reorganización central

 

long SRRCR_WRITE(int i, int j, double dImpo,

                               const void *pDK00);

Grabación de ítems a reorganizar

 



La codificación de Psrcr se centra esencialmente en el botón OK y consiste en

 

...

 

// Generación de muestras

 

er = PrGen(M, N);

 

 

 

// Proceso de resumación

 

er = SRRCR_REORGANIZE(M, N);

 

 

// Bucles de extracción de importes ajustados

 

 

// En filas

 

for (i=1;i<=M;++i)

{

 

 // En columnas

 

 for (j=1;j<=N;++j)

 {

  // Extrae ítem ij y lo representa

 

  lresul = SRRCR_CHAIN(i, j, &DSRSUM);

 

  m_LIST.AddString(DSRSUM);

 

 }

}

 

...

 

 

// Pasa resultados a pantalla

 

UpdateData(false);

 

...

 

                                                                                                   _______

 

 

Los servicios más importantes de SRRCR, WRITE y REORGANIZE, se presentan extractados a continuación, el resto son interfaces directos a funciones de SRRCW sobre el fichero virtual de soporte usado internamente; en cualquier caso, todos ellos pueden consultarse en las carpetas de proyecto

 

//------------------------------------------------------------------------------

// Función: SRRCR_WRITE

//

// Descripción: Graba 1 ítem del conjunto a reorganizar de las sumas de 1 informe

//

// Parámetros:

// (I) i: Identificador de fila de la matriz "DSRSUM" a ajustar

// (I) j: Identificador de columna de la matriz "DSRSUM" a ajustar

// (I) dImpo: Importe origen a ajustar

// (I) pDK00: Puntero a klist de enlace origen

//

// Retorno: NºIndice archivo ítem (i,j) 0=Error de proceso

//------------------------------------------------------------------------------

long SRRCR_WRITE(int i, int j, double dImpo, const void *pDK00)

{

 double deci = 0.0; // Auxiliar cálculo decimales

 double dImpr = 0.0; // Auxiliar redondeo 3 dec

 double dImrr = 0.0; // Auxiliar redondeo 0 dec

 

 

 // Pasa campos de la estructura soporte de reorganización de sumas

 

 

 // Paso común de claves - índices en todas las vías de acceso

 

 DSRSUM.DK.li = i;

 DSRSUM.DK.lj = j;

 

 DSRSUM.DK01.li = i;

 DSRSUM.DK01.lj = j;

 

 ...

 

 

 // Paso de importe origen, descomposición en parte entera y decimal

 

 DSRSUM.DD.dImpo = dImpo;

 DSRSUM.DD.lDeciOr = PrDeci(dImpo, &DSRSUM.DD.dEnteOr);

 

 

Ejemplo numérico:

 

dimpo 111.81981872005 --> EnteOr 111 + DeciOr .819818720

 

 

 

 

 // Paso de importe redondeado a 3 decimales, descomposición entera y decimal

 

 dImpr = SRRCU_ROUND(1000.0 * dImpo) / 1000.0;

 

 DSRSUM.DD.dImpr = dImpr;

 DSRSUM.DD.lDeciRdOr = PrDeci(dImpr, &DSRSUM.DD.dEnteRdOr);

 

 

Ejemplo numérico:

 

dimpo 111.81981872005 --> dimpr 111.82000000000

                      --> EnteRdOr 111 + DeciRdOr .820000000

 

 

 

 // Paso de importe redondeado a 0 decimales

 

 DSRSUM.DD.dEnteRROr = SRRCU_ROUND(dImpo);

 

 

 

Ejemplo numérico:

 

dimpo 111.81981872005 --> dEnteRRor 112

 

 

 

 // Paso de la vía de acceso de enlace origen

 

 memcpy(&DSRSUM.DK04.DK00, pDK00, sizeof(DSRSUM.DK04.DK00));

 

 

 // Paso de claves, importes

 

 DSRSUM.DK02.lDeci = 999999999;

 DSRSUM.DK03.lDeci = 999999999;

 

 if (DSRSUM.DD.lDeciRdOr < 500000000) DSRSUM.DK02.lDeci -= DSRSUM.DD.lDeciRdOr;

 else                                 DSRSUM.DK03.lDeci  = DSRSUM.DD.lDeciRdOr;

 

 

 

Ejemplos numéricos:

 

dimpo 111.81981872005 --> dimpr 111.8200000000

                      --> EnteRdOr 111 + DeciRdOr .820000000

                      --> DK02.lDeci 999999999 DK03.lDeci 820000000

 

 

dimpo 950.31586657308 --> dimpr 950.3160000000

                      --> EnteRdOr 950 + DecoRdOR .316000000

                      --> DK02.lDEci 684000000 DK03.lDeci 999999999

 

 

 

 // Graba estructura a ajustar

 

 return SRRCW_WRITE("DSRSUM", &DSRSUM);

}

 

                                                                                                     _______

      

 

Una vez grabados los ítems mediante SRRCR_WRITE, la reorganización de ajuste, promoción y resumación de los mismos es tarea de la función siguiente:

 

//------------------------------------------------------------------------------

// Función: SRRCR_REORGANIZE

//

// Descripción: Reorganiza las sumas de un informe, soportado por una matriz aij

//

// Parámetros:

// (I) M: Nº filas de la matriz "DSRSUM" a ajustar

// (I) N: Nº cols. de la matriz "DSRSUM" a ajustar

//

// Retorno: 0/1 Error de proceso

//------------------------------------------------------------------------------

short int SRRCR_REORGANIZE(int M, int N)

{

 short int er = 0;   // Control de errores

 short int iSigno=0; // Marca de diferencia a ajustar. 1=Sumará -1=Restará

 int i=0;            // Contador de for en filas 1..M

 int j=0;            // Contador de for en columnas 1..N

 int iAjus=0;        // Diferencia a ajustar, neta

 long lresul = 0;    // control de resultados en SRRCW

 double dSum1 = 0.0; // Suma de importes redondeados a 3 dec

 double dSum2 = 0.0; // Suma de importes redondeados a 0 dec

 double dAjus = 0.0; // Diferencia a ajustar, bruta

 

 

 // Bucle en columnas a ajustar

 

 for (j=1;j<=N;++j)

 {



  // Inz.contadores parciales

 

  dSum1 = dSum2 = 0.0;

 

 

  // Situa para bucle de lectura del cálculo de subtotales de la columna actual

 

  DSRSUM.DK01.lj = j;

 

  lresul = SRRCW_SETLL("DSRSUM01", &DSRSUM.DK01, sizeof(long));

 

 

  // Bucle de lectura para el cálculo de subtotales de la columna en curso

 

  for (i=1;i<=M;++i)

  {

   lresul = SRRCW_READE("DSRSUM01", &DSRSUM.DK01, sizeof(long), &DSRSUM);

 

 

   // Sumas parciales

 

   dSum1 += DSRSUM.DD.dImpr;

   dSum2 += (double) DSRSUM.DD.dEnteRROr;

  }

 

 

 // Signo de la diferencia ajustar

 

 iSigno = 1;

 if (dSum2 > dSum1) iSigno = -1;

 

 

 // Diferencia a ajustar

 

 dAjus = SRRCU_ROUND(fabs(dSum2 - dSum1));

 iAjus = (int) dAjus;

 dAjus *= (double) iSigno;

 

 

 // Ajusta la columna en curso si procede

 

 if (!iAjus) continue;

 

 

 

 // Bucle de ajustes de la columna en curso

 

 for (i=1;i<=iAjus;++i)

 {

 

  // Prepara posicionamiento

 

  if (iSigno > 0) DSRSUM.DK02.lj = j;

  else            DSRSUM.DK03.lj = j;

 

 

  // Lee el siguiente registro más próximo para ajustarlo

 

  if (iSigno > 0)

  {

   SRRCW_SETLL("DSRSUM02", &DSRSUM.DK02.lj, sizeof(long));

   lresul = SRRCW_READE("DSRSUM02", &DSRSUM.DK02, sizeof(long), &DSRSUM);

  }

  else

  {

   SRRCW_SETLL("DSRSUM03", &DSRSUM.DK03.lj, sizeof(long));

   lresul = SRRCW_READE("DSRSUM03", &DSRSUM.DK03, sizeof(long), &DSRSUM);

  }

 

 

  // Accede a su registro físico base para actualizar

 

  lresul = SRRCW_CHAIN("DSRSUM", &DSRSUM);

 

 

  // Ajusta y retira de la lista de ajustables "quemándolos" a 9's

 

  DSRSUM.DD.dEnteRRAj += (double) iSigno;

 

  if (iSigno > 0) DSRSUM.DK02.lDeci = 999999999;

  else            DSRSUM.DK03.lDeci = 999999999;

 

  lresul = SRRCW_UPDATE("DSRSUM", &DSRSUM);

 }

 

 

 // Fin de proceso satisfactorio

 

 return NO_ERRO;

}

 

 

Rutina que compendia el uso de bucles, accesos y actualizaciones de ficheros virtuales utilizando vías principales y secundarias sobre los mismos datos.

 

                                                                                                   _______

 

 

La codificación completa extractada aquí se adjunta en el apéndice

"C5 Relación de programas de muestra desarrollados en el libro"

 

 

                                                                                                   _______