PDF de programación - Optimice su código.... ....Pero sin Ofuscarlo!!

Imágen de pdf Optimice su código.... ....Pero sin Ofuscarlo!!

Optimice su código.... ....Pero sin Ofuscarlo!!gráfica de visualizaciones

Actualizado el 21 de Marzo del 2018 (Publicado el 16 de Octubre del 2017)
751 visualizaciones desde el 16 de Octubre del 2017
186,5 KB
9 paginas
Creado hace 13a (21/09/2010)
COMENTARIO TECNICO

Optimice su código....

....Pero sin Ofuscarlo!!
Por Ing. Eduardo A. Martínezi - Ing. Marcelo E. Romeoii

Segunda Parte.

1.1. En lo posible, no use aritmética de punto flotante.

Si bien el lenguaje permite trabajar en punto flotante a través de los tipos float, double y
long double no es recomendable usarlo, por varias razones, entre ellas:

• La unidad aritmético-lógica de la mayor parte de los procesadores que se

usan para propósitos específicos no poseen la capacidad de cálculo en
punto flotante, por lo cual deben recurrir a uso de funciones de biblioteca
muy extensas en código y en tiempo de ejecución o a coprocesadores,
con el aumento de costo y de tiempo de ejecución.

• La aritmética de punto flotante es solamente útil cuando hay que

mantener una precisión determinada en valores que difieren en varios
órdenes de magnitud entre ellas, lo cual no es tan usual.

• La comparación en punto flotante es más bien complicada: determinar

que dos números de punto flotante son iguales entre sí (o totalmente
desiguales), necesitan de la comparación contra un valor de guarda.

Es muy común encontrar programas que usan punto flotante innecesariamente, como
por ejemplo en el caso de manejo de medios de pago; mucha gente piensa que porque
un valor esté expresado en fracciones de entero o con decimales, debe obligatoriamente
usar punto flotante.

Supongamos, por ejemplo, que estamos realizando el programa que maneja una caja
registradora de supermercado: obviamente, el resultado de la venta va en pesos con sus
respectivos centavos. Ahora bien, todos los precios tienen la misma característica, con
lo cual no estamos manejando magnitudes de órdenes distintos (que es lo único que
justificaría el uso de punto flotante). Puede, por lo tanto, usarse una representación
interna que no sea necesariamente la externa y colocar todos los montos en centavos en
lugar de en pesos.

Si se considera que un long signado posee una capacidad de representación de
aproximadamente dos mil millones y representamos con ese tipo de variable la venta
total de una caja registradora en el día de trabajo en centavos, ello significaría en pesos
un valor de veinte millones, más que suficiente para la representación buscada.

Una vez que los cálculos han sido realizados internamente en representación long, no
existe inconveniente en mostrar los resultados en la representación externa, ya que es
fácil convertir a texto con la coma decimal para mostrarlo en el display de cajero o
imprimirlo en el ticket.

1.2. No use variables intermedias o temporales para cambiar la representación.

Continuando con el ejemplo de la caja registradora, supongamos que el precio unitario
de los productos de un supermercado debe ser mantenido en un archivo o arreglo dentro
de la caja registradora; es usual que un supermercado medio tenga una base de
productos posibles cercanos a los 20000, con lo cual debería elegirse la representación
más pequeña disponible para dicho precio unitario.

Consideremos el caso de un unsigned short: la capacidad de representación será de 0 a
65535 (ya que es de 16 bits); si representa el precio de cada producto en centavos,
tendríamos una capacidad de representación en pesos de 655, lo cual puede ser
aceptable.
Consideremos, además, que guardaremos el precio neto (sin IVA) por lo cual frente a
una venta, deberemos calcular el precio final con IVA.

Obviamente, supondremos que la capacidad de representación de 16 bits alcanza para el
precio final; sin embargo, deberemos hacer un cálculo intermedio sin perder precisión
que involucra la multiplicación por un factor.

Alguien propone el siguiente trozo de código, suponiendo que el número de producto
está en num_prod:

#define NUM_PRODS
#define IVA_VAL 21UL

20000

unsigned short prices[NUM_PRODS], net_price;
unsigned final_price;
unsigned long iva;
int num_prod;

net_price = prices[ num_prod ];
iva = IVA_VAL * net_price;
final_price = net_price + (unsigned short)(iva/100);

Obviamente, el resultado va a ser correcto; sin embargo, nos obligó a utilizar una
variable intermedia y a repartir el cálculo en varias sentencias del lenguaje, perdiendo,
de esa manera, la posibilidad de reutilizar los resultados que quedan en los registros de
trabajo del procesador.

Si proponemos el siguiente código, vamos a obtener el mismo resultado, con una mayor
optimización por utilizar las construcciones del mismo lenguaje y, posiblemente, una
mayor claridad.

#define NUM_PRODS
#define IVA

12UL

20000

unsigned short prices[NUM_PRODS];
unsigned final price;

final_price = prices[num_prod];
final_price += (unsigned short)( ( IVA_VAL * final_price )/ 100 );

Como conclusión, utilice la capacidad del compilador de cambiar la representación
mediante el operador de promoción forzadaiii para no necesitar variables intermedias y
poder resolver sus cálculos en una sola expresióniv.

1.3. Tipos de variables en implementaciones pequeñas.

Hoy en día existen compiladores de C para procesadores relativamente pequeños, como
es el caso de microcomputadoras de 8 bits con capacidades de programa y de memoria
RAM más bien reducidasv.

Para muchos procesadores de 8 bits, las operaciones a 16 bits no son muy directas de
implementar y necesitan varios ciclos de ejecución para lograrlas; de hecho, la ALU es
de 8 bits y las operaciones aritméticas y lógicas se realizan eficientemente en 8 bits.

Los compiladores que se realizan para esos procesadores generalmente asignan 16 bits
para el tipo int y permiten evaluaciones en 8 bits, en contraposición a lo establecido por
la norma ANSI y a lo mostrado en la Tabla 1.

Ello, más que una desventaja, se puede usar como ventaja para optimizar el código, sin
perder la generalidad que debe implicar un buen programa; recuerde siempre que, si
bien Ud. debe aprovechar las ventajas de la actual implementación, debe ser
suficientemente transparente a las mismas de manera de poder migrar rápidamente y sin
mayores sufrimientos a otras implementaciones.

Es por ello, que los autores, en distintos proyectos, han mantenido un archivo de
inclusión denominado cutils.h que permite tener definiciones generales útiles para todo
proyecto, así como definiciones de tipo que permiten aprovechar las características de
las implementaciones para 8 bits sin perder la generalidad necesaria.

A continuación, se muestra parte de dicho archivo:

#ifndef __CUTILS_H__
#define __CUTILS_H__

#define forever

for(;;)

typedef unsigned char
typedef signed
typedef unsigned int uint;
typedef unsigned long

uchar;
char schar;

ulong;

MUint

#ifdef __TINY_PROC__
typedef uchar
typedef schar
#else
typedef uint
typedef int
#endif

Mint;

MUint;
Mint;

#endif

La definición de forever es para mostrar que en este archivo se colocan definiciones que
son útiles para cualquier programa en C (las otras definiciones se han extraído para
mantener corto y claro el texto).

Como colocar ciertas definiciones de tipo son más bien tediosas por la cantidad de texto
que involucran, existen cuatro typedef para la redefinición de tipos usuales.

Lo más importante de este archivo, para las finalidades de este artículo, son aquellas que
se seleccionan por la existencia o no de la definición de la variable del preprocesador
__TINY_PROC__.En efecto, si no está definida dicha variable, los tipos MUint y Mint
se hacen respectivamente iguales a uint y a int; si está definida, se hacen
respectivamente igual a uchar y schar.

Para ver la utilidad de estas definiciones, vamos a considerar el siguiente sencillo
módulo de demostración:

/*
* Use of square function
*/

#include “cutils.h”

static Mint
square( Mint val )
{

return val * val;

}

int
main( void )
{

Mint i, a;

for( i = 0 ; i < 4 ; ++i )
a = square( i );

return 0;

}

Consideremos dos casos:

1.3.1. __TINY_PROC__ no está definida

Si la variable __TINY_PROC__ no está definida, lo que va a ver el
compilador como código será:

static int
square( int val )
{

return val * val;

}

int
main( void )
{

int i, a;

for( i = 0 ; i < 4 ; ++i )
a = square( i );

return 0;

}

Este código, entonces, es el normal que está de acuerdo a las consignas de la norma
ANSI C sobre evaluación de tipos de variables.

1.3.2. __TINY_PROC__ está definida

En este caso, el código que verá el compilador será:

static signed char
square( signed char val )
{

return val * val;

}

int
main( void )
{

signed char i, a;

for( i = 0 ; i < 4 ; ++i )
a = square( i );

return 0;

}

El cual aprovecha la característica de los procesadores de 8 bits de ser más eficiente
desde el punto de vista deevaluación aritmética en 8 bits que en 16 bits.

Se puede demostrar que, en general, ésta es una de las mejores optimizaciones en
código para procesadores de 8 bits; sin embargo, deben tenerse en cuenta estas
restricciones:

• Los tipos Mint y MUint sólo deben utilizarse para la definición de variables

automáticas de trabajo, de argumentos de funciones y de retornos de funciones
siempre y cuando los valores a alojar en ellas estén de acuerdo con lo que
soportan los tipos uchar y schar;

• De ninguna manera, deben ser utilizados para la declaración de

almacenamiento, especialmente de arreglos o de miembros de estructuras; en
esos casos, sólo deben utilizarse los tipos de C directamente

La ventaja fundamental de esta forma de proceder es que se es absolutamente
transparente para la compilación en distintas plataformas y que sólo debe definirse o no
la variable del preprocesador __TINY_PROC__, lo cual puede hacerse perfectamente
en el comando de compilación mismo.

1.4. Almacenamiento estático contra argumentos de funciones.

Un de las ventajas más potentes de un lenguaje de alto nivel como C es la posibilidad de
escribir funciones que no estén especializadas sobre variables fijas, sino que operen
sobre argumentos que se le pasan en el momento de invocación.

Para ello consideremos un sencillo manejador de la estructura de dato pila
implementado en un módulo de compilación separado denominado stack.c que
  • Links de descarga
http://lwp-l.com/pdf7201

Comentarios de: Optimice su código.... ....Pero sin Ofuscarlo!! (0)


No hay comentarios
 

Comentar...

Nombre
Correo (no se visualiza en la web)
Valoración
Comentarios...
CerrarCerrar
CerrarCerrar
Cerrar

Tienes que ser un usuario registrado para poder insertar imágenes, archivos y/o videos.

Puedes registrarte o validarte desde aquí.

Codigo
Negrita
Subrayado
Tachado
Cursiva
Insertar enlace
Imagen externa
Emoticon
Tabular
Centrar
Titulo
Linea
Disminuir
Aumentar
Vista preliminar
sonreir
dientes
lengua
guiño
enfadado
confundido
llorar
avergonzado
sorprendido
triste
sol
estrella
jarra
camara
taza de cafe
email
beso
bombilla
amor
mal
bien
Es necesario revisar y aceptar las políticas de privacidad