Ir al contenido


Foto

Sumas Raras en un select


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

#21 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.448 mensajes
  • LocationMéxico

Escrito 14 febrero 2011 - 11:52

Una pregunta, esos  valores (-0.10, -0.10, -0.10, 0.50, -0.10, -0.10)

¿ Son capturados o es el resultado de una operación ?

Salud OS
  • 0

#22 agag4

agag4

    Advanced Member

  • Miembros
  • PipPipPip
  • 298 mensajes
  • LocationMéxico

Escrito 14 febrero 2011 - 12:07

Es el resultado de una operación de un trigger.
  • 0

#23 agag4

agag4

    Advanced Member

  • Miembros
  • PipPipPip
  • 298 mensajes
  • LocationMéxico

Escrito 14 febrero 2011 - 12:12

Adjunto archivo con las sentencias SQL para crear la tabla, 4 registros, etc. etc.
  • 0

#24 Sergio

Sergio

    Advanced Member

  • Moderadores
  • PipPipPip
  • 1.092 mensajes
  • LocationMurcia, España

Escrito 15 febrero 2011 - 03:10

Yo he tenido caso similares, y al final, todo estaba en pensarse muy bien si cada linea del sumatorio es una cantidad de por si, tiene que estar claro si se ha de redondear o no, y hacerlo en origen, de forma que cualquier query que las lea y sume de simepre lo mismo.

Por ejemplo, si tienes facturas cada una con 10 lineas, y cada linea tiene precio x unidades, ambas con 2 decimales, puesto que al imprimir la factura precio x unidades = importe de la linea se da con 2, hay que redondear cada importe de linea ANTES de sumarlo (mejor desde la base de datos) y obtener la base de la factura. Si redondeas la base solo, pierdes o ganas hasta 1 centimo por linea, asi que puedes terminar con +/- 10 centimos.

Si ahorta vas a obtener el IVA como base * 0.18 de nuevo esta cantidad toca redondearla ANTES de sumarla a la base y obtener el total.

Si finalmente vas a sumar toda la facturacion, has de obtener el total de cada fac tura con el metodo anterior, no vale redondear las cosas en otro orden ni nada similar, asi que nosotros usamos unos procedures que nos dan la base, iva y total de una factura y dentor se hace todo este redondeo, y delphi siempre ve las cantidades correctas.

nota: Los euros, por norma, se redondean al laza en el caso de medio centimo, ojo a esto.
  • 0

#25 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 15 febrero 2011 - 12:22

Hola,

O sino la última que queda es olvidarnos de la aritmética de punto flotante y cambiar al esquema hacia una aritmética entera ya que esta SI ES EXACTA y no tiene pérdida alguna de precisión.

El "truco" pasa por algo muy simple... no se guarda ningún real, todo se opera con números enteros. Se establece una cantidad fija N de decimales y se destina los últimos N dígitos para representarlos.

Por ejemplo: digamos que N = 3 y tenemos el valor $4781,625. Esto se almacena como: 4781625. Es decir que si por ejemplo queremos guardar 0,789 entonces se transforma en 789.

Como la aritmética es la misma, el resultado seguirá siendo el mismo (y exacto a la cantidad de decimales  ;) ) por lo que de lo único que nos tenemos que preocupar es la darle formato al presentar el dato.

Naturalmente este esquema toca de lleno la forma en como se hacen los cálculos en el sistema y en la estructura de la base de datos para cambiar todo a nivel de enteros.

Este "truco" en muchos lugares es una OBLIGACION, y está definido por LEY. Los programas administrativos y de gestión (generalmente, los que tienen algun vínculo con el fisco) son obligados a emplear esta técnica a fin de evitar justamente estos tipos de problemas de redondeo y de pérdidas o excesos de decimales y las cuentas no cierran.

Por cierto, esta técnica en buena parte es utilizada por un tipo especial que ya he mencionado: el Currency. Este tipo es un tipo ENTERO... no no es un real, Delphi nos lo hace creer que lo es pero lo cierto es que es un entero y destina los últimos 4 dígitos para almacenar los decimales. De ese modo de forma automáticamente cuando realiza alguna operación multiplica o divide (según sea el caso) el número por 10000 para conseguir los "desplazamientos" de la coma.  ;)

Saludos,
  • 0

#26 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 15 febrero 2011 - 03:13

Parece que no se entendió mi idea, o no les resulta de agrado  :( :

Nadie comentó algo.  :(

Saludos,
  • 0

#27 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.448 mensajes
  • LocationMéxico

Escrito 15 febrero 2011 - 04:53

Parece que no se entendió mi idea, o no les resulta de agrado  :( :

Nadie comentó algo.  :(

Saludos,


Francamente desconocia la obligatoriedad de esa técnica, me parece que es un tema muy interesante.

Salud OS
  • 0

#28 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 15 febrero 2011 - 05:17

Francamente desconocia la obligatoriedad de esa técnica, me parece que es un tema muy interesante.

Salud OS

Por algo yo decía que en algunos lugares, se les obliga (en realidad la ley fiscal lo estipula) a que sus sistemas contables y administrativos trabajan con la aritemética entera y no con la flotante para evitar estos inconvenientes del redondeo y el de perder (o hasta ganar) centavos.
Esto de la aritemética flotante es uno de los principales causantes de que en algunos sistemas contables los balances no den "suma-cero"  ;) .

En mi país creo recordar no hay mucha presión sobre esto (no al menos como ley en el plano técnico), pero creo que en España si tienen una ley similar a lo que describo.

Saludos,
  • 0

#29 eduarcol

eduarcol

    Advanced Member

  • Administrador
  • 4.483 mensajes
  • LocationVenezuela

Escrito 17 febrero 2011 - 06:56

y que pasaria con los limites de los enteros? al utilizar este truco con tres decimales cual seria el maximo numero que se puede guardar

2.147.483,647

Fijate que no es un numero tan grande si hablamos de montos en ciertos paises.
  • 0

#30 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 17 febrero 2011 - 07:18

y que pasaria con los limites de los enteros? al utilizar este truco con tres decimales cual seria el maximo numero que se puede guardar

2.147.483,647

Fijate que no es un numero tan grande si hablamos de montos en ciertos paises.

Naturalmente Eduardo que el sistema tienes sus contras, y como indicas: tenemos un límite.

Pero fíjate de que esto se puede solventar si consideramos el tipo Int64 y, además, firebird cuenta con el tipo BIGINT que es su equivalente.

Creería que este este tipo es lo suficientemente grande como para contentarte  ;)

Ha, y si se preguntan que se está desperdiciando tamaño por los de los 64 bits entonces yo digo que también lo hacen con cualquier tipo double... que casualmente ocupa lo mismo. El tipo BIGINT es mucho más rápido que el tipo flotante de igual tamaño.

Saludos,
  • 0

#31 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 17 febrero 2011 - 07:28

O la otra posibilidad, que he visto no se en donde (mi cabeza me está fallando demasiado ultimamente), es la descomponer el número en dos campos: PARTE_ENTERA y PARTE_DECIMAL.

Se dispone de un tipo ENTERO lo suficientemente grande para satisfacer las necesidades para PARTE_ENTERA y para PARTE_DECIMAL se destina el tipo entero más chico y que cumpla con los requisitos.

Desde luego que esto requiere de nuevas técnicas matemáticas, pero son otra posibilidad más a considerar.

Recuerden que para la máquina realizar operaciones matemáticas enteras es una tarea tan trivial que el multiplicar y dividir por 10, 100, 1000, etc es poca cosa.

Saludos,
  • 0

#32 eduarcol

eduarcol

    Advanced Member

  • Administrador
  • 4.483 mensajes
  • LocationVenezuela

Escrito 17 febrero 2011 - 07:36

BIGINT data type

Added in: 1.5

Description: BIGINT is the SQL99-compliant 64-bit signed integer type. It is available in Dialect 3 only.

BIGINT numbers range from -263 .. 263-1, or -9,223,372,036,854,775,808 .. 9,223,372,036,854,775,807.


Esto nos dejaria trabajar con

9.223.372.036.854.775,807


Creo que ahora si,  :D
  • 0

#33 Sergio

Sergio

    Advanced Member

  • Moderadores
  • PipPipPip
  • 1.092 mensajes
  • LocationMurcia, España

Escrito 18 febrero 2011 - 03:57

Delphius, en FireBird, un Numeric(10,2) ES INTERNAMENTE UN ENTERO y no tiene los problemas de los float, internamente se hacen las cosas como tu comentas, con enteros, y al final, se pone la comita donde toca, y ese es el resultado que ves, es decir, que en un Numeric(10,2) esta igualdad se da siempre:

1/3=0.33

Cosa que como sabeis, no ocurriria en un tipo float "a pelo".

NOTA: Este hecho lo aprendi en unas conferencias de FireBird en Praga, donde una charla de uno de los programadores -creo recordar- fue sobre estos casos de matematicas confusas con decimales, pero en la documentacion de FireBird, por mas que he buscado para documentar este post, no aparece, ya que todo lo que existen son "languaje updates" donde se menciona solo "lo nuevo", y Numeric existe desde "siempre". En la documentacion original de Interbase 6, bastante mas cuidada que la que existe en FireBird, es donde se definen estos numeric, y dice "Example: NUMERIC(10,3) holds numbers accurately in the following format: ppppppp.sss". No lo dice tan claro como deberia, pero ES un entero internamente, palabrita del niño Jesus!

Mas info en el PDF de "Languaje reference" de Interbase 6 http://www.ibphoenix...s/60LangRef.zip y la pagina donde lo encontre http://www.firebirds...=doc#category_9 (Buscar por Interbase 6, Languaje reference, y teneis el link primero al PDF).

El problema ha de estar en otro sitio, por ejemplo se me ocurren dos:

1) En algun calculo intermedio se usan float en lugar de Numeric(10,2), con lo que ocurreen errores de redondeo que, una vez sumados y copiados a un Numeric(5,2), te cambian el ultimo de los decimales.

2) Como se estan usando Numeric(10,4) pero supongo que una vez sumado todo se da con 2 decimales, se estan desechando los 2 decimales ultimos, cosa que puede hacer que falle la suma por la misma razón que el punto 1:

Ejemplo: Tienes que sumar la cantidad con 4 decimales 2.0010 x 8 veces, eso te da un total de 16.0080, que al pasarlo a dos decimales te da 16.01, que NO es igual a 2.0010 x 8.

Mi consejo: Si las cantidades a sumar pueden tener 4 decimales, usa 4 decimales en TODO, incluido el total de la suma, o redondealas a 2 decimales en origen (cada numero a sumar se redondea antes de ser sumado, y no al final).

Esto no te quita el problema de "unidades x precio = total": en mi caso, las facturas de mi aplicacion tienen lineas donde en las unidades permitimos 2 decimales, y en el precio igual, con lo que el total de cada linea se calcula con 4 decimales, pero una vez calculado, se redondea a 2 decimales y esa es la cantidad que mostramos al imprimir y que sumamos luego (es importantismo que las dos cosas coincidan internamente y externamente), con lo que ese "error" no se acumula si no que se "tira lo que sobra" al calcular el total de cada linea que se va a sumar, con lo que la suma no tiene nunca decimales sobrantes que se eliminen.

Es un tema delicado el donde se deben de hacer los redondeos en el proceso, interesa hacerse un esquema y aplicarlo en todos los procedures que sumen, sena de delphi o sean por base de datos, o si no siempre se pierden o ganan decimales de vez en cuando.
  • 0

#34 Sergio

Sergio

    Advanced Member

  • Moderadores
  • PipPipPip
  • 1.092 mensajes
  • LocationMurcia, España

Escrito 18 febrero 2011 - 06:06

Encontre este antiguo manual sobre Interbase 4 http://www.ibphoenix.../general/doc_62 dan la explicacion EXACTA a este problema de las cantidades en float (nota: en esos dias no existian los bigint ni similares en InterBase, pero hoy dia claro que si):

The simplest solution for a lazy mind, like mine (and others, no doubt) would be to work exclusively in pennies (ignoring fractions of course), storing the data as integers and scaling the displayed values to two places to show the major currency unit. Unfortunately, in InterBase, integers are only 32-bit, so using this solution is not practical if large sums are involved, or if one is working in a hyper-inflated currency. If your application will never deal with aggregated sums of more than £21,474,836.48, then integers are a safe bet for currency storage. InterBase Software Corp has been lobbied intensively to introduce a 64-bit INTEGER and have promised that it will be introduced with a bug-fix release of version 5 sometime in the coming year. It will not be in v5.0, but its need is acknowledged and will be be addressed.

Editors Note

64-bit INTEGER is now available in InterBase 6.0

So, for larger sums or fractions of a penny, what is one to do? On perusal of the manual the solution appears to lie in the NUMERIC or DECIMAL data type, but further reading does not really help one to distinguish between the two. Neither does it satisfactorily explain the effect of the two parameters that one can use, unless you read very closely.

To summarise the manual:

    * Precision means the total number of digits stored - inclusive of both sides of the decimal point.
    * Scale is the number of those digits that are to the right of the decimal point.
    * Numeric means that the largest value stored is dictated by (precision-scale).
    * Decimal means that numbers with larger than precision-scale will be stored; decimal specifies at least in contrast to numerics' the most.

If you are still confused, read the several pages of explanation in the manual and then come back to the above summary.

Having cleared up the semantics of these datatypes, which should one use? The convention amongst developers appears to favour NUMERIC over DECIMAL and I cannot comment further on that. The next step is to choose an appropriate precision and scale. To achieve an effect similar to our maximum integer above and still store the data in an integer datatype (thus not requiring any further conversion) one would use NUMERIC(9,3) giving a maximum of £999,999.999. Not quite enough for anything larger than a very small business. To store values up to £999,999,999.999 requires NUMERIC(12,3). Enough for me but perhaps not enough for roubles or lira though. If you use NUMERIC(15,4) you get values up to £99,999,999,999.9999 (ie 99 billion) That should do the trick for most people, combining size with the ability to handle calculations down to a hundredth of a penny.
  • 0

#35 Marc

Marc

    Advanced Member

  • Moderadores
  • PipPipPip
  • 1.484 mensajes
  • LocationMallorca

Escrito 18 febrero 2011 - 07:31

Hola Sergio.

Creo que has confundido el hilo para esta respuesta :) (no veo que relación tiene con lo anterior).
  • 0

#36 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 18 febrero 2011 - 08:30

Ye he movido el post a su hilo que corresponde  ;)

Sergio, me dejas en blanco. No he leído aún el enlace que comentas sobre el tema de NUMERIC(10,2) es un entero. Es posible que sea un caso particular como el de BIGINT = NUMERIC(18,0).

Creo que la explicación lógica es que como el tipo entero es de 32 bits, y en éste es posible almacenar un máximo de 10 dígitos (2^32 = 4294967296)... y en vista a que NUMERIC(10,2) es un número flotante con formato pppppppp.ss a fin de obtener una cifra exacta lo "mapea" al formato entero.

Coincido contigo que en algún lado hay algún traspié que hace que los cálculos no se mantengan... o se están recortando los decimales, o se hacen mezclas de tipos...

Respecto a lo que dices que el tipo NUMERIC(P,S) consiste en un número flotante cuyo formato es:

p1p2...pp-s.s(p-s)+1s(p-2)+2...Sp

Me es sabido. Ahora bien, por lo que tengo entendido Agag4 está utilizando NUMERIC(16,4) y su tipo Field que genera es TFloatField lo que le permitiría, según la ayuda, almacenar cualquier número flotante de doble precisión y de ser así entonces internamente todo se traduciría a Double.

Y como ya dije antes... Double es lo suficientemente preciso para cualquier operación terrenal, de ingeniería y hasta para algunas operaciones científicas... no debería haber un problema al utilizarlo.
De hecho, si uno hace en un Double esto:



delphi
  1. var d: Double;
  2. begin
  3. d := 0.0;
  4. end;



Y mostrase su valor, recibirá exactamente eso: 0.00....

Bueno, si uno se pone bien quisquilloso y se pone a jugar con las excepciones de la FPU debería ser cuidadoso... el cero es un número especial.  ;)

En vista a que agag4 comentó que trabajan tanto a 2 como a 4 decimales tiendo a pensar que a lo mejor en sus cálculos internamente está perdiendo precisión.

Ya he dicho yo: las mezclas no son buenas.

Saludos,
  • 0

#37 Sergio

Sergio

    Advanced Member

  • Moderadores
  • PipPipPip
  • 1.092 mensajes
  • LocationMurcia, España

Escrito 23 febrero 2011 - 10:06

Internamente, en FireBird, un Numeric(10,4) es un entero y se almacena como tal, ese es "el dato" que aportaba a la discusión, aunque claro, al recibirlo en tu aplicacion te lo convierte a double, pero si un procedure de tu BD suma un monton de numeric(10,4), la suma es entera y no "pierde decimales" ni nada similar.


  • 0




IP.Board spam blocked by CleanTalk.