Cuando cero no es igual a cero

Published on

in

,

Si PHP es la plataforma de tu elección, y estás convencid@ de su efectividad, seguramente has tenido que discutir con seguidores de otras plataformas respecto su superioridad o inferioridad comparada con estas alternativas.

Sin embargo, llegará ese momento incómodo, el pedazo de cascarón en un huevo revuelto que no esperas, la pasa en el pan de dulce que amarga todo, el pistache rancio que echa a perder tu botana: el momento PHP, el instante en que PHP es indefendible y aquí te narro el mío.

Mi crónica es acerca de un script que leía un conjunto de registros de una base de datos, y a través de un algoritmo de prorrateo, por cada registro leído de tabla, el monto reportado es distribuido en un conjunto de centro de costos de acuerdo a porcentajes definidos. Durante cada iteración, los montos distribuidos se van acumulando, de forma que al final, sea posible verificar si el prorrateo ha sido exitoso, es decir, que no falte y no sobre monto comparado con el original.

Por ser el prorrateo una operación de distribución, era posible perder precisión cuando se acumulan los montos distribuidos. Para verificar que esta pérdida de precisión estuviera dentro de un rango aceptable, se obtenía el valor absoluto de la diferencia entre el monto original y la suma de los montos distribuidos. Si esta diferencia excedía un monto máximo, entonces se alertaba al usuario para que tomara medidas preventivas. Y es aquí donde inicia ese pequeño infierno que puede ser PHP.

El algoritmo era más o menos como sigue (no puedo exponer el código porque es propiedad del organismo para quien se hizo):

if ( $montoOriginal != $acumuladoProrrateado ) { 
$diferencia = abs($montoOriginal - $acumuladoProrrateado); 
} 
if ( $diferencia > 0 ) 
{ 
// notificacion al usuario ... 
}

El problema surgió cuando, durante las pruebas, un registro notificaba tener diferencia entre el monto prorrateado y el monto original, y esta diferencia… en realidad no existía. Después de verificar todo el flujo del proceso (todos los pasos de la distribución) llegamos a la determinación de que el programa estaba detectando una diferencia en la variable $diferencia. ¿Qué quiero decir con eso? A manera de debug, desplegamos el valor de $diferencia en cada punto, excepto después de declarar la variable, es decir, algo como lo que sigue:

if ( $montoOriginal != $acumuladoProrrateado ) { 
$diferencia = abs($montoOriginal - $acumuladoProrrateado); 
echo "Diferencia calculada: ".$diferencia; 
} 
if ( $diferencia > 0 ) { 
echo "Diferencia es mayor a cero: ".$diferencia; 
// notificacion al usuario … 
}

El valor de $diferencia era siempre el mismo: 0.00000001784, que aunque apenas significativo sí es un valor distinto de cero.

La primera revisión era obvia, $diferencia no se había incializado y era probable que se hubiera creado con «basura». Así que modificamos el script:

$diferencia = 0; if ( $montoOriginal != $acumuladoProrrateado ) { $diferencia = abs($montoOriginal - $acumuladoProrrateado); echo "Diferencia calculada: ".$diferencia; } if ( $diferencia > 0 ) { echo "Diferencia es mayor a cero: ".$diferencia; // notificacion al usuario … }

Pero el resultado fue igual: 0.00000001784.

Probamos de todo. Hacer casting a double al iniciar la variable, casting a cada valor obtenido de la base de datos antes de hacer los cálculos, durante el prorrateo, a la variable diferencia… pero todas y cada una de las veces, la variable $diferencia portaba el valor 0.00000001784, y lo más curioso, sólo con este caso, en otros casos dondea diferencia calculada era cero, la variable en turno almacenaba un cero perfecto.

En esos momentos sólo puedes pensar: «…con razón la gente odia PHP».

¿La solución?

Una técnica matemática: el cambio de variable. El script quedó como sigue:

$diferenciaCalc = 0; if ( $montoOriginal != $acumuladoProrrateado ) { $diferenciaCalc = abs($montoOriginal - $acumuladoProrrateado); echo "Diferencia calculada: ".$diferenciaCalc; } if ( $diferenciaCalc > 0 ) { echo "Diferencia es mayor a cero: ".$diferenciaCalc; // notificacion al usuario … }

-¿Es decir que cambiar el nombre a la variable arregló el problema?

-Pues… sí. ¿Qué te digo?

<?php echo «Hasta aquí la crónica…»; ?>

Deja un comentario

Descubre más desde Crónicas de Programación

Suscríbete ahora para seguir leyendo y obtener acceso al archivo completo.

Seguir leyendo