Ir al contenido


Foto

Sumas Raras en un select


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

#1 agag4

agag4

    Advanced Member

  • Miembros
  • PipPipPip
  • 298 mensajes
  • LocationMéxico

Escrito 11 febrero 2011 - 03:04

Tengo una sentencia SQL en firebird 1.5

Select Coalesce(Importe,0) + Coalesce(IVA,0) total from tabla ....

me arroja los totales bien, pero al visualizarlos en el Qreporte me sale otro total, y si reproduzco el select en el ibexpert, tambien me pasa lo mismo, les anexo la imagen donde se mira....

Siendo que en el resultado de la suma debe de ser = CERO  (h)

Archivos adjuntos


  • 0

#2 Caral

Caral

    Advanced Member

  • Moderador
  • PipPipPip
  • 4.266 mensajes
  • LocationCosta Rica

Escrito 11 febrero 2011 - 03:34

Hola
Y encerrandolos?
Select Coalesce((Importe,0) + Coalesce(IVA,0)) total from tabla ....Saludos
  • 0

#3 eduarcol

eduarcol

    Advanced Member

  • Administrador
  • 4.483 mensajes
  • LocationVenezuela

Escrito 11 febrero 2011 - 03:38

el problema no es el select, el problema esta en firebird y el tipo de dato flotante, para evitar esto debes trabajar los montos como numeric(15,2)
  • 0

#4 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 11 febrero 2011 - 05:21

Hola agag4,
Primeramente deberías indicarnos el tipo de dato que definiste en el/los campo/s. Dependiendo de esto se define la precisión con la que se harán los cálculos. En teoría, un tipo de datos compatible y equiparable con double precisition debería ser suficiente para que la mayoría de los cálculos sean más precisos y que al momento de aplicar los redondeos se pueda garantizar un resultado más exacto.

En segundo lugar hay que tener presente que en el mundo de la aritemética de coma flotante no existe exactitud, sino una aproximación de exactitud. Aún utilizando el tipo de datos más preciso que acepte la arquitectura de tu máquina (aún hoy en día el tipo más preciso es el double extended pero no se recomienda su utilización) los cálculos nunca serán 100% exactos. Si lee el resultado "exactamente" esperado se debe en realidad a que por dentro de la aritmética IEEE de punto flotante existen algoritmos de redondeo exacto que garantizan un valor preciso en el orden de +/- 0.5 ulp.

Ese valor que estás obteniendo muy posiblemente sea el mínimo valor subdesbordado parcial. Es decir, el mínimo valor posible a representar mayor a cero.

Te conviene tener en cuenta el material disponible en este hilo para comprender el tema.
  • 0

#5 agag4

agag4

    Advanced Member

  • Miembros
  • PipPipPip
  • 298 mensajes
  • LocationMéxico

Escrito 11 febrero 2011 - 05:42

El tipo de dato que uso es numeric 16,4
  • 0

#6 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.137 mensajes

Escrito 11 febrero 2011 - 06:35

Usa la función que pongo en el ejemplo, compara los resultados obtenidos con Button1Click (-5,55111512312578E-17) y con Button2Click (0).



delphi
  1. unit Unit1;
  2.  
  3. interface
  4.  
  5. uses
  6.   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  7.   Dialogs, StdCtrls;
  8.  
  9. type
  10.   TForm1 = class(TForm)
  11.     Button1: TButton;
  12.     Button2: TButton;
  13.     procedure Button1Click(Sender: TObject);
  14.     procedure Button2Click(Sender: TObject);
  15.   private
  16.     { Private declarations }
  17.   public
  18.     { Public declarations }
  19.   end;
  20.  
  21. var
  22.   Form1: TForm1;
  23.  
  24. implementation
  25.  
  26. {$R *.dfm}
  27.  
  28. procedure TForm1.Button1Click(Sender: TObject);
  29. const
  30.   Numeros: array [0 .. 5] of double = (-0.10, -0.10, -0.10, 0.50, -0.10, -0.10);
  31. var
  32.   Val: double;
  33.   i: integer;
  34. begin
  35.   Val := 0;
  36.   for i := 0 to 5 do
  37.     Val := Val + Numeros[i];
  38.   showmessage(floatTostr(Val))
  39. end;
  40.  
  41. function Redondea(Valor: double; PrecisionDec: Byte): double;
  42.   function Potencia(Base: double; Exponente: Byte): double;
  43.   begin
  44.     Result := Exp(Exponente * ln(Base))
  45.   end;
  46.  
  47. begin
  48.   Result := Round(Valor * Potencia(10, PrecisionDec)) / Potencia
  49.     (10, PrecisionDec)
  50. end;
  51.  
  52. procedure TForm1.Button2Click(Sender: TObject);
  53. const
  54.   Numeros: array [0 .. 5] of double = (-0.10, -0.10, -0.10, 0.50, -0.10, -0.10);
  55. var
  56.   Val: double;
  57.   i: integer;
  58. begin
  59.   Val := 0;
  60.   for i := 0 to 5 do
  61.     Val := Redondea(Val, 2) + Redondea(Numeros[i], 2);
  62.   showmessage(floatTostr(Val))
  63. end;
  64.  
  65. end.


  • 0

#7 agag4

agag4

    Advanced Member

  • Miembros
  • PipPipPip
  • 298 mensajes
  • LocationMéxico

Escrito 11 febrero 2011 - 06:54

Te quedo al fregazo la funcion del redondeo, pero lo malo es que en delphi en donde me sale tambien mal la suma es dentro del Qreport, uso bandas TQrGroup para hacer agrupaciones entre los movimientos, y solo hace la autosuma con el TQRExpr, y en el evento beforeprint del TQrExpr formateo el importe a como saldria:


delphi
  1. procedure TfhotGenImpreMovDiarios.QRExpr40Print(sender: TObject;
  2.   var Value: String);
  3. begin
  4.   value := FormatFloat('###,###,##0.00',Redondea(StrToFloat(value),2));
  5. ....
  6.  


No me suma correctamente, aqui me sale el resultado = 3.47, en vez de salir a CERO.
  • 0

#8 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.137 mensajes

Escrito 11 febrero 2011 - 07:12

Lo que pasa es que solo estás redondeando  el total, también debes hacerlo con los valores a sumar.
Desconozco tu implementación, pero se me ocurre que podrías crear un campo calculado y al valor de este le pasas la función, entonces en el reporte no usas el campo original sinó el campo calculado ya redondeado.

Saludos
  • 0

#9 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 11 febrero 2011 - 10:04

Wilson, Delphi ya viene con funciones de redondeo bastante similares a la que expones. Cito algunas: Round(), RoundTo(), SimpleRoundTo(). Y también están Ceil(), Floor(). Están definidas en la unidad Math (excepto Round() que está en System). Y además es posible cambiar el modo de redondeo gracias a la función SetRoundMode().

Y si se quiere llegar más lejos, hasta tenemos la posibilidad de establecer el tipo de precisión que debe adoptar el compilador al modificar la palabra de control del FPU con SetPrecisionMode().

En lo que no estoy de acuerdo es lo de redondear cada número. Esto en realidad "inflará" el resultado haciendo quizá que el error relativo final aumente en un 50% en cada operatoria. Por ejemplo, si se realizan n sumas entonces tendrás 0,5 ulp + (n * 0,5 ulps). Supongamos 10 sumas: 0,5 ulp + (10 * 0,5) = 5,5 ulps.

Es decir que, por ejemplo hagamos de cuenta que se calcula una sumatoria de 3468,179. El resultado "real" de dicha suma estará en realidad en el rango 3468,179 +/- 5,5 ulps = [3468,1735;3468,1845]

El resultado sería distinto si se hiciera la sumatoria y al final se redondease. Al menos así podríamos esperar un mejor efecto cancelatorio de redondeo, y al finalizar tendremos como siempre cuanto mucho un 0,5 ulp.

Ahora bien, si uno quisiera ser bien meticuloso y generar una gran precisión en una sumatoria debería pensarse en la implementación del algoritmo de Kahan.

Ante todo hago la aclaración de que ya el estánder IEEE 754 establece que las operaciones deben realizarse "exactamente redondeadas" por lo que uno no debería preocuparse demasiado en perder precisión en las operatorias intermedias sino más bien que debería centrarse en determinar que sus propios algoritmos funcionen adecuadamente y en los límites pre-establecidos del márgen del error (tanto relativo como absoluto).

Agag4, ¿Los valores de los campos son muy altos? ¿O son cercanos a ceros? Porque si en realidad hay muchos registros y algunos de ellos son cercanos al valor máximo esperado entonces lo de esperar es un desbordamiento y a lo mejor Firebird toma solamente el "residuo" de dicho desborde.

Por ejemplo: el máximo para el integer (2^32) es 4294967296 y si le sumamos 1, obtendríamos esto: 4294967297 pero como el valor es mayor al esperado en realidad nos quedaríamos como la "diferencia" entre el máximo y el actual: -1.

Nos sería de mucha ayuda el que nos digas la clase del Field correspondiente a dicho resultado. Si tienes los campos persistentes. Esto nos podría decir mucho de la precisión esperada y con la que está operando.

Saludos,
  • 0

#10 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.137 mensajes

Escrito 12 febrero 2011 - 08:49

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:



sql
  1. CREATE DOMAIN T_CANT7 AS
  2. NUMERIC(10,7)
  3. DEFAULT 0
  4. NOT NULL;
  5.  
  6. CREATE DOMAIN T_PRECIO AS
  7. NUMERIC(12,2)
  8. DEFAULT 0
  9. CHECK (VALUE >=0);
  10.  
  11. CREATE DOMAIN T_PORCENT AS
  12. NUMERIC(3,2)
  13. DEFAULT 0
  14. CHECK (VALUE>=0);
  15.  
  16. CREATE TABLE DET_VENTAS (
  17.     ID_DETALLE  T_ID NOT NULL /* T_ID = INTEGER NOT NULL */,
  18.     ID_VENTA    T_ID /* T_ID = INTEGER NOT NULL */,
  19.     CANTIDAD    T_CANT7 /* T_CANT7 = NUMERIC(10,7) DEFAULT 0 NOT NULL */,
  20.     ID_PRODUCTO  T_ID /* T_ID = INTEGER NOT NULL */,
  21.     PRECIO      T_PRECIO /* T_PRECIO = NUMERIC(12,2) DEFAULT 0 CHECK (VALUE >=0) */,
  22.     IMPUESTO    T_PORCENT /* T_PORCENT = NUMERIC(3,2) DEFAULT 0 CHECK (VALUE>=0) */,
  23.     ID_USUARIO  T_ID /* T_ID = INTEGER NOT NULL */
  24. );



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.
  • 0

#11 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 12 febrero 2011 - 09:25

Si tampoco digo no hay que analizar lo que comentas amigo. Sino que intento explicar a Agag4 que en el mundo de la aritemética flotante no existe exactitud.

Como bien indicas, dependiendo del formato y tipo definido para el campo tendremos cierta precisión y además en el tipo de Field que los componentes de acceso a base de datos crean.

En teoría, al menos, se aconseja utilizar el tipo de dato Currency para cálculos monetarios ya que está diseñado para esto. Como sabemos, este tipo es bastante especial ya que en realidad es un tipo entero y en la aritemética entera hay precisión exacta.
A los Fields que son de carácter monetario es más que aconsejable establecer la propiedad Currency (si dispone de ésta) en true. Para obligar al compilador a utilizar este tipo y no uno derivado en la "familia" BCD.

También hay que considerar que en lo posible hay que evitar la mezcla de variables de diferentes precisión y tipos. Un ejemplo, medio ridículo:



delphi
  1. var a: single;
  2. b: double;
  3. b := Pi/2;
  4. a := b * 2;
  5. ShowMessage(FloatToStr(a));
  6. ShowMessage(FloatToStr(b*2));



Lo que dices de que en ocasiones nos vemos motivados a hacer esos tipos de soluciones no te digo que esté mal... No hay otra salida. A lo que voy es que en lo posible hay que analizar mejor nuestros casos, comprender mejor las limitaciones de cada tipo de dato, tener en cuenta las operaciones que van a realizar, etc.

Yo por algo he finalizado mi mensaje pidiéndole a agag4 que nos brinde más información, que al menos nos diga el Field que tiene... y si, sería más que oportuno que nos indique los componentes de acceso que utiliza.

Saludos,
  • 0

#12 agag4

agag4

    Advanced Member

  • Miembros
  • PipPipPip
  • 298 mensajes
  • LocationMéxico

Escrito 12 febrero 2011 - 09:46

Muchas gracias por sus comentarios y aportaciones son muy valiosas, uso los componentes fibplus v6.3, con delphi7, firebird 1.5, el tipo da dato de los campos son Numeric 16,4
  • 0

#13 agag4

agag4

    Advanced Member

  • Miembros
  • PipPipPip
  • 298 mensajes
  • LocationMéxico

Escrito 12 febrero 2011 - 10:13

Al parecer se soluciono agregando F_ROUNDFLOAT(D.IMPORTE,0.05) + F_ROUNDFLOAT(D.IVA,0.05) es con una función externa para firebird que encontre en un portal de internet, pero como dicen no es correcto redondear por registro porque va a variar en los totales.
  • 0

#14 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.137 mensajes

Escrito 12 febrero 2011 - 10:36

De eso mismo te quería hablar.  EL amigo Delphius que tiene una base matemática sólida nos puede ayudar a escoger la función mas apropiada para tu caso (aunque creo que la que escogiste es la correcta).

FBUDF ROUND (VALUE)
Linux, Win32 Rounds a fixed numeric number up or down to the nearest integer.
Arguments value is a column or expression that evaluates to a fixed numeric type
with a scale > 0.
Return value A number of an integer type.
Notes This is plain rounding—if the digit immediately to the right of the
decimal is equal to or greater than 5, it adds 1 to the digit at the left of
the decimal point, and then truncates any digits to the right.
Otherwise, it truncates all digits to the right of decimal point.
Example The following statement calculates an estimate based on the result of
rounding the product of two NUMERIC(11,2) numbers up or down:
SELECT JOB_NO, ROUND(RATE * HOURS) + 1 AS ESTIMATE
FROM QUOTATION
WHERE RATE IS NOT NULL AND HOURS IS NOT NULL;

FREEUDFLIB F_ROUNDFLOAT(VALUE1, VALUE2)
Win32 Attempt to round the passed value up or down to the nearest specified
fraction.
Arguments value1: A column or expression that evaluates to a floating-point type.
This is the number to be rounded.
value2: A column or expression that evaluates to a floating-point type.
This must be a number less than 1 and greater than 0. For example,
pass a value2 of 0.25 to round to the nearest quarter.
Return value A floating-point number, which will be value1 rounded up or down to
the nearest specified value2 fraction.
Example The following statement calculates PAID_HOURS by rounding
HOURS_WORKED up or down to the nearest quarter-hour:
UPDATE TIMESHEET
SET PAID_HOURS = F_ROUNDFLOAT(HOURS_WORKED, 0.25)
WHERE DATE_TIMESTAMP > CURRENT_DATE - 7;

FREEUDFLIB F_DOUBLEABS(VALUE)
Win32 Returns the absolute value of a floating-point number.
Arguments value is a column or expression that evaluates to a number of type
DOUBLE PRECISION or FLOAT.
Return value A positive number of type DOUBLE PRECISION.
Example SELECT ABS(SUM(ASSET_VALUE)) AS LIABILITY
FROM ASSET_REGISTER
WHERE ASSET_VALUE < 0;
See also ABS( ), another external function that performs the same
task and is available on non-Windows platforms.

IB_UDF CEILING(VALUE)
Linux, Win32 Returns a DOUBLE PRECISION value representing the smallest
integer that is greater than or equal to the input value.
Arguments value is a column or expression that evaluates to a number of
DOUBLE PRECISION type.
Return value A DOUBLE PRECISION number with a zero decimal part.
Example SELECT CEILING(LAST_TOTAL) AS ROUND_UP_NEAREST
FROM SALES_HISTORY;

IB_UDF FLOOR(VALUE)
Linus, Win32 Returns a floating-point value representing the largest integer that is
less than or equal to value.
Arguments value is a column or expression that evaluates to a number of
DOUBLE PRECISION type.
Return value A DOUBLE PRECISION number with a zero decimal part.
Example SELECT FLOOR(CURRENT_DATE - START_DATE) AS DAYS_ELAPSED
FROM DVD_LOANS;


  • 0

#15 agag4

agag4

    Advanced Member

  • Miembros
  • PipPipPip
  • 298 mensajes
  • LocationMéxico

Escrito 12 febrero 2011 - 10:50

Ahora la bronca que traigo es que se me arreglaron esos importes pero me alteraron otros que tenia en ese mismo reporte, como dicen, no es recomendable aplicar redondeos sobre registros.
  • 0

#16 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 12 febrero 2011 - 12:02

Hola,

Agag4 ¿Tienes campos persistentes? Te agradecería que nos indiques que clase de los xxxField te genera para el campo en cuestión.
Esto nos podría decir mucho de como está operando internamente Delphi.

Ten en cuenta que los Reporteadores lo que hacen es "leer" el valor que éstos Field regresan. Por tanto es muy importante saber de que clase son para determinar si el problema viene desde el lado del cliente o si es del lado de Firebird (que es poco probable).

Aviso, y les recuerdo, que el motor de Firebird lo que almacena es la mejor representación numérica de un número, de modo que a efectos de redondeo y de lecturas por los componentes de acceso a datos se lea el valor de una forma más precisa. Por ejemplo: si uno pasa el valor 1,2345643 en FB se guarda un valor ligeramente inferior (por lo general de entre 2 a 3 ulps), por decir uno: 1,2345598.
De este modo, cuando se opera y se leeen los datos se aplican los redondeos y no se ve alterado el número "original".

No es como otros motores que directamente almacenan el valor "textual" que se les ingrese, que son más propensos al doble redondeo. Como es el caso de MS SQL Server.

De eso mismo te quería hablar.  EL amigo Delphius que tiene una base matemática sólida nos puede ayudar a escoger la función mas apropiada para tu caso (aunque creo que la que escogiste es la correcta).

No te creas que es bastante sólida mi matemática  :D , se me caen los estantes bastante seguidos  :D :p

No había oido hablar de esa UDF.

Si ya estás aplicando un redondeo en la consulta, no lo vuelvas a aplicar en el cliente. ¡Estarás doble redondeando!

La regla es: si ya redondeaste, no lo vuelvas a hacer  ;)

Si nos comentas como lees los datos de esa consulta, y de que clase son los campos persistentes (aunque aviso que no conozco los FibPlus) podemos ver el meollo del asunto.

Saludos,
  • 0

#17 agag4

agag4

    Advanced Member

  • Miembros
  • PipPipPip
  • 298 mensajes
  • LocationMéxico

Escrito 12 febrero 2011 - 11:26

La forma en que leo los datos de una consulta en delphi es conectando el dataset en el Qreport y la clase de los campos son TFloatField.
  • 0

#18 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 13 febrero 2011 - 02:09

Siendo TFloatField con más razón debería funcionar y regresar un valor 0 la suma ya que este campo está diseñado para trabajar a doble precisión; más que suficiente para cualquier dato de la vida real y práctico. Y por si fuera poco, no habría que recurrir a cualquier técnica de redondeo en una etapa intermedia.

Te voy a pedir agag4 que dejes de ser tan escueto, explícate bien, aporta más información; como lees los datos, de como configuraste los fields, etc.

Es necesario que nos comentes tu caso con la mayor claridad posible. No podemos seguir sacándote las cosas a cuenta gotas... ¿Tiene algún formato establecido en DisplayFormat o EditFormat? ¿Aparte de los componentes de reportes, hay otros que estén ligados, directa o indirectamente, al dataset y a los fields correspondientes?

¿Te aseguraste de que la consulta que estás ejecutando está regresando los valores adecuados? ¿Editas, insertas o modificas algún campo en el ínterin?

¿Es una simple suma o hay algo más que no nos cuentas?

Cuando más nos puedas comentar sobre tu caso más fácil será poder ayudarte.

Recuerdo nuevamente que si la idea es trabajar con datos financieros que se utilizara el tipo adecuado a la precisión y rango para ello y a los Fields establecer la propiedad Currency en true.
Como ha dicho Eduardo, NUMERIC(15,2) que es un valor bastante habitual y lo suficientemente "grande" para aceptar valores aceptables y esperado en un entorno real, debería ofrecerte buenos resultados. Ahora bien la pregunta es ¿Para que NUMERIC(18,4)? ¿Necesitas de más?

Saludos,
  • 0

#19 agag4

agag4

    Advanced Member

  • Miembros
  • PipPipPip
  • 298 mensajes
  • LocationMéxico

Escrito 14 febrero 2011 - 09:56

Buen dia, tengo usando Numeric(16,4) desde hace casi 10años sin problemas hasta ahorita, lo uso asi porque hay clientes que me han pedido de mostrar hasta 4 decimales en los importes, el dataset que uso de los fibplus es para solo hacer consultas de alli genero la consulta para el reporte, la forma de accesar a los campos es conectando el dataset en el Qreport, no hay más, no uso DisplayFormat - EditFormat , solo formateo los importes en el evento OnPrint del QrdbText



delphi
  1. procedure TfhotGenImpreMovDiarios.QRDBText5Print(sender: TObject;
  2.   var Value: String);
  3. begin
  4.   value := FormatFloat('###,###,##0.00',StrToFloat(value));
  5. end;
  6.  



  • 0

#20 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 14 febrero 2011 - 11:44

Pues ya me quedé sin propuestas  :(
Tendría que hacer una prueba, pero para que sea exacta debería contar con los FIBPlus; y no estoy en posición de adquirirlos.

Yo utilizo 1.5.3 y D6 con los IBX podría hacer una prueba y comparar resultados.

Si me indicas más o menos la estructura de la tabla y la consulta que realizas podría comprobar los resultados.

Lo que se me ocurre es que puedes utilizar las funciones SameValue(). Básicamente la idea de esas funciones es la de comparar dos valores con un valor aceptable de error (comunmente llamado epsilon) y determinar si son iguales o no.

Puedes evaluar el resultado comparado con 0.0 y en caso de considerarlos iguales hacer que dicho valor se establezca en 0.0. Algo como:



delphi
  1. if SameValue(Valor, 0.0) //Epsilon es un parámetro opcional
  2.   then Valor := 0.0
  3.   else ShowMessage('Los valores no son iguales. Revise los datos');




Esta técnica se suele utilizar sobre todo en el área científica y cálculos de ingeniería que trabajan con márgenes de error. No será lo más adecuado pero al menos puede ofrecer una postura más flexible en cuanto al margen de error en los cálculos.

Si has estado trabajando varios años con el tipo de datos sin problemas y que ahora surjan da que pensar...

Saludos,
  • 0




IP.Board spam blocked by CleanTalk.