Delphius lo que dices es cierto, pero no dejamos de enfrentarnos en nuestra programación cotidiana (para la vida real, como dirían algunos) a ciertas situaciones bién curiosas que en teoría parecen obvias pero que en la práctica no lo son tanto y nos vemos forzados a buscar souciones más prácticas que ortodoxas, todo esto porque el diseño e implementación de una aplicación encierra cierto tipo de variables que a veces escapan a nuestro sueño purista, y eso en el mejor de los casos de que seamos nosotros los que iniciemos desde cero la aplicación, pero hay escenarios más complejos, en donde hay que trabajar sobre algo existente, o sobre diferentes orígenes de datos que dan tratamiento diferente a estos.
Para el caso de los números de punto flotante, se podría considerar:
1- Qué tipo de número es el que necesito manilpular o almacenar?
2- Cómo lo debo manipular o almacenar ? Porque si bien manipular el valor de la velocidad de una partícula en el acelerador de Hadrones y el valor del IVA en una factura matemáticamente son lo mismo, las precauciones y técnicas para abordarlos pueden (deben) ser diferentes.
3- Que herramientas voy a utilizar? Aquí empieza troya .... Que hardware?, Que lenguaje? , Que IDE?, Si necesito almacenar el número en cuestión en una DB, cual DB utilizar?, Que tipo de dato escoger?, Cómo me voy a conectar?.
4- Cómo lo quiero presentar? Esta también es fuente de desavenencias. En muchos casos necesitamos hacer los cálculos con cierta precisión pero solo mostrar por ejemplo los dos primeros decimales. En este punto también influye y mucho el componente visual que vamos a utilizar para mostrar los datos.
Voy a mencionar un ejemplo de una situación trivial pero curiosa que me ocurrió en esta semana y que ilustra un poco las anteriores líneas:
CREATE DOMAIN T_CANT7 AS
NUMERIC(10,7)
DEFAULT 0
NOT NULL;
CREATE DOMAIN T_PRECIO AS
NUMERIC(12,2)
DEFAULT 0
CHECK (VALUE >=0);
CREATE DOMAIN T_PORCENT AS
NUMERIC(3,2)
DEFAULT 0
CHECK (VALUE>=0);
CREATE TABLE DET_VENTAS (
ID_DETALLE T_ID NOT NULL /* T_ID = INTEGER NOT NULL */,
ID_VENTA T_ID /* T_ID = INTEGER NOT NULL */,
CANTIDAD T_CANT7 /* T_CANT7 = NUMERIC(10,7) DEFAULT 0 NOT NULL */,
ID_PRODUCTO T_ID /* T_ID = INTEGER NOT NULL */,
PRECIO T_PRECIO /* T_PRECIO = NUMERIC(12,2) DEFAULT 0 CHECK (VALUE >=0) */,
IMPUESTO T_PORCENT /* T_PORCENT = NUMERIC(3,2) DEFAULT 0 CHECK (VALUE>=0) */,
ID_USUARIO T_ID /* T_ID = INTEGER NOT NULL */
);
Tengo una tabla de detalles de venta como pueden apreciar (con los tipos de datos de los dominios), agrego un campo calculado de tipo Currency que me devuelva el valor de la línea de detalle, multiplicando la cantidad por el precio y sumándole el impuesto, hasta allí todo bien, cuando voy a mostrar la factura en la capa cliente en un TcxGird (el Grid de dev Express), en el formato para mostrar solo hago visibles los dos primeros decimales (como es lógico para mostrar dinero), este grid dispone de un potenete "Footer" en donde puedo mostrar el valor de la suma de una columna (en este caso la suma del campo calculado), yo hubiese podido agarrar el total de la columna directamente desde el Footer para asignarlo al Importe total de la venta pero no lo hice proque en el grid dejé abierta la posibilidad de filtrar los datos, lo que daría pie a obtener un valor incorrecto, en su defecto hice una función de tipo double que rrecorre la columna y suma los valores (sin filtrar), el valor de la función era el mismo que el de la suma en el footer pero cuando lo asignaba al Importe total de la venta, el bdEdit me mostraba un valor ligeramente diferente en el segundo decimal, porque? es claro que cada objeto de acceso a datos llámese driver, dbConnection, Dataset, etc, implementa ligeramente diferente su forma de manipulación de datos según su diseñador, por ejemplo un campo declarado en Firebird como Numeric (12,2), DBExpress lo mostrará como TFMTBCDField, FIBPlus como TFIBBCDField, Ado como TBCDField.
El caso es que si el usuario agarrara la calculadora y sumara lo que tenía ante sus ojos el resultado real para el, sería el que observaba en el footer (el mismo de la función) y encontraría como erróneo el valor del de dbEdit, en este punto fué que tuve (después de muchas pruebas) que utilizar la función que está en el ejemplo de un post anterior, aplicada a cada fila y no al total.
En conclusión es obvio que la matemática es una sola y no falla y lo que expresa el amigo Delphius en sus muy buenos aportes es irefutable, pero hay veces (muchas de ellas cuando ya hemos avanzado demsiado en un proyecto) que sin proponernos llegamos a unos callejones sin salida en donde nos vemos forzados a cualquier cosa (sin detrimento de la veracidad e integridad de los datos) para poder continuar y a veces para poder cumplir.
Saludos
PD: Es solo mi humilde opinión.