Descomponer un float

Started by Danielo515, March 23, 2009, 01:42:52 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Danielo515

Chicos, ya se que los foat en c, tienen muchos muchos errores de precisión, que son caca mala y que no hay que usarlos. Pero quiero usar decimales, de un número indeterminado de cifras decimales, y me gustaría poder descomponer en dos enteros la parte entera, y la parte decimal. Ejemplo
12.18

entero a=12;
entero b=18;

He usado varios métodos, pero todos me dan problemas con la precisión. Si a alguno se le ocurre como solucionarlo, yo, le doy mi mano en matrimonio,
Pequeño ejemplo que funciona a veces;
[code language="bennu"]#include<stdio.h>
#include<conio2.h>

int main(){
    char a;
    int i,j,num,inc;
    double dec;
while(a!='c'){
    num=0;
    inc=10;
   
    printf("\n\t Introduzca un número decimal, pazguato:");
    scanf("%lf",&dec);

    if(dec>1.0){
             i=(int)dec;
             dec=(float)dec-i;
             }
             
    printf("\n Numero sin parte entera: %lf\n",dec);
   
    do{
                     i=dec*inc;
                     j=dec*inc*10;
                     inc*=10;
                     printf("\n i:%d j:%d",i,j);
                     
                     
    }while(j-(i*10)!=0);
    num=i;

printf("\n Numero convertido a entero: %d",num);
a=getch();
}//while
}//main
[/code]
Un saludo.

DCelso

Pues si, deberías de trabajar con los dos int desde el principio haciendo algo como un scanf("%ld.%ld")
De todos modos el codigo siguiente me va bien para todos los casos que he probado.

#include "stdio.h"
#include "math.h"
#include "string.h"
int main()
{
double real;
int parteEntera;
int parteDecimal;
char buffer[255];
printf("Número real:");
scanf("%lf",&real);
fflush(stdin);
parteEntera=real;
printf("Parte Entera:%d\n",parteEntera);
real-=parteEntera;
printf("Restante:%lf (double)\n",real);
    sprintf(buffer,"%lf",real);
printf("Restante:%s (string)\n",buffer);
    int i=strlen(buffer)-1;
while(buffer[i]=='0'){
    buffer[i]=0;
    i--;
    }
printf("Restante:%s (string reducido)\n",buffer);
real*=pow(10,strlen(buffer)-2);
printf("Parte Decimal:%lf (double)\n",real);
    parteDecimal=round(real);
printf("Parte Decimal:%d (int)\n",parteDecimal);

return 0;
}

Monstruos Diabólicos

"A PAck of classic GAMEs For BennuGD" en desarrollo
http://code.google.com/p/apagame4be/

SplinterGU

si quieren evitar usar flotantes por la precision, entonces no hay que usar flotantes en ninguna etapa.
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

Danielo515

Tengo que usar un float, porque en el ejemplo lo capturo por teclado, pero en el programa lo recibo como resultado de una división de enteros, de la cual me tengo que quedar con la parte decimal y convertira a entera, y no se, a priori, cuantos decimales me va a dar la división.

Muchas gracias.

SplinterGU

trabaja con numeros multiplicados por 1000 o 100, segun la cantidad de decimales que necesites... y trabaja con enteros...
por ejemplo

1.23 = 123
245.3 = 24530

trabaja directamente con numeros multiplicados, no uses decimales, y ahi ya sabes que los ultimos 2 (o N) digitos del numero son los decimales...
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

HaCkZJuaNN

#5
Splinter, eso da algunos problemas al multiplicar y dividir que no has mencionado. 1.23 = 123/100(es decir, 123 corriendo 2 lugares la coma); y 1.23+2.02 = 123/100+202/100 = (123+202)/100(corriendo 2 lugares la coma otra vez). Sin embargo, si multiplicas, 1.23*2.02 = 123/100*202/100 = (123*202)/10000; es decir, que si multiplicas 1.23 por 2.02 utilizando tu sistema(123*202), el resultado tendrás que correrle la coma 4 posiciones y no 2 para que te de el auténtico resultado de 1.23*2.02.

Sin embargo, al dividirlo, te da lo mismo 123/202 que 1.23/2.02; no hay que correr la coma porque ambos resultados te dan lo mismo, y en el caso de que lo hagas con enteros da 0; así que creo que no es muy buena solución la que propones.

splinter_work

#6
Caramba!

Yo no dije que multiplique ni divida nada...

dije que tomando una base, segun la cantidad de decimales que necesite, trabaje siempre con numeros "ya multiplicados" (sin hacer ninguna multiplicacion ni division para obtenerlos)...

si necesita 2 decimales, el sabra que los 2 ultimos digitos del numero son decimales
si necesita 3 decimales, el sabra que los 3 ultimos digitos del numero son decimales

el sistema funciona perfectamente, tanto funciona que es lo que se usa desde hace muchos años en todo sistema de transacciones financieras a nivel mundial (ATM, compras con tarjetas de credito, debito, y un largo etc...) ... (para mas detalle ISO8583, campo 4 -ammount-)

EDIT: Yo hablaba de la representacion... es cierto, no lo mencione, si multiplicas 2 numeros tendras que correr 4 la coma y descartar los 2 ultimos digitos.

splinter_work

para el caso de las divisiones, hay que multiplicar uno de los miembros por 100 o por la base que se decida usa...

por ejemplo,

si tenemos 123/456

debemos hacer

123*100/456 = 26 = 026 = 0.26

ya que estamos vamos a poner que hacer para la multiplicacion:

( 123 * 456 ) / 100 = 560 = 5.60

estas formulas dan los valores adecuados siguiendo la misma norma.


resumen:

suma: a + b
resta: a - b
multiplicacion: (a*b)/100
division: (a*100)/b

siempre usar enteros... obviamente nos encontraremos con el limite de los enteros, pero no tendremos problemas de redondeo.

Danielo515

Eso está muy bien cuando sabes de antemano cuantos decimales vas a usar.
Pero, si no lo sabes?
Es decir, tenemos a/b, que va a dar decimales, pero da la casualidad de que a es un numero dado por teclado y b un numero aleatorio. Entonces ¿como predecir cuantos decimales va a dar?

a=134
b=99
da 1,3673469387755102040816326530612
¿como adivino cuantos decimales va a dar?
¿pongo un límite de decimales y punto?
digo, máximo 10 decimales. Vale ¿y como adivino si son menos?
a=133
b=50
da 2.66, vaya, ahora son solo 2 decimales.

¿que criterio puedo poner para predecir el numero de decimales aún con un tope?

Gracias, colegas.

SplinterGU

no importa cuantos decimales vengan, lo que importa son los que vos vas a usar en tu sistema...
claro, vos definis y pones su limite.

tantos decimales, olvidate.

por que no explicas bien que queres hacer, para que lo necesitas?
Download Lastest BennuGD Release: http://www.bennugd.org/node/2


HaCkZJuaNN

Quote from: Danielo515 on March 27, 2009, 10:46:44 PM
Eso está muy bien cuando sabes de antemano cuantos decimales vas a usar.
Pero, si no lo sabes?
Es decir, tenemos a/b, que va a dar decimales, pero da la casualidad de que a es un numero dado por teclado y b un numero aleatorio. Entonces ¿como predecir cuantos decimales va a dar?

a=134
b=99
da 1,3673469387755102040816326530612
¿como adivino cuantos decimales va a dar?
¿pongo un límite de decimales y punto?
digo, máximo 10 decimales. Vale ¿y como adivino si son menos?
a=133
b=50
da 2.66, vaya, ahora son solo 2 decimales.

¿que criterio puedo poner para predecir el numero de decimales aún con un tope?

Gracias, colegas.

Tú sólo decides cuántos decimales quieres usar tú, si te dan menos, se trunca, si te dan más, te salen ceros. Luego en esos dos casos que has puesto, suponiendo que hubieras decidido hacerlo con 5 decimales te quedaría: 1,36734 en el primer caso(136734) y  2,66000 en el segundo(266000)

Danielo515

Al final he tenido que tomar la decisión de tomar un numero determinado de decimales.
Era para un sistema de generación de números aleatorios (bastante malo por cierto) que se quedaba con la parte decimal de ciertas operaciones, y la parte decimal de ese numero era uno de los números aleatorios y la semilla del siguiente.
si daba 1,52 pues el 52 sería un numero aleatorio y la semilla para el siguiente.

Al final decidí tomar tantos decimales como cifras tuviera la semilla inicial.

Un saludo y muchas gracias.

SplinterGU

para numeros aleatoreos podrias usar get_timer y tomar algunos digitos... o alguna combinacion de operaciones sobre get_timer... si bien es un contador, en los momentos en que lo vas a requerir creo que te dar unos resultados bastante random.
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

Drumpi

Si el programa no se ejecuta siempre igual, es decir, necesita los numeros random en un momento indeterminado de tiempo, con los timers basta, si no, pues se le añade alguna operación con la hora y fechas actuales y listo, más random imposible.
Hala, como con 1001 procesos sólo va a 9 FPS, vamos a meterle 32 veces más, a ver si revienta.
(Drumpi epic moment)