Mostrando entradas con la etiqueta c. Mostrar todas las entradas
Mostrando entradas con la etiqueta c. Mostrar todas las entradas

lunes, octubre 17, 2011

El descuento de efectos

Cuando tienes un cheque cuya fecha no ha vencido todavía no lo puedes cobrar. Si tienes necesidad de liquidez puedes ir a varios bancos e intentar negociar el cobro anticipado (descuento).

El banco se quedará con una comisión a cambio de adelantar el pago.

Cuando hablamos de días de anticipo podemos emplear esta fórmula:

comision = (capital x dias x interes) / 36000

Este programita C te ayudará cuando tengas prisa y no te acuerdes de la fórmula:

#include <stdio.h>
int main()
{
float capital, comision, tasaInteres;
int dias, rta;
printf("\n\n\n");
printf("Descuento de efectos (o anticipos de letras o pagares) \n");
printf("-------------------------------------------------------\n");
printf("1.-Necesitas saber la tasa de interes que te cobran\n");
printf("2.-Quieres saber la comision que te va a cobrar el banco\n");
printf("Elige: ");
scanf("%d",&rta);
getchar();
printf("\n\nIntroduce estos datos:\n");
printf("Capital: ");
scanf("%f",&capital);
printf("\n\nDias de prestamo: ");
scanf("%d",&dias);
if (rta==1){
printf("\n\nY ahora pon aqui la comision por el adelanto: ");
scanf("%f",&comision);
tasaInteres = comision*36000/capital/dias;
printf("\n\nLa tasa de interes es de %f",tasaInteres);
}
if (rta==2){
printf("\n\nY ahora pon aqui la tasa de interes: ");
scanf("%f",&tasaInteres);
comision = capital*dias*tasaInteres/36000;
printf("\n\nLa comision que te van a cobrar es de %f",comision);
}
printf("\n\nPulsa cualquier letra para salir...");
getchar();
getchar();
}

domingo, octubre 16, 2011

Proyectos ANSI C en Visual Studio


Cuando vas a crear un proyecto en C estándar (ANSI C) en lugar de en C++ con el Visual Studio, no hay una opción clara y se tiene que hacer así:

1.-Entrar en Visual Studio.
2.-Menú Archivo, Nuevo, Proyecto. Seleccionamos la aplicación de consola Win32.

3.-En configuración de la aplicación seleccionamos "PROYECTO VACÍO".

4.-Buscamos en pantalla el "EXPLORADOR DE SOLUCIONES". Seleccionamos nuestro proyecto con el botón derecho. Hacemos clic en "AGREGAR", y luego "NUEVO ELEMENTO":


5.-Seleccionamos agregar un "ARCHIVO C++". No hay opción de seleccionar "ARCHIVO C". Por lo tanto el fichero que se añada tendrá extensión .cpp en lugar de .c

Saludos.

miércoles, diciembre 29, 2010

Compiladores C y C++ en Ubuntu

Acaba de terminar el partido de fútbol entre las selecciones de Euskadi y Venezuela. Ha estado muy bien con un ambiente excepcional.

Ahora que tenemos un Linux recién instalado necesitamos un buen compilador.
El compilador C viene de serie en los Linux.

Los lenguajes C y C++ tienen una gran ventaja y es que están presente en la mayoría de sistemas operativos (puede que en todos los de cierta entidad). Por eso se pueden considerar multiplataforma, aunque no lo sean en el mismo sentido que Java.

Compilar el "Hola mundo" en C:

Abrimos una sesión de terminal.
Escribimos el típico "Hola mundo" en C:

Llamo al fichero prueba.c

Lo compilamos:

gcc prueba.c

Y ejecutamos el resultado que es el fichero a.out:

./a.out

Hola mundo


Ahora bien, gcc es compilador de C.

Compilar el Hola Mundo en C++:

Llamo al fichero prueba.cpp:


pero... ya hemos dicho que no hay compilador de C++

Hay que instalarlo:

sudo apt-get install 'g++'

y ahora sí:

g++ prueba.cpp

./a.out

Hola mundo

Saludos.

domingo, julio 19, 2009

Casi mejor no tocar la afinidad

Hola a tod@s,
Por fin de vacaciones, pero antes de marchar de viaje me gustaría saber si lo que ocurrió con el programa C le ha pasado a más gente, y por qué.

Recordar que teníamos un programita que ejecutamos marcando la afinidad a un procesador concreto y tardó 11 segundos más que sin toquetear la afinidad.

Primero una pequeña aclaración que analizaremos otro día:
El ordenador que utilicé en esas pruebas es un ADM Phenon x3, el cual tiene un único procesador con 3 cores (o nucleos en castellano). Windows nos dirá que hay tres procesadores y que podemos determinar la afinidad para forzar la ejecución en los procesadores que queramos, pero sólo hay un procesador y los núcleos comparten ancho de banda en el acceso a la caché L3 (memoria compartida por todos los cores). La caché L2 es la memoria que tiene cada core.

Bueno, ahora vamos a leer lo que otro (Iñaki Ayucar) ha analizado:

Artículo original en inglés: http://www.codeproject.com/Articles/35679/Parallel-computing-and-processor-affinity-Never-underestimate-the-Windows-Vista-Scheduler.aspx?display=PrintAll

Y en castellano: http://graphicdna.blogspot.com/2009/01/programacion-paralela-y-processor.html

¿Cual es el resumen?

1.-Al menos habría que abril un hilo por core físico en la máquina. Ya, pero el programa no es mio y el autor metió programación paralelizada en el programa original Fortran, pero no en el C. Esto será una mejora para el después de vacaciones.

2.-Este punto lo voy a poner tal cual está, porque lo explica de maravilla. El autor nos dice: "En un mundo ideal, una tarea simple, que no va a ser paralelizada más y que vive solita (no con las docenas de vecinos que un proceso tiene en un SO moderno), se gestiona mejor con una sola CPU, porque esto incrementa los aciertos de cache y elimina el consumo de la infraestructura de cambio entre hilos. Pero en la vida real, los procesos son interrumpidos por las operaciones del sistema, IO, otros procesos y muchas otras cosas. Una maquina multi-núcleo es perfecta para manejar todas esas interrupciones, porque puede repartirlas por los núcleos existentes, pero si comenzamos a fijar nuestras aplicaciones a CPUs específicas, la capacidad del sistema para evitar bloqueos y esperas se reduce considerablemente".

Uff, este punto número 2 lo podemos separar en otros cuantos:

2.1.-Cuidado, porque puede ocurrir que la ejecución en tu viejo portátil con una CPU pueda ir mejor, ya que hay más aciertos de cache y hay menor consumo por cambio de hilos.

2.2.-El hecho de que hay un montonazo de procesos extra en ejecución con sus respectivas interrupciones, etc. etc. da pie a que en tu nuevo pc multinucleo la cosa funcione mejor.

2.3.-En el caso de que estemos en nuestro pc nuevo multinucleo, fijar las CPU-s puede perjudicar ya que el sistema tiene menos opciones para evitar los bloqueos, esperas, etc.

En el artículo pasa a describir el tema de cómo fijar la afinidad y luego viene lo interesante:

Las pruebas:

Las pruebas se componen por 5 partes:

Parte I: Programa NO multihilo (como el nuestro).
Si se establece la afinidad el programa tarda 28 segundos más que si no se hace nada.
Mejor dejar hacer a Windows.

Parte II: Dos hilos de ejecución (principal + secundario con algún cálculo).
El programa tarda 3 segundos menos si no se establece la afinidad.
Mejor dejar hacer a Windows.

Parte III: Tres hilos de ejecución (principal + dos hilos de cálculo).
El programa tarda 2 segundos menos si no se establece la afinidad.
Mejor dejar hacer a Windows.

Parte IV: Cinco hilos de ejecución (principal + cuatro hilos de cálculo).
Empate técnico (bueno, por décimas gana la afinidad).
Windows ha perdido por la mínima.

Parte V: Nueve hilos de ejecución (principal + ocho hilos de cálculo).
El programa tarda 3 segundos menos si no se establece la afinidad.
Mejor dejar hacer a Windows.

Los resultados cuadran totalmente con lo que nos ocurría en el programita.

Parece que cuando la programación es multihilo es mejor no tocar la afinidad, aunque la diferencia es pequeña. Lo que está claro es que si el programa no es multihilo hay grandes diferencias en tiempo de ejecución siendo más rápido sin tocar la afinidad.

Saludos.

lunes, julio 13, 2009

Siguiendo los consejos recibidos el otro día la semana pasada hice la prueba de ejecución "con afinidad".

No fijé la afinidad por programación. Simplemente lancé la ejecución, y a toda leche modifiqué la afinidad con el Administrador de tareas de Windows.

Estoy con mi viejo portátil con un solo procesador por lo que no os puedo enseñar la opción, pero la explico...



Ahí arriba está el Administrador de tareas. He pinchado en una tarea y tengo opción de subir o bajar la prioridad de un proceso.

Si tuviera más de un procesador, debajo de la opción de prioridad tendríamos algo así como "afinidad". Al pinchar aparecen un check box donde podemos elegir uno o varios procesadores. Yo elegí el procesador 0.

Así fue la ejecución:

El PC estaba ligerito de trabajo:


Lanzo el proceso, pongo en marcha el cronometro y establezco la afinidad:

En la imagen de arriba ya se ve que un procesador se pone al 100% mientras que los otros dos prácticamente vuelven a la situación inicial.

Al final termina el proceso y todo vuelve a su ser:


Ahora lo importante, ¿qué ha pasado con el tiempo de ejecución?

Pues ha tardado 18 minutos 42 segundos. Once segundos más que sin tocar la afinidad.

Creo que vamos a tener que enterarnos de la forma de funcionamiento de estos procesadores AMD64 para entender algo.

Saludos.

lunes, julio 06, 2009

Could faster chips translate into slower computers?

Ya que el otro día mejoramos la ejecución en el super PC-1 (18 minutos 31 segundos), se me ha ocurrido compilar y ejecutar el programa Visual C++ en mi viejo portátil.

Con el Dev C++ sin optimizar tardaba 21 minutos 9 segundos y tenía curiosidad por saber lo que iba a mejorar.

Han sido ni más ni menos 14 minutos 20 segundos, lo que significa que ¿es la máquina más rápida? ¡Imposible!

Algo raro está ocurriendo... el resultado no es lógico, o tal vez sí...

Así es la utilización de la CPU al comenzar la ejecución. 100% de uso del único procesador hasta el final.



Y así la relajación final:


El AMD64 es multinucleo y se comporta diferente. El XP lo ve como si fueran 3 procesadores. El caso es que el uso de la CPU se mantiene bastante constante en un 34% de uso.


Cuando termina:


Esto hay que estudiarlo un poco pero el punto de partida puede ser este:

Could faster chips translate into slower computers?

Esta es la pregunta que se hicieron en este artículo de la revista Fortune e indica una posibilidad que puede estar ocurriendo, o tal vez no.

Saludos.

jueves, julio 02, 2009

Prueba con Visual C++

Seguimos con el programa de generación del primo más grande (del año 1994).

Hicimos una prueba de compilación con Dev C++ en un PC decente. El resultado fue un poco decepcionante porque los 27 minutos que tardaba eran 6 minutos más que en un viejo portátil XP.

Es verdad que no me preocupé demasiado por ajustar los parámetros del compilador. Pero he preferido pasar directamente al compilador comercial por excelencia de Windows XP: Visual C++.

1.-Instalo Visual Studio 2005 (en los próximos días probaremos el Visual Studio 2008).

2.-Iniciamos un nuevo proyecto Visual Studio. Seleccionamos el lenguaje Visual C++ y "Aplicación de consola Win32"



3.-Así tendremos el proyecto vacío:


4.-Añado el programa C original de Slowinski y lo adapto ligeramente para el Visual C++. Concretamente hay que:
  • Modificar la sintaxis de main().
  • Comentar las líneas para el control de tiempos.
  • Comentar la cabecera que Visual C++ ha añadido por defecto: stdafx.h
  • Añadir la cabecera stdlib.h para poder usar la función atoi.

Al final de este post añado el código fuente entero para el que lo quiera probar.

5.-Lanzamos la compilación-ejecución y a esperar. En total ha tardado 23 minutos 45 segundos. Mejor que el Dev C++ pero un resultado bastante pobre. Ahora toca hacer unos pequeños ajustes.

6.-Priorizamos el rendimiento frente al tamaño del ejecutable:

Para ello vamos al Menú Proyecto, propiedades del proyecto, propiedades de configuración, C/C++, Entramos en la sección "Optimización" y seleccionamos "Maximizar velocidad" que se corresponde con la opción /O2.



Ahora intentamos la compilación y...SORPRESA. Se produce un error que dice lo siguiente: "las opciones de líneas de comandos '/O2' y '/RTC1' son incompatibles".


Bueno, pues hay que volver a Proyecto, propiedades del proyecto, propiedades de configuración, C/C++, General. Vamos a "formato de la información de depuración" y seleccionamos "Deshabilitado".

Además de esto, también hay que ir a C/C++, Generación de Código, "Comprobaciones básicas en tiempo de ejecución" y marcarlo como PREDETERMINADO.



Pues aunque volvamos a intentar compilar nos sale un nuevo error: '/Gm' requiere '/Zi' o '/ZI'.


Jeje, ya estaremos un poco aburridos tanto toquetear, pero esta es la última vez (de momento). Volvemos a Proyecto, propiedades del proyecto, propiedades de configuración, C/C++, Generación de código. Vamos a "habilitar regeneración mínima" y ponemos que NO.


7.-Ahora sí, ya podemos compilar y ejecutar tranquilamente. Y el rendimiento mejora bastante. El programa tarda ahora 18 minutos 31 segundos. Nuevo record, aunque todavía insuficiente.

Saludos.

Ahora el código fuente... (cuidado, algunos símbolos se han podido modificar. Cosas de blogger):


// Programa visualizador. 2009-07-02.

//#include "stdafx.h"

#include
#include
#include
#include

//Para que funcione la función atoi es necesario incluir stdlib.h.
#include

// Pequeña modificación en main:
//main(argc, argv)
//int argc;
//char *argv[];

int main(int argc, char* argv[])
{
#define EXP 859433 /* will calculate 2^859433 - 1, the 33rd Mersenne prime */
//Quitamos el cálculo de tiempos:
//double t, ftp0, ftp1;
double c0 = 0, c1 = 0, c2 = 0;
int n;
int *a, *b, *c;
int ddigit = 4; /* number decimal digits per part */
int vdig = (int)pow((double)10, (double)ddigit); /* decimal value of part */
int i, j, k, maxpart, mx;
unsigned int size;
char format[64];

n = EXP;
if (argc == 2) /* command-line param for new n? */
n = (atoi(argv[1]) > 0) ? atoi(argv[1]) : EXP;
printf("calculating 2^%d - 1\n", n);

size = (n+1)*sizeof(int);
printf ("allocating %d bytes for working arrays\n", 3*size);

if ((a = (int *)malloc(size)) == NULL) {
fprintf(stderr, "cannot allocate %d bytes for a\n", size);
exit(1);
}
if ((b = (int *)malloc(size)) == NULL) {
fprintf(stderr, "cannot allocate %d bytes for b\n", size);
exit(1);
}
if ((c = (int *)malloc(size)) == NULL) {
fprintf(stderr, "cannot allocate %d bytes for c\n", size);
exit(1);
}

for (i = 1; i <= n; i++) { a[i] = 0; /* set results array to null */ b[i] = 2; /* load up multiplicand array with n 2s */ c[i] = 0; /* set carry array to null */ } a[1] = 1; /* set initial intermediate result to 1 */ mx = 1; //#ifdef FTIME // ftime(&tp0); //#else // gettimeofday (&tp0, (struct timezone *)NULL); //#endif //#pragma _CRI parallel shared(n, a, b, c, mx, vdig) private(i, j) for (j = 1; j <= n; j++) { //#pragma _CRI taskloop vector for (i = 1; i <= mx; i++) { a[i] *= b[j]; } //#pragma _CRI taskloop vector for (i = 2; i <= mx+1; i++) c[i] = a[i-1]/vdig; //#pragma _CRI guard if (c[mx+1] > 0)
mx++;
//#pragma _CRI endguard

//#pragma _CRI taskloop vector
for (i = 1; i <= mx; i++) { a[i] = (a[i] % vdig) + c[i]; } } //#pragma _CRI endparallel /* propogate carry through one last time */ j = 0; for (i = 1; i <= n; i++) { k = a[i] + j; a[i] = k % vdig; j = k/vdig; } //#ifdef FTIME //ftime(&tp1); //ftp0 = (double)tp0.time+(double)tp0.millitm/(double)1000000; //ftp1 = (double)tp1.time+(double)tp1.millitm/(double)1000000; //#else //gettimeofday (&tp1, (struct timezone *)NULL); //ftp0 = (double)tp0.tv_sec+(double)tp0.tv_usec/(double)1000000; //ftp1 = (double)tp1.tv_sec+(double)tp1.tv_usec/(double)1000000; //#endif //t = (ftp1-ftp0 == 0) ? 0.000001 : ftp1-ftp0; //printf("wall time for main loop: %.5lf seconds\n", t); maxpart = 0; for (i = 0; i <= n; i++) if (a[i] != 0) maxpart = i; printf ("max parts used: %d (each part is %d decimal digits)\n", maxpart, ddigit); /* subtract one from answer and see if we match Slow's number */ a[1]--; if (a[1] < i =" 2;" j =" 0;" i =" maxpart;">= 1; i--) {
printf (format, a[i]);
j++;
if (j % 15 == 0)
printf ("\n");
}
printf ("\n");

return 0;
}

lunes, junio 29, 2009

Pequeña decepción

Os comento la prueba que quería hacer esta tarde.

Tenía dos equipos idénticos. Dos PC-s que le dan mil vueltas a este portátil en el que estoy escribiendo. Voy a poner unos datos para verlo:

1.-Portátil donde realicé la prueba del visualizador.exe:

2.-PC1 y PC2:

  • AMD Phenom X3 64.
  • HP Compaq DC5850.
  • Triple-Core Processor
  • 2,29 GHz,
  • 3,23 Gb Ram.

El PC1 tenía XP instalado y ahí he instalado el Dev C++ 5.0 beta 9.2 con el compilador Mingw/GCC 3.4.2

En el PC2 tenía Ubuntu 9.04 que trae instalado un compilador FORTRAN.

La idea era esa... Compilar el programa C en PC1 y el equivalente FORTRAN en PC2, comparar y quedarnos con el más rápido. Aquí están los dos enlaces a los programas

El problema ha sido que la ejecución en el programa C recién compilado en el super PC1 ha tardado 27 minutos 05 segundos. Cuando el mismo programa en el viejo portátil tardaba 21 minutos 09 segundos.

¿¿¿¿¿??????
¿Los viejos cacharros son mejores? No.
¿Windows XP no es capaz de sacar provecho de la máquina? Tampoco.

No, no es nada de eso. Tiene más que ver con el compilador, más concretamente si es capaz de utilizar los recursos de la máquina, o los está infrautilizando.

El Dev C++ 5.0, tal y como lo descargas lleva debajo el compilador MinGw 3.4.2. Realmente la última versión disponible es la 5.1.4 como se puede ver en http://sourceforge.net/project/showfiles.php?group_id=2435

Ahora lo que toca es buscar el mejor compilador C posible para el AMD64 con Windows.

Saludos.

jueves, mayo 28, 2009

Programas C curiosos

Hola,

Se acerca el verano y quería ver como iba el tema de los números primos más grandes descubiertos. Es una pena pero me alejé del tema y ahora habrá que empezar otra vez de 0.

El caso es que he estado navegando por las web-s de primos gigantes que analizamos hace ya 9 meses y... he encontrado esto:



¡Que interesante!
Un pequeño y complejo programa C que ha ganado en un "especial" concurso de programación C.

Es la IOCCC (The International Obfuscated C Code Constest): http://www.ioccc.org/

¿Un concurso de código C "ofuscado"?

Aquí están los ganadores. Por lo títulos de los premios prometen: mejor juego, más humor, mejor salida, peor estilo, peor utilización del preprocesador, mejor ofuscación, mejor utilidad, mejor uso de luces y esferas, mejor programa corto, etc. etc.

Habrá que compilar y mostrar las salidas, creo que no habrá problemas de autor si mencionamos la procedencia.

Saludos.

sábado, febrero 07, 2009

Minix. De la 00000 hasta la 000068

Hoy vamos a empezar a analizar el código fuente de MINIX.
Para ello tendremos que recordar algunas nociones de C. El código se encuentra en /usr/src/.

Tanembaun ha numerado cada línea de código desde la 00000 hasta la 28864.
De la 00000 a la 00068 corresponden al fichero include/ansi.h

Recordemos que los ficheros .h son ficheros de cabecera. Una aplicación de cierto tamaño se diseña de forma modular. Cuando se hace un módulo en C (fichero .c), se suele preparar también la interfaz de ese módulo (fichero .h).

La interfaz sirve para hacer público al resto de módulos algunas funciones, variables, tipos de datos y constantes. Los módulos que vayan a utilizar ese módulo lo incluirán por medio de un #include="cabecera.h".

El directorio /usr/src/contiene ficheros de cabecera del estándar POSIX.
Incluye 3 subdirectorios:
-sys: ficheros de cabecera POSIX.
-minix: ficheros de cabecera utilizados por MINIX.
-ibm: ficheros de cabecera específicos de IBM PC.

Ansi.h

Hay una serie de ficheros de cabecera que son de propósito general y se procesan en todas las compilaciones de todos los módulos de MINIX.

Ansi.h es uno de ellos. Es el segundo que se procesa siempre. Sólo se procesa antes /include/minix/config.h

Propósito de Ansi.h:
Comprobar si el compilador sigue los requerimientos del C estándar (ANSI C).
El estándar define varias macros que pueden ser testeadas en tiempo de compilación.

Nota: Para entender Ansi.h hay que conocer las directivas del preprocesador.

Un compilador que siga el estándar establecerá __STDC__ = 1.

Lo primero que se hace en Ansi.h es comprobar el valor __STDC__. Si es 1, entonces _ANSI se define como 31459, que significa que sigue el estándar.

Luego hace una comprobación más (considera que si está definido __GNUC__ también es ANSI). Por lo tanto _ANSI se establece a 31459.

Ahora viene lo más importante. En C antes de utilizar una función hay que declararla por medio de un prototipo. En el prototipo se adelantan los tipos de datos que recibe y el que devuelve. En ANSI C es así:

int calcular(int numero1, int numero2)

Pero en otros C-s puede ser así:

int calcular()

Por medio de la macro _PROTOTYPE el preprocesador transformará nuestros prototipos a la forma adecuada.

Por último, en Ansi.h se define _POSIX_SOURCE como valor 1 en función de otras macros.

Saludos.