Quedarme solo con algunos decimales.

Iniciado por astinx, 4 Abril 2012, 16:50 PM

0 Miembros y 1 Visitante están viendo este tema.

astinx

Hola, tengo un problema muy sencillo y que aún así me sigue quemando el coco.
Tengo una función que me devuelve un float, un float que es el resultado de 10/3, osea 3,333333...
Quiero recortarle algunos decimales cosa de que me quede como 3,333 o 3,3333.
Lo que hago es sencillo, tomo el float en cuestión, lo multiplico por 10⁴, si quiero tener 4 decimales luego de la coma y lo convierto a entero cosa de que me quede: 33333. Luego lo divido a ese entero, casteado a float por 10⁴, para volver a mover los decimales, cosa de que me quede 3,3333. Sin embargo lo que me ocurre es que cuando lo imprimo formateado como %.100f (cosa de ver todos los decimales posibles), me queda 3,333300000000003454345677. Esto me esta volviendo loco, porque solo me sucede con numeros periódicos y es un razonamiento muy sencillo.

El codigo seria algo como
int decimales = 3;
float miNumero = funcion_que_devuelve_float(10,3);
int miNumero2 = (int)(miNumero * pow(10,decimales));
float miNumero = (float)(miNumero2 / pow(10,decimales));

También intente multiplicar en ambos casos, en uno por la potencia negativa y en otro por la positiva, con el mismo resultado.

Muchas gracias por detenerse a leer y saludos.
La programación hoy en día es una carrera entre los ingenieros de software intentando construir mejores y más eficientes programas a prueba de idiotas y el Universo intentando producir mejores y más grandes idiotas. De momento, el Universo está ganando

Ferno

Esto se debe a que el número 3,3333 que te queda del último cálculo y el casteo a float (simple presición) es irrepresentable perfectamente en una computadora.
Lo que hace la máquina es aproximar este tipo de numeros por el conocido método del "Punto Flotante" que se rige bajo la norma IEEE754.

Se expresan de la forma: mantisa * 2^(exponente) Con la mantisa normalizada (1 =< mantisa < 2).

Lo que hace el micro es (lo explico en simple presición ya que estás usando el tipo float), representar el número utilizando 32 bits. Se utiliza:
1 bit para el signo del número (en este caso 0, positivo)
8 bits para el exponente (con la convención del Exceso-127)
23 bits para la mantisa.

Para el caso particular del 3,3333 éste se representa en binario como 1,10101010101010011001001....(sigue indefinidamente) * 2^(1)

Esto queda, utilizando simple presición:
(signo) | (exponente = 128 (se le suma 127 al exponente 1) ) | mantisa normalizada
0 | 10000000 | 10101010101010011001001

Y el resultado de ésta expresión es el número que se imprime al querer mostrar todos los decimales posibles de tu resultado.

Yo te diría que muestres los decimales que tengas que utilizar, si mostrás todos los posibles, jamás quedará un resultado redondo por lo que expliqué más arriba. Truncalo.
Espero que te sea de ayuda, creí conveniente explicar un poco cómo se maneja el micro en cuanto a números fraccionales.
Saludos!

astinx

Gracias, ahora usando _Decimal64 lo solucione :D
La programación hoy en día es una carrera entre los ingenieros de software intentando construir mejores y más eficientes programas a prueba de idiotas y el Universo intentando producir mejores y más grandes idiotas. De momento, el Universo está ganando

david_BS

#3

no se si era lo pedido, pero traté de improvisar algo con referencia a eso..

EI: la idea del foro es ayudar y no hacer.