Pregunta

La aplicación de mis clientes exporta e importa bastantes variables de tipo real a través de un archivo de texto usando writeln y readln. Intenté aumentar el ancho de los campos escritos para que el código se vea así:

writeln(file, exportRealvalue:30); //using excess width of field
....
readln(file, importRealvalue);

Cuando exporto y luego importo y exporto nuevamente y comparo los archivos, obtengo una diferencia en los últimos dos dígitos, por ejemplo (podría estar desactivado en el número real de dígitos aquí pero lo obtienes):

-1.23456789012E-0002
-1.23456789034E-0002

Esto realmente marca la diferencia en la aplicación, por lo que el cliente quiere saber qué puedo hacer al respecto. Ahora no estoy seguro de que sea solo la escritura / lectura lo que lo hace, pero pensé en lanzar una pregunta rápida antes de sumergirme en la pila de hey nuevamente. ¿Tengo que ir binario en esto?

Esta no es una aplicación que se ocupe de moneda o algo, simplemente escribo y leo los valores en / desde el archivo. Sé que los puntos flotantes son un poco extraños a veces y pensé que una de las rutinas (writeln / readln) puede tener algunos asuntos divertidos en curso.

¿Fue útil?

Solución

Si desea especificar la precisión de un real con un WriteLn, use lo siguiente:

WriteLn(RealVar:12:3);

Produce el valor Realvar con al menos 12 posiciones y una precisión de 3.

Otros consejos

Puede intentar cambiar a extendido para mayor precisión. Sin embargo, como se señaló, los números de coma flotante solo tienen tantos dígitos significativos de precisión, por lo que aún es posible mostrar más dígitos que luego se almacenan con precisión, lo que podría dar como resultado el comportamiento que especificó.

De la ayuda de Delphi:

Tipos reales fundamentales de Win32

                                            | Significant | Size in 
Type     | Range                            | digits      | bytes
---------+----------------------------------+-------------+----------
Real     | -5.0 x 10^–324 .. 1.7 x 10^308   | 15–16       |   8  
Real48   | -2.9 x 10^–39 .. 1.7 x 10^38     | 11-12       |   6   
Single   | -1.5 x 10^–45 .. 3.4 x 10^38     |  7-8        |   4   
Double   | -5.0 x 10^–324 .. 1.7 x 10^308   | 15-16       |   8   
Extended | -3.6 x 10^–4951 .. 1.1 x 10^4932 | 10-20       |  10   
Comp     | -2^63+1 .. 2^63–1                | 10-20       |   8   
Currency | -922337203685477.5808..          |             | 
                    922337203685477.5807    | 10-20       |   8   
  

Nota : el tipo Real48 de seis bytes se llamaba Real en versiones anteriores de Object Pascal. Si está volviendo a compilar código que usa el tipo Real de seis bytes anterior en Delphi, puede cambiarlo a Real48 . También puede usar la directiva del compilador {$ REALCOMPATIBILITY ON} para convertir Real nuevamente en el tipo de seis bytes. Las siguientes observaciones se aplican a los tipos reales fundamentales.

     
      
  • Real48 se mantiene por compatibilidad con versiones anteriores. Dado que su formato de almacenamiento no es nativo de la arquitectura del procesador Intel, resulta en un rendimiento más lento que otros tipos de punto flotante.
  •   
  • Extendido ofrece mayor precisión que otros tipos reales, pero es menos portátil. Tenga cuidado al usar Extended si está creando archivos de datos para compartir entre plataformas.
  •   

Observe que el rango es mayor que los dígitos significativos. Por lo tanto, puede tener un número mayor que luego se puede almacenar con precisión. Recomendaría redondear a los dígitos significativos para evitar que eso suceda.

Cuando utilice tipos de punto flotante, debe tener en cuenta las limitaciones de precisión en los tipos especificados. Un tipo IEEE-754 de 4 bytes, por ejemplo, tiene solo alrededor de 7.5 dígitos significativos de precisión. Un tipo IEEE-754 de ocho bytes tiene aproximadamente el doble del número de dígitos significativos. Aparentemente, el tipo real delphi tiene una precisión que ronda los 11 dígitos significativos. El resultado de esto es que cualquier dígito adicional de formato que especifique es probable que sea ruido que puede generar conversiones entre los valores formateados en base 10 y los valores de coma flotante en base 2.

En primer lugar, trataría de ver si puedo obtener ayuda al usar Str con diferentes argumentos o aumentar la precisión de los tipos en su aplicación. (¿Has intentado usar Extended?)

Como último recurso, ( ¡Advertencia! ¡Solución! ) Intentaría guardar la representación de cadena del cliente junto con la representación binaria en una lista ordenada. Antes de volver a escribir un valor de coma flotante, vería si ya hay un valor coincidente en la tabla, cuya representación de cadena ya se conoce y se puede usar en su lugar. Para que esta búsqueda sea rápida, puede ordenarla según el valor numérico y utilizar la búsqueda binaria para encontrar la mejor coincidencia.

Dependiendo de cuánto procesamiento necesite hacer, una alternativa podría ser mantener los números en formato BCD para mantener la precisión original.

Es difícil responder esto sin saber de qué tipo son sus ExportRealValue e ImportRealValue. Como otros han mencionado, los tipos reales tienen diferentes precisiones.

Vale la pena señalar, al contrario de lo que se piensa, extendido no siempre es una precisión mayor. Extendido es 10-20 cifras significativas donde el doble es 15-16. Como tiene problemas alrededor de la décima sig fig, quizás ya esté usando extendido.

Para obtener un mayor control sobre la lectura y la escritura, puede convertir los números hacia y desde las cadenas usted mismo y escribirlos en una secuencia de archivos. Al menos de esa manera no tiene que preocuparse si readln y writeln no son buenos a sus espaldas.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top