elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Usando Git para manipular el directorio de trabajo, el índice y commits (segunda parte)


  Mostrar Mensajes
Páginas: 1 [2] 3 4 5
11  Programación / Programación C/C++ / Re: Ayuda en C que estoy reloco en: 27 Mayo 2015, 23:16 pm
Cuando tú trabajas con números de precisión flotante, tienes que tener en cuenta bastantes cosas, pero por norma general, es como dice engel lex, problemas de precisión. Ejemplo bastante ilustrador:

Código
  1. printf("%f", 0.5);

Verás que imprime 0.5 sin problemas. Pero ahora, incrementale la precisión de impresión:

Código
  1. printf("%.20f", 0.5);

Ahora hemos imprimido 0.5 con una precisión de 20 cifras decimales, y seguramente verás un valor como: 0.05000000000000000278. Es decir, en realidad `0.5` representa a un número un poquito más grande, ya que es imposible garantizar precisión exácta cuando se tratan de números flotantes (verás, de todas formas, que el error es muy muy muy pequeño).

Pues eso es fundamentalmente lo que te está pasando, que esas diferencias de precisión te están jugando una mala pasada. En el caso concreto de 1.55, si imprimes el valor que `scanf` ha leído:

Código
  1. float n;
  2. scanf("%f",&n);
  3. printf("%.20f", n);
  4.  

Te imprimirá algo como: 1.54999995231628417969 (un valor ligeramente menor a 1.55; y por eso te devuelve 0 en la última división). Incrementar la precisión ayuda, pero no resuelve el problema:

Código
  1. double n;
  2. scanf("%lf",&n);
  3. printf("%.20f", n);
  4.  

Ahora a mí me imprime algo como: 1.55000000000000004441 (un número ligeramente superior). Pero como verás, sigue sin ser exáctamente el mismo número.

Por otro lado, en ésta división (supón que `n` es `float` como en tu caso original):

Código
  1. b05=n/0.50;

Si escribes un "literal de número flotante", como `0.50`, por defecto, dicho literal `0.50` tiene tipo `double`. Por tanto, `n` se transforma en un `double` antes de hacer la división. Luego, se hace una división entre `double`s y se transforma el valor en un entero para asignarlo a `b05`. Para realizar una división `float` y no `double`, debes especificar que tu literal lo es: `0.50f`, y así no habrá conversiones de `n`.

Ésta conversiones implícitas puede incrementar (¡o disminuir, no se sabe!) la precisión, añadiendo más caos al asunto.

Si la precisión es fija, trabaja con números enteros y te quitas de en medio a los flotantes, tal y como propuso engel lex:

Código
  1. int main()
  2. {
  3.    int b200,b100,b50,b20,b10,b5,b2,b1,b05,b01,b005;
  4.    float naux;
  5.    int n;
  6.  
  7.    scanf("%f", &naux);
  8.    n = naux * 100;
  9.  
  10.    b200=n/20000;
  11.    printf("La cantidad de billetes de 200 es : %d\n",b200);
  12.    n=n-20000*b200;
  13.  
  14.    b100=n/10000;
  15.    printf("La cantidad de billetes de 100 es : %d\n",b100);
  16.    n=n-10000*b100;
  17.  
  18.    // etc...
  19.  
  20.    b1=n/100;
  21.    printf("La cantidad de billetes de 1 es : %d\n",b1);
  22.    n=n-100*b1;
  23.  
  24.    b05=n/50;
  25.    printf("La cantidad de monedas de 0.50 es : %d\n",b05);
  26.    n=n-50*b05;
  27.  
  28.    b01=n/10;
  29.    printf("La cantidad de monedas de 0.10 es : %d\n",b01);
  30.    n=n-10*b01;
  31.  
  32.    b005=n/5;
  33.    printf("La cantidad de monedas de 0.05 es : %d\n",b005);
  34.  
  35.    system("pause");
  36.  
  37.    return 0;
  38. }

O, para rematar la faena, hazlo con un bucle:

Código
  1. #include <stdio.h>
  2.  
  3. int main()
  4. {
  5.    float faux;
  6.    int n, naux;
  7.    unsigned i;
  8.  
  9.    scanf("%f", &faux);
  10.    n = faux * 100;
  11.  
  12.    int vec[] = { 20000, 10000, 5000, 2000, 1000, 500, 200, 100, 50, 10, 5 };
  13.    int prec[] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2 };
  14.  
  15.    for (i = 0; i < 11; ++i) {
  16.        naux = n / vec[i];
  17.  
  18.        printf("La cantidad de monedas de %.*f es %d\n", prec[i], vec[i] / 100.0, naux);
  19.        n = n - vec[i] * naux;
  20.    }
  21.  
  22.    return 0;
  23. }

Explicación de mi `printf`: Si yo en el `printf` pusiera algo como: "%f" sin más, se mostraría en la salida algo como:

Código
  1. La cantidad de monedas de 200.000000 es 4
  2. La cantidad de monedas de 100.000000 es 1
  3. // etc...
  4. La cantidad de monedas de 0.050000 es 4

Por que por defecto, la precisión de un `printf` es de 6 cifras decimales. Para "personalizar" la precisión, existe el modificar `.*` que permite pasarle la precisión como parámetro, antes del número que quiero imprimir.

Por ese motivo, he creado otro vector, llamado `prec`, que indica la precisión que quiero para cada elemento de la lista (ninguna para los números mayores a 0.5, de 1 cifra para 0.5 y 0.1, y de dos para 0.05), y ya se imprime bonito:

Código
  1. La cantidad de monedas de 200 es 4
  2. La cantidad de monedas de 100 es 1
  3. // etc...
  4. La cantidad de monedas de 0.05 es 4
12  Programación / Programación C/C++ / Re: Volcar cadena de fichero binario en C en: 27 Mayo 2015, 21:11 pm
¿Puedes poner un ejemplo de fichero de entrada?

Nota: Fichero de entrada (o entrada del programa) = fichero que tu programa debe leer.
13  Programación / Programación C/C++ / Re: No puedo sobrecargar el operador ostream en: 27 Mayo 2015, 21:10 pm
Eso no es cierto. Un operador o una función se hacen friend[/i] cuando:

  • El operador o función debe ser externo a la clase por la cuestión que sea.
  • El operador o función, además, necesita acceder a los datos privados de la clase.

Y no por el sencillo hecho de ser "un operador cuyo operando más a la izquierda no es un miembro de la clase". Un operador se podría hacer externo a la clase, "cuyo operando más a la izquierda ES un miembro de la clase", sencillamente para permitir conversiones implícitas.

Si no necesitas acceder a los datos privados, puedes hacer tu operador externo a la clase sin problemas, tal y como he puesto (aunque no sé qué son `local`, ni `gols_local`, ni `visitant`; asumo que subobjetos de un partido --es obvio; pero como no lo ha explicado, pues lo he dejado "tal cuál"; me he centrado en la sintáxis; si son datos privados, que sustituya su acceso mediante métodos lectores o que la haga friend como bien dices).
14  Programación / Programación C/C++ / Re: Como manejar un Buffer de 11000 caracteres ? en: 27 Mayo 2015, 18:49 pm
¿Pero necesitas almacenar esos 11000 carácteres de golpe? ¿O puedes almacenarlos en paquete, procesar cada paquetes, descartarlo, y reutilizar el búfer para el siguiente grupo?

Pero si debes guardar esos 11000 carácteres de golpe, tendrías que buscar un sitio donde "te quepa". Podrías considerar guardar dicho búfer como variable local en vez de global, o quizás que el búfer esté en memoria dinámica. Quizás es la única forma, y 11000 carácteres, que no llega ni a 11KB, no es problema para la memoria dinámica.

Tal y como dije en otro post, la memoria de un programa está divida en secciones: las variables globales inicializadas van a un sitio (.glob), las variables globales no inicializadas (como tu búfer), van a otro (y se inicializan a cero), las variables locales, a otro (stack), y las variables dinámicas, a otro (heap).

Y cada arquitectura/entorno puede tener limitaciones diferentes sobre el tamaño de cada una de éstas secciones. Pero normalmente, un programa tiene tanta memoria (en suma) como direcciones de memoria que el SO pueda manejar (si un SO puede manejar hasta 4GB de RAM, pues tu programa también). Y normalmente, las secciones .globl, stack, .rodata y demás, suelen ser secciones relativamente pequeñas, mientras que el heap (montículo) es capaz de albergar todo lo demás.

Si tu arquitectura puede manejar 2GB de RAM, pero .globl, .rodata, stack y el resto de secciones "no dinámicas" ocupana 50 MB, pues el montículo podrá albergar hasta 1GB y 950MB de memoria.

En conclusión, mira las limitaciones de memoria de tu arquitectura en la documentación pertinente para ver qué cabe donde.
15  Programación / Programación C/C++ / Re: Volcar cadena de fichero binario en C en: 27 Mayo 2015, 18:35 pm
¿Puedes poner un ejemplo de fichero de entrada?
16  Programación / Programación C/C++ / Re: Volcar cadena de fichero binario en C en: 27 Mayo 2015, 02:10 am
Yo `fread` nunca lo he utilizado, la verdad, pero asumo que de la siguiente forma:

Código
  1. // Asumo que las cadenas tienen almacenamiento para hasta 100 carácteres.
  2. // Además, las cadenas de por sí son punteros, no hace falta pasarle su dirección
  3. // de memoria. `fread` necesita un búfer (una dirección de memoria a partir de la
  4. // cual meter cosas). Si ya tienes una cadena, la propia cadena en sí te sirve como búfer.
  5. fread(&libreria[x].dato, sizeof(libreria[x].date), 1, fichero);
  6. fread(libreria[x].cadena, sizeof(char), 100, fichero);
  7. fread(libreria[x].borja, sizeof(char), 100, fichero);

Pero de todas formas, me da la impresión de que `fread` lee un fichero sin formato: es decir, pilla tantos bytes como le indiques por parámetro, pero no sabe si lo que está leyendo es un flotante, un entero o qué.

Date cuenta que la representación binaria de un número flotante, por ejemplo, no es igual a la representación binaria de una cadena (que representa un flotante). Me explico.
Si tienes en un fichero de una linea por ejemplo:

Código:
163.25

Su representación binaria será la representación binaria del carácter '1', seguida de la del carácter '6', y así sucesivamente hasta llegar al '5'. Sin embargo, la representación binaria de un número flotante en memoria será una cosa totalmente diferente (basado en mantisa/exponente).

Para ello, utiliza `fscanf`. Aparte de ser más cómodo, lee de un fichero con formato:

Código
  1. fscanf("%d%s%s", &libreria[x].dato, libreria[x].cadena, libreria[x].borja)

Así, `fscanf` saber que primero leerá un número decimal (y transformará los carácteres correspondientes del fichero en un número decimal), y luego leerá dos cadenas (`fscanf` sabe que las cadenas empiezan y terminan con espacios, saltos de líneas o tabuladores; no va a pillarte líneas enteras ni nada de eso). Ese `fscanf` leería bien un fichero como:

Código:
12 Hola amigos

El `12` iría para `.dato`, "Hola" para `.cadena`, y "amigos" para `.borja`.
17  Programación / Programación C/C++ / Re: (Ayuda) Programa crashea al analizar una cadena (char *) en: 27 Mayo 2015, 01:59 am
Cuando haces un `realloc`, si no hay espacio para añadir un elemento más en la localización actual, `realloc` te mueve el vector a una posición diferente, y dicha nueva dirección de memoria, se devuelve. Debes asignar dicho nuevo valor:

Código
  1. _value = (char*)realloc(_value, num_characters + 1);

Aunque si trabajas en C++, utiliza los `castings` correspondientes (ya que `realloc` devuelve un puntero de tipo `void*`):

Código
  1. _value = static_cast<char*>(realloc(_value, num_characters + 1));
18  Programación / Programación C/C++ / Re: Problema con Arrays en C (no C++) en: 26 Mayo 2015, 23:41 pm
Jaja. Hecho.
19  Programación / Programación C/C++ / Re: Problema con Arrays en C (no C++) en: 26 Mayo 2015, 23:19 pm
Fíjate en la línea 12.

Además, recuerda que si el usuario quiere "enero", introducirá un 1, y no un 0. Así que en la primera vuelta del lector ya se suman los dias del mes introducido (línea 12).
20  Programación / Programación C/C++ / Re: Volcar cadena de fichero binario en C en: 26 Mayo 2015, 23:19 pm
El segundo parámetro de `fread` es el número de bytes que ocupa cada "objeto" que quieres leer, y el tercero, cuántos objetos quieres leer.

Así que tu `fread` de `read` está mal:

Código
  1. fread(&read, sizeof(int), 1, fichero);
  2.  

Posiblemente, tu `fread` original (al tener 1, 100), ha intentando leer 100 chars, ha guardado el primero en `read`, y los demás, bueno..., lo que no sé cómo no te ha dado un `segmentation fault` de caballo xD. El caso es que después del primer `fread`, el fichero se ha quedado vacío y no ha quedado nada que guardar en `rlibreria`.

El `fread` de `rlibreria`, sin embargo, es correcto.

Páginas: 1 [2] 3 4 5
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines