Serie ficheros virtuales 

 

 

C Ficheros Virtuales

 

 

 

A.II Ejemplos

 

 

 

A.II.4 Totales y porcentajes

 

 A.II.4.1 Presentación

 A.II.4.2 Interfaz

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

 A.II.4.4 Implementación del interfaz PSRRCT y de los servicios de la DLL SRRCT


                                                   _______ 

 

 

A.II.4.1 Presentación

 

Es habitual encontrarse con la situación de disponer de unas series de importes y tener que calcular sus porcentajes frente al total, teniendo en cuenta además que los porcentajes de las cantidades negativas se deben expresar al estilo financiero. Esto es, como porcentajes de pasivo frente al activo total; activo que vendría dado por la suma de las cantidades positivas, y finalmente tener que reordenar las series en consecuencia, como sucede a continuación:

 

1                                                                2

   

nº  Importe     %      - a +     %    nº  + a -     %     nº     nº  Importe     %      - a +     %    nº   + a -     %    nº

--  ------- -------- -------- ------- -- -------- ------- --     --  ------- -------- -------- ------- -- -------- ------- --

01   44,679   1,188  -601,519 -15,999 10  958,098  25,484 03     01  676,259  12,972  -523,911 -10,049 10  990,112  18,992 03

02  885,830  23,561   -32,135  -0,854 05  885,830  23,561 02     02  978,881  18,777  -330,912  -6,347 05  978,881  18,777 02

03  958,098  25,484    44,679   1,188 01  870,143  23,144 09     03  990,112  18,992   200,842   3,852 04  941,129  18,052 07

04   53,682   1,427    53,682   1,427 04  508,011  13,512 08     04  200,842   3,852   368,358   7,065 09  676,259  12,972 01

05  -32,135  -0,854   192,846   5,129 06  246,314   6,551 07     05 -330,912  -6,347   390,758   7,495 08  666,829  12,791 06

06  192,846   5,129   246,314   6,551 07  192,846   5,129 06     06  666,829  12,791   666,829  12,791 06  390,758   7,495 08

07  246,314   6,551   508,011  13,512 08   53,682   1,427 04     07  941,129  18,052   676,259  12,972 01  368,358   7,065 09

08  508,011  13,512   870,143  23,144 09   44,679   1,188 01     08  390,758   7,495   941,129  18,052 07  200,842   3,852 04

09  870,143  23,144   885,830  23,561 02  -32,135  -0,854 05     09  368,358   7,065   978,881  18,777 02 -330,912  -6,347 05

10 -601,519 -15,999   958,098  25,484 03 -601,519 -15,999 10     10 -523,911 -10,049   990,112  18,992 03 -523,911 -10,049 10

Suma+               3.759,60570                                                      5.213,17178

 

 

En este capítulo se aborda este problema con la técnica de ficheros virtuales, que se basarán en un sistema de estructuras de datos de detalle y totales, y que se concretará en el desarrollo de unos servicios de totalización y actualización de detalle que estarán implementados en una DLL y a los que se dotará de un interfaz de presentación.

 

                                                   _______  

 

A.II.4.2 Interfaz

 

 

La imagen que muestra el interfaz es

 

 

 

La resolución del problema es muy sencilla cuando se dispone de una base de datos que permita resolver las reordenaciones que se plantean.

 

Se presentará una solución en C, sin embargo conviene comentar que una solución en RPG tendría una codificación más sencilla ya que la asignación de secuencia se haría directamente, sin necesidad de ningún artificio, al poder utilizar variables enteras de mayor longitud (De hasta 63 posiciones).

 

                                                   _______  

 

 

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

 

 

SRRCTDS.h: Estructuras del servicio de reorganización de importes por rangos

 

 

 

 

// Estructura de claves de acceso a los términos de la matriz a ajustar en rangos

 

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

{

 long li; // Índice i del nodo (Fila)

 long lj; // Índice j del nodo (Columna)

};

 

 

 

// Ds de claves de enlace origen

 

// (Opcional. Permite conservar una referencia al origen de los datos y facilitar

// informes posteriores. Se utilizaría en DK04 enlazada con la clave destino)

 

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

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

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

} DK00;

 

 

 

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

 

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

{

 long lj; // Índice j del nodo (Columna)

 long li; // Índice i del nodo (Fila)

};

 

 

 

// Ds de claves del lógico para lectura de ítems ordenados de menor a mayor

 

struct sDK02 // Lógico de - a +

{

 long lj;    // Índice j del nodo (Columna)

 long lSecu; // Secuencia ordenación directa

 long li;    // Índice i del nodo (Fila)

 char EOR;   // Marca de fin de estructura

};

 

 

 

// Ds de claves del lógico para lectura de ítems ordenados de mayor a menor

 

struct sDK03 // Lógico de + a -

{

 long lj;    // Índice j del nodo (Columna)

 long lSecu; // Secuencia ordenación inversa

 long li;    // Índice i del nodo (Fila)

 char EOR;   // Marca de fin de estructura

};

 

 

 

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

 

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

// (Se añade i,j de forma redundante para prevenir DK00 nula)

{

 struct sDK00 DK00; // Identificación fila i en origen

 long lj;           // Índice j del nodo (Columna)

 long li;           // Índice i del nodo (Fila)

 char EOR;          // Marca de fin de estructura

};

 

 

 

 

// Estructura de datos del fichero virtual de soporte de la matriz a reordenar en rango

 

struct sDD // Estructura de datos a reordenar

{

 double dImpo; // Importe (Es un dato de entrada)

 double dPorc; // Porcentaje sobre el +total (Es un dato de salida)

};

 

 

 

 

 

// Estructura del fichero virtual de ajuste de la matriz de importes a reordenar

 

static struct sDsKD

{

 struct sDK DK;     // Clave principal (ij)

 struct sDK01 DK01; // Clave alternativa (ji)

 struct sDK02 DK02; // Clave de - a +

 struct sDK03 DK03; // Clave de + a -

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

 struct sDD DD;     // Datos

} DSRORD;

 

 

 

 

// Substructuras del fichero auxiliar de totales

 

 

 

 

// Ds de claves de acceso a los términos de totales por columna a ajustar en rangos

 

struct sDKT // Estructura de claves de acceso a total j

{

 long lj; // Columna j

 char EOR; // Marca de fin de estructura

};

 

 

 

// Ds datos del fichero virtual de soporte del cálculo de totales

 

struct sDDT // Datos de totales por columna

{

 double dMin; // Mínimo

 double dMax; // Máximo

 double dTot; // Total(+)

};

 

 

 

// Ds del fichero virtual de totales por columnas de la matriz de importes a reordenar

 

static struct sKDT

{

 struct sDKT DK; // Clave columna j

 struct sDDT DD; // Totales columna j

} DSTORD;

 

 

                                                   _______  

 

 

A.II.4.4 Implementación del interfaz PSRRCT y de los servicios de la DLL SRRCT

 

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

 

 

long SRRCT_CHAIN(int i, int j, void *pDSRORD);

Recupera 1 ítem del conjunto reorganizado de importes

 

long SRRCT_CHAIND(int j, int iSecu, void *pDSRORD);

Ídem en forma secuencial directa

long SRRCT_CHAINI(int j, int iSecu, void *pDSRORD);

Ídem en forma secuencial inversa

long SRRCT_CHAINT(int j, void *pDSTORD);

Recupera un ítem de totales

short int SRRCT_ERASE(void);

Elimina la base de datos virtual soporte de proceso

long SRRCT_NEW(void);

Crea la base de datos virtual soporte de proceso

 

short int SRRCT_REORGANIZE(int M, int N);

 

Reorganización central

 

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

 

 

Grabación de ítems a reorganizar

 

                                                   _______  

 

 

Para ello, al pulsar el botón de generar muestras en PSRRCT, se arranca un proceso que efectúa las siguientes acciones:

 

 

* Se invoca al módulo de generación de muestras PrGen, que carga los datos de muestra en 2 pasos

 

 

// Paso 1. Inicia una nueva base de datos virtual para ajuste

 

 

SRRCT_NEW();

 

 

Que crea en vacío los ficheros virtuales DSRORD y DSTORD, y los lógicos

                                         DSRORD01,02,03,04

 

según el diseño presentado más arriba, y donde

 

 DSRORD archiva importes y sirve de base a los lógicos de reordenación de - a + y viceversa

 

 DSTORD archiva importes totales base del cálculo porcentual

 

 

 

 

// Paso 2. Bucle de generación de importes al azar para muestra de ajustes

 

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

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

 {

  dRand = (double) rand() / (double) RAND_MAX;

  dImpo = 1000.0 * dRand;

  SRRCT_WRITE(i, j, dImpo);

 }

 

 

 

* Punto seguido se ejecuta el proceso de totalización y reordenación:

 

 

SRRCT_REORGANIZE(M, N);

 

 

Abrimos ahora una presentación de la rutina SRRCT_REORGANIZE

 

 

 

 

En ella se leen los datos archivados para calcular totales y una vez obtenidos se releen los datos de partida actualizando porcentajes de la forma siguiente:

 

 

 // Bucle en columnas a ajustar

 

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

 {

 

  // Inz.totales parciales

 

  dTot = 0.0;

 

 

  // Sitúa para bucle de lectura del cálculo de subtotales de la columna actual

 

  DSRORD.DK01.lj = j;

 

  SRRCW_SETLL("DSRORD01", &DSRORD.DK01, sizeof(long));

 

 

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

 

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

  {

   SRRCW_READE("DSRORD01", &DSRORD.DK01, sizeof(long), &DSRORD);

 

   if (DSRORD.DD.dImpo > 0.0) dTot += DSRORD.DD.dImpo;

  }

 

 

  // Graba totales en fichero auxiliar

 

  DSTORD.DK.lj = j;

 

  DSTORD.DD.dTot = dTot;

 

  SRRCW_WRITE("DSTORD", &DSTORD);

 }

 

                                                   _______  

 

 

... (El código continua tras el siguiente inciso)

 

           

 

 

Obtenidos los totales, se releen los datos de partida para actualizarlos con la inclusión de los porcentajes y de los números de secuencia para la ordenación directa e inversa.

 

En el prácticamente imposible caso de coincidencia de valores porcentuales, la definición de las estructuras de reordenación DSK02 y DSK03 eludirían la colisión al integrar las propias claves del nodo (i,j).

 

 

La asignación de secuencia directa funciona como sigue:

 

 

 Supongamos un valor porcentual de 7.2250027064614, comprendido entre -100 y 100.

 

 Se asigna entonces el valor porcentual + 100 (para que resulte positivo) pasado a entero, esto es 107225003.

 

 La secuencia inversa sería el “complemento a 0” máximo: 1000000000 - 107225003 = 892774997

 

 

 

 Para un valor negativo de -4.8899511171440 resultaría (100 - 4.8899511171440) = 95,11004882856.

 

 Que sería pasado a entero como secuencia directa 95110049.

 

 La secuencia inversa sería el “complemento a 0”, esto es 1000000000 - 95110049 = 904889951.

 

 

 

(Alternativamente, se podría haber utilizado una clave alfanumérica de un tamaño superior que tomara mayor cantidad de cifras decimales impidiendo entonces por construcción una colisión de los mismos porcentajes destino para distintas cantidades origen, pero la ampliación del desarrollo necesario sólo procedería en caso de estimar frecuente la posibilidad de las colisiones entre valores porcentuales, lo que no es el caso dada la cantidad de cifras decimales desplegada en los ejemplos, además de contar con el mecanismo de inclusión de las propias claves del nodo (i,j) como diferenciador adicional)

 

 

                                                   _______  

 

 

 ... Continuando el código de SRRCT_REORGANIZE tras el inciso, las sentencias resultantes serían

 

 

 

 // Reposiciona para proceder al bucle de actualización por columna

 

 [DSRORD.DK01.lj = j;]

 lresul = SRRCW_SETLL("DSRORD01", &DSRORD.DK01, sizeof(long));

 

 

 // Bucle de lectura asociado para actualizar

 

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

 {

  lresul = SRRCW_READE("DSRORD01", &DSRORD.DK01, sizeof(long), &DSRORD);

 

 

  // Calcula porcentajes

 

  DSRORD.DD.dPorc = 100.0 * DSRORD.DD.dImpo / dTot;

 

 

  // Calcula secuencias

 

  DSRORD.DK02.lSecu = PrSecDirecta(DSRORD.DD.dPorc);

  DSRORD.DK03.lSecu = PrSecInversa(DSRORD.DD.dPorc);

 

 

  // Actualiza resultados

 

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

 }

 

}

                                                   _______  

 

 

Las rutinas de secuencia PrSecXXXXXX aplican las notas del inciso anterior, y presentan la codificación principal siguiente:

 

 

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

// Función: PrSecDirecta

//

// Descripción: Obtiene nº secuencia de - a +, como función del porcentaje

//

// Parámetros:

// (I) dPorc: Valor porcentual (de -100 a +100) dado

//

// Retorno: Nº de secuencia sintético basado en el porcentaje desplazado n dec.

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

long PrSecDirecta(double dPorc)

{

 long lSecu = 0;     // Nºde secuencia devuelto

 double dSecu = 0.0; // Nºde secuencia (en formato double)

 

 

 // Expresa dPorc como nº de secuencia de 9 cifras y lo devuelve

 

 dSecu  = 1000000.0;          // FactorDesplazamientoDecimal del % en 6 cifras

 dSecu *= 100.0 + dPorc;      // Garantiza + y desplaza decimales

 dSecu  = SRRCU_ROUND(dSecu); // Redondea resultado

 lSecu  = (long) dSecu;       // Devuelve nº de secuencia obtenido

 

 return lSecu;

}

                                                   _______  

 

 

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

// Función: PrSecInversa

//

// Descripción: Obtiene nº secuencia de + a -, como función del porcentaje

//

// Parámetros:

// (I) dPorc: Valor porcentual (de -100 a +100) dado

//

// Retorno: Nº de secuencia sintético basado en el porcentaje calculado como complemento a 100 de la secuencia directa

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

long PrSecInversa(double dPorc)

{

 long lSecu = 0;          // Nºde secuencia devuelto

 long lKmax = 1000000000; // Valor máximo de escala para 9 cifras

 

 

 // Calcula secuencia directa

 

 lSecu = PrSecDirecta(dPorc);

 

 

 // Convierte en inversa y termina proceso

 

 lSecu = lKmax - lSecu;

 

 return lSecu;

}

 

 

 

 

 

 

* Tras la invocación de la rutina de totalización y actualización, a PSRRCT ya sólo le queda leer los datos de detalle en la secuencia deseada

 

 

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

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

 {

  // Extrae ítem ij

 

  SRRCT_CHAIN(i, j, &DSRORD);

 

  // Pasa a pantalla del cuadro de lista

 

  PrPasNsecLISTH(i, cLISTH0);

  PrPasImpoLISTH(DSRORD.DD.dImpo, cLISTH1);

 

  m_LISTH0.AddString(cLISTH0);

  m_LISTH1.AddString(cLISTH1);

 }

 

 

* Y también los totales

 

 

SRRCT_CHAINT(1, &DSTORD);

 

m_dSuma1 = DSTORD.DD.dTot;

 

 

 

* Por último, se pasan los resultados a pantalla

 

 

UpdateData(false);

 

                                                   _______  

 

 

La codificación completa extractada aquí se adjunta en el apéndice  "C5 Relación de programas de muestra desarrollados en el libro"

 

En el capítulo siguiente se presenta una problemática similar, que también se resuelve con una algorítmica de bucles y actualizaciones sobre ficheros virtuales relacionados por vías lógicas

                                                   _______