Ir al contenido


Foto

Error al convertir String a Float


  • Por favor identifícate para responder
20 respuestas en este tema

#1 cannabis

cannabis

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 257 mensajes
  • LocationMéxico

Escrito 27 diciembre 2016 - 04:30

Hola, foreros.
 

 
Este es el código:

delphi
  1. s_Importe:= InputBox('Pago del cliente', 'Importe','0');
  2.  
  3. f_Importe:= StrToFloat(s_Importe);
  4.  
  5. showmessage('s_Importe: ' + s_Importe + #13 +
  6.             'f_importe: ' + FormatFloat(',0.0000000000000000000000000000',f_Importe));

Con el importe: 16.51
 

delphi
  1. s_Importe = 16.51
  2.  
  3. f_Importe = 16.51000000000000160000000000

Con el importe: 17.58
 

delphi
  1. s_Importe = 17.58
  2.  
  3. f_Importe = 17.5799999999999983000000000000

¿Alguien ha tenido este problema?
 
 
 
Hasta pronto
  • 0

#2 cannabis

cannabis

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 257 mensajes
  • LocationMéxico

Escrito 27 diciembre 2016 - 04:31

Sospecho que me equivoqué con la etiqueta de código; es Delphi 7

 

 

Gracias.

 


  • 0

#3 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.448 mensajes
  • LocationMéxico

Escrito 27 diciembre 2016 - 04:44


[off-topic]
Un gusto verte por aquí de nuevo amigo cannabis, un abrazo.

Saludos


  • 0

#4 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.448 mensajes
  • LocationMéxico

Escrito 27 diciembre 2016 - 04:51

Hola
 
Acabo de hacer una prueba en Delphi 2007 y me muestra lo siguiente:
 


delphi
  1. procedure TForm2.Button1Click(Sender: TObject);
  2. var
  3. s_Importe: string;
  4. f_Importe: Extended;
  5. begin
  6. s_Importe:= InputBox('Pago del cliente', 'Importe','0');
  7. f_Importe:= StrToFloat(s_Importe);
  8. showmessage('s_Importe: ' + s_Importe + #13 +
  9. 'f_importe: ' + FormatFloat(',0.0000000000000000000000000000',f_Importe));
  10. end;

[Content]
s_Importe: 16.51
f_importe: 16.5100000000000000000000000000
[OK]
 
[Content]
s_Importe: 17.58
f_importe: 17.5800000000000000000000000000
[OK]

Saludos


  • 0

#5 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 27 diciembre 2016 - 05:17


delphi
  1. // delphi7
  2.  
  3. var
  4. s_Importe: String;
  5. f_Importe: currency;
  6. begin
  7. s_Importe:= '17,58';//InputBox('Pago del cliente', 'Importe','0');
  8.  
  9. f_Importe:= StrToFloat(s_Importe);
  10.  
  11. showmessage('s_Importe: ' + s_Importe + #13 +
  12. 'f_importe: ' + FormatFloat(',0.0000000000000000000000000000',f_Importe));
  13. end;

s_Importe: 17.58
f_importe: 17.5800000000000000000000000000


Saludos.
  • 0

#6 sir.dev.a.lot

sir.dev.a.lot

    Advanced Member

  • Miembros
  • PipPipPip
  • 545 mensajes
  • Location127.0.0.1

Escrito 27 diciembre 2016 - 05:19

Cual es el tipo de Dato que usa @Cannabis ?

 

Ya sabemos que Delphi 7, es el IDE #1 y Delphi 2007 el IDE #2 y @eGostar el Extended.

 

He visto algunos problemas de funciones de redondeo, en discusiones de StackOverflow y ExpertExchange.   Quizas el inconveniente este por ahi.

 

Saludos!


  • 0

#7 cannabis

cannabis

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 257 mensajes
  • LocationMéxico

Escrito 27 diciembre 2016 - 05:21

[off-topic]
Un gusto verte por aquí de nuevo amigo cannabis, un abrazo.

Saludos

 

El gusto es mío, egostar.


Con respecto a los resultados del InputBox, lo único diferente es que ahora estoy usando un componente (AlphaControls) que compré para que los programas no se sean muy simples visualmente.
Voy a desinstalarlo y probar.

Muchas gracias.


  • 0

#8 cannabis

cannabis

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 257 mensajes
  • LocationMéxico

Escrito 27 diciembre 2016 - 05:24

Cual es el tipo de Dato que usa @Cannabis ?

 

Ya sabemos que Delphi 7, es el IDE #1 y Delphi 2007 el IDE #2 y @eGostar el Extended.

 

He visto algunos problemas de funciones de redondeo, en discusiones de StackOverflow y ExpertExchange.   Quizas el inconveniente este por ahi.

 

Saludos!

 

Hola, sir.dev.a.lot

 

var

  s_Importe: AnsiString;

  f_Importe: Double;

 

 

 

 

var

  s_Importe: AnsiString;

  f_Importe: Double;

 

 

 


  • 0

#9 cannabis

cannabis

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 257 mensajes
  • LocationMéxico

Escrito 27 diciembre 2016 - 05:31


delphi
  1. // delphi7
  2.  
  3. var
  4. s_Importe: String;
  5. f_Importe: currency;
  6. begin
  7. s_Importe:= '17,58';//InputBox('Pago del cliente', 'Importe','0');
  8.  
  9. f_Importe:= StrToFloat(s_Importe);
  10.  
  11. showmessage('s_Importe: ' + s_Importe + #13 +
  12. 'f_importe: ' + FormatFloat(',0.0000000000000000000000000000',f_Importe));
  13. end;

Saludos.

 

 

Cambié la variable f_Importe a Currency y funciona.

 

Aunque me quedará la duda de por qué falla con la variable tipo Double.

 

 

Muchas gracias a todos.


  • 0

#10 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 27 diciembre 2016 - 05:35

Cambié la variable f_Importe a Currency y funciona.
 
Aunque me quedará la duda de por qué falla con la variable tipo Double.


Es un problema de la precisión de los tipos single y double.

Saludos.
  • 1

#11 cannabis

cannabis

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 257 mensajes
  • LocationMéxico

Escrito 27 diciembre 2016 - 05:38

Es un problema de la precisión de los tipos single y double.

Saludos.

 

Revisaré el programa para cambiar las variables a Currency.

 

Gracias escafandra.


  • 0

#12 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.448 mensajes
  • LocationMéxico

Escrito 27 diciembre 2016 - 05:52

Hola

 

Yo suelo utilizar Currency cuando se trata de cantidades monetarias, es lo mas adecuado (desde mi punto de vista),

 

En éste caso Delphi asignó la variable como Extended automáticamente al agregarlo con Ctrl+V.

 

saludos


  • 0

#13 sir.dev.a.lot

sir.dev.a.lot

    Advanced Member

  • Miembros
  • PipPipPip
  • 545 mensajes
  • Location127.0.0.1

Escrito 27 diciembre 2016 - 07:04

Hola

 

Yo suelo utilizar Currency cuando se trata de cantidades monetarias, es lo mas adecuado (desde mi punto de vista),

 

En éste caso Delphi asignó la variable como Extended automáticamente al agregarlo con Ctrl+V.

 

saludos

 

Si, esta es la verdadera manera de trabajar sin errores... el tipo de dato CURRENCY.

 

Que bueno que se resolvio.

 

Saludos!


  • 0

#14 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 27 diciembre 2016 - 08:19

s_Importe = 16.51

f_Importe = 16.51000000000000160000000000

 

 s_Importe = 17.58

f_Importe = 17.5799999999999983000000000000

 

 

Esos problemas de aproximacion ocurren porque no estas usando el tipo de dato adecuado. Si necesitas precision en los digitos decimales, deberias usar currency, como se comento.

 

Los tipos flotantes, Single, Double y Extended tienen el problema de que existe la posibilidad de que no puedan representar exactamente un valor, por eso se dice que hay perdida de precision; entonces el numero es convertido automaticamente al valor mas cercano posible de representar para el tipo de datos. De hecho te pueden ocurrir absurdos en los que esta sentencia evalua falso:


delphi
  1. var
  2. X: Single;
  3. Y: Double;
  4. begin
  5. X := 0.1;
  6. Y := 0.1;
  7. X = Y --> Evalua a falso
  8. end;

http://docwiki.embar...oint_Arithmetic

 

El currency es en realidad un Int64, por lo tanto no se almacena como un numero de punto flotante, sino de punto fijo. Se aplica automaticamente un "scaling" multiplicando o dividiendo por 10000 cuando sea necesario Osea basicamente los ultimos 4 digitos del Int64 son los 4 decimales de tu valor

 

Este link te permite ver como se representa un numero en los tipos Single, Double y Extended de Delphi

http://pages.cs.wisc...at?number=17.58

 

Tenes que cambiar el tipo de las variables a Currency donde sea adecuado, y ademas tambien utilizar las funciones de conversion desde/hacia string pero para el tipo Currency. Donde antes usabas StrToFloat ahora usas StrToCurr, y donde antes usabas FloatToStr ahora usas CurrToStr


  • 1

#15 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 27 diciembre 2016 - 10:18

Para ampliar las explicaciones de Escafandra y Agustín déjenme decir que el tipo Double solo puede tener 15 dígitos significantes (16 para un caso especial). De ahí en adelante es basura.

Si se ponen a contar los dígitos de 16.51000000000000160000000000 desde el 1ro de la izquierda hacia la derecha, llegarán a que justo esos 160000000000 están en el 16vo dígito.

 

No se aconseja usar extended a menos que sea estrictamente necesario. Esto es debido a que su implementación depende de la arquitectura.

 

Hace un buen tiempo he dejado un hilo con mucho material sobre aritmética de punto flotante. Recomiendo por sobre todo la lectura del documento "Lo que todo informático debe saber sobre aritmética flotante". El título lo dice todo, es un tanto denso (y está en inglés) pero vale la pena su lectura.

 

Lo qu si me permito corregir a Agustín es su 1er párrafo:

 

 

Esos problemas de aproximacion ocurren porque no estas usando el tipo de dato adecuado. Si necesitas precision en los digitos decimales, deberias usar currency, como se comento.

 

El problema no es que esté usando el tipo adecuado, o que un tipo no sea correcto ni preciso.

El tipo Double es bastante útil, para casi todas las operaciones de la vida real que imaginemos. Si, hasta para ciertas operaciones de ingeniería nos es suficiente.

 

El problema no son los tipos... ni la cantidad de decimales, ni la aritmética flotante.

El problema está en que le damos un uso incorrecto para lo cual fueron pensados.

 

Y esto es más que nada por el desconocimiento del funcionamiento y de como es que fueron implementados. Si tenemos presente el formato de cada tipo de dato de aritmética flotante y definimos los criterios tolerable de pérdida de precisión aceptables entonces el miedo a usarlos desaparece. Los cálculos SI se hacen de manera precisa y exacta a los dígitos significativos que fueron definidos. Pretender ir más allá para lo cual fueron pensados y diseñados es nuestro error.

 

Estadísticamente, para el caso del tipo double podemos trabajar sin temor alguno hasta el orden de e-12. Dejando los dos últimos dígitos de guarda como error tolerables para nuestras operaciones. Es más este valor (e-12) es el valor por defecto de la variable epsilon para la determinación del error absoluto para el tipo double. Internamente los cálculos se realizan de manera precisa para los "dígitos faltantes", pero es habitual y más que recomendable dejar esta guarda ya que cuanto operemos con otros cálculos posterioes son estos últimos los que se verán afectados por algún desplazamiento de la coma.

 

Saludos,


  • 2

#16 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 28 diciembre 2016 - 05:46

Para apoyar las explicaciones de Delphius:
What Every Computer Scientist Should Know About Floating-Point.
¿Cuál es el valor de epsilon (o como calcularlo) de Delphi?
Aparecen decimales indeseados en una suma simple

Algún enlace me dejo por el camino.

 

 

Saludos.


  • 2

#17 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 28 diciembre 2016 - 11:18

 

Gracias por citar mi hilo amigo. Anoche estaba cansado y medio vago como para buscar el enlace y ponerlo. :D

 

Saludos,


  • 0

#18 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 28 diciembre 2016 - 12:59

 

El problema no es que esté usando el tipo adecuado, o que un tipo no sea correcto ni preciso.

El tipo Double es bastante útil, para casi todas las operaciones de la vida real que imaginemos. Si, hasta para ciertas operaciones de ingeniería nos es suficiente.

 

Me exprese mal pero lo que queria transmitir era esto. El pobre Double no tiene la culpa, sino que, como te gusta decir a vos, es un problema de la capa 8 en el modelo OSI   (h)  (h)

 

Por otra parte, si nos ponemos en modo programadoril, habria que ver como se comporta en terminos de eficiencia el tipo flotante vs Currency. Me imagino que las operaciones en Currency son mucho mas eficientes. Aunque quiza en 32 bits este mas "peleado", en 64 bits deberia ganar "por goleada" el Currency porque entrarian los 64 bits en un registro de la CPU. Digo para casos en los que no son necesarios tantos decimales (ej: porcentaje de algo)


Editado por Agustin Ortu, 28 diciembre 2016 - 01:02 .

  • 1

#19 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 28 diciembre 2016 - 05:19

Me exprese mal pero lo que queria transmitir era esto. El pobre Double no tiene la culpa, sino que, como te gusta decir a vos, es un problema de la capa 8 en el modelo OSI   (h)  (h)

 

Por otra parte, si nos ponemos en modo programadoril, habria que ver como se comporta en terminos de eficiencia el tipo flotante vs Currency. Me imagino que las operaciones en Currency son mucho mas eficientes. Aunque quiza en 32 bits este mas "peleado", en 64 bits deberia ganar "por goleada" el Currency porque entrarian los 64 bits en un registro de la CPU. Digo para casos en los que no son necesarios tantos decimales (ej: porcentaje de algo)

 

No hay problema Agustín. Tampoco es que te estaba culpando; simplemente aclaraba.

 

No soy un experto en tema, pero me animo a decir que SIEMPRE es más rápido trabajar con un entero que con un tipo de coma flotante, y esto es independiente del tamaño del tipo.

A la máquina le resulta trivial manejarse con enteros, y como sabemos: currency es un entero. Multiplicar y/o dividir por 1000 no le cuesta nada... ¡simplemente dezplaza los bits la cantidad necesaria!

En el mundo de la aritmética de punto flotante las cosas son más complicadas. Entran cuestiones más técnicas como verificar si hay que cambiar el exponente (dezplazar la coma), (des)normalizar el número, etc. Hay más pasos intermedios que efectuar.

 

Saludos,


  • 1

#20 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 28 diciembre 2016 - 08:00

A la máquina le resulta trivial manejarse con enteros, y como sabemos: currency es un entero. Multiplicar y/o dividir por 1000 no le cuesta nada... ¡simplemente dezplaza los bits la cantidad necesaria!

Una aclaración, el procesador desplaza bits para multiplicar solo si multiplicamos o dividimos por una potencia de 2, en otro caso el cálculo se complica un poco más.

 

Desplazar un bit a la izquierda es multiplicar por dos y a la derecha, dividir por 2.

 

 

Saludos.


  • 1




IP.Board spam blocked by CleanTalk.