Tengo un script que lee un archivo delimitado y suma el tercer elemento del archivo para cada registro. Para la mayoría de los archivos de datos, esto funciona bien excepto para uno. Tengo un archivo de datos donde hay 193 registros en el archivo de datos. Espero recuperar 2028219,43 del script. En cambio, obtengo un número exponencial que parece haber sido redondeado. Al principio pensé que al usar printf obtendría el número, pero si el número ya se ha redondeado, no me devolverá lo que esperaba.
Este es el código que estoy usando para leer el archivo de datos delimitado. Los datos de cada registro están delimitados por un *.:
export clm_total=$( awk -F* '{f1+=$3} END {print f1}' datafile.dat)
export new_clm_total=$(printf "%.2f" $clm_total)
Esto es lo que aparece en el registro cuando ejecuto el script:
+ export clm_total=2.02822e+06
+ printf %.2f 2.02822e+06
+ export new_clm_total=2028220.00
+ echo 2028220.00
Esta es una muestra del archivo de datos. Hay más registros, no pensé que fuera necesario mostrar los 193 registros:
CLM*123456789*4820.9***13:A:1**A*Y*Y
CLM*123698547*3642.05***13:A:7**A*Y*Y
CLM*147852369*579.25***13:A:1**A*Y*Y
CLM*789654123*929.8***13:A:1**A*Y*Y
Lo que espero es 2028219.43. Lo que recibo es 2.02822e+06, que luego se formatea como 2028220.00.
Respuesta1
Awk realiza aritmética con números de coma flotante de doble precisión. No sé exactamente hasta qué límite se obtienen resultados exactos para números con dos decimales, pero estás dentro del rango. Sin embargo estopodría ser un problema si los números aumentan. Si necesita asegurarse de obtener resultados exactos, limítese a los números enteros y tenga cuidado con el desbordamiento, o utilice bcel cual realiza aritmética de precisión arbitraria.
El problema aquí es que awk está calculando el resultado correcto, pero el formato de impresión predeterminado es aproximado. Utilice un formato explícito al imprimir el resultado.
export clm_total=$( awk -F'*' '{f1+=$3} END {printf "%.2f\n", f1}' datafile.dat)
Alternativamente, puede seguir printsiempre que cambie el formato de impresión para convertir números en cadenas. El valor predeterminado es %.6gel que da como resultado la aproximación que estás viendo.
export clm_total=$( awk -F'*' -v CONVFMT='%.2f' '{f1+=$3} END {print f1}' datafile.dat)
Respuesta2
Cuando se trata de matemáticas de punto flotante en informática (específicamente awken su caso), debe prestar atención a los mecanismos subyacentes que se utilizan para representar sus datos dentro del sistema.
Creo que este es el problema al que se enfrenta en su caso particular. Vea este artículo:D.3 Advertencias sobre los números de coma flotante, para obtener información adicional sobre el tema. Este artículo también fue útil para arrojar luz sobre el tema:15.2 Comprensión de la programación de punto flotante.
Lo mejor que puedo decir cuando se trata de números de coma flotante es que awkparece que solo tienes unos pocos dígitos disponibles para la porción de mantisa del número, por lo que a medida que continúas acumulando números llegas al punto en el que se introducen errores de redondeo y truncamiento y estás perdiendo precisión.
Ejemplo
Puede ver aquí cuando superamos el umbral y comenzamos a usar notación científica para rastrear el número real.
$ seq -f "%f" 1413 | awk '{f1+=$1+0.4} END {print f1}'
999556
$ seq -f "%f" 1414 | awk '{f1+=$1+0.4} END {print f1}'
1.00097e+06


