En el foro preguntaron:

¿Por qué esta consulta:

Listado 1.

SELECT
   192.76110000000000 / 2.2200
FROM
   RDB$DATABASE

muestra el error: -802 Arithmetic overflow or division by zero has occurred.?

El problema, tal y como se explicó en el artículo Usando NUMERIC y DECIMAL es debido a la forma en que el Firebird define a los números escalados (también llamados de coma fija o de punto fijo; son sinónimos).

En Firebird los números escalados tienen el formato:

p.s

donde p indica la precisión y s indica la escala (s=scale, en inglés).

La precisión máxima en Firebird, hasta la versión 2.5.4 es de 18. La escala siempre debe ser menor o igual a la precisión, nunca puede ser mayor.

¿Cuál es la precisión del resultado cuándo se hace una división?

Siempre es 18.

¿Cuál es la escala del resultado cuándo se hace una división?

Siempre es la suma de la escala del numerador más la escala del denominador.

¿Cuál fue el problema en la división que dio origen a este artículo?

Que el numerador (192.76110000000000) tiene una escala de 14 y el denominador (2.2200) tiene una escala de 4. El resultado de la división por lo tanto tendrá una escala de 18 (es decir, 14 + 4). Ya está en el límite máximo permitido.

La división anterior sí funcionará si la parte entera del numerador es pequeña, por ejemplo:

Listado 2.

SELECT
   19.76110000000000 / 2.2200
FROM
   RDB$DATABASE

La parte entera del numerador es 19 y allí sí funciona.

¿Por qué funciona cuándo el numerador es pequeño?

Si la precisión es 18 entonces el número se guarda como un BIGINT. Los números de tipo BIGINT pueden encontrarse entre -2 * 10 ^ 63 y 2 * 10 ^ 63 – 1. O sea, entre -9.223.372.036.854.775.808 y +9.223.372.036.854.775.807

Si la escala es 18 entonces el Firebird divide a ese número por 1.000.000.000.000.000.000 o sea un 1 seguido por 18 ceros.

Al dividir 9.223.372.036.854.775.807 por 1.000.000.000.000.000.000 obtenemos: 9,223372036854775807

Por lo tanto, si la precisión es 18 y la escala es 18 (como en el Listado 1.) el resultado de la división debe ser 9,22 ó menor para no obtener un error de overflow.

Pero en el Listado 1. el resultado de la división es 86,829321…., ese número es mayor que 9,22 y entonces lo que se obtiene es un … error de overflow.

¿Y si necesitamos hacer sí o sí la división del Listado 1., cómo lo solucionamos?

Tenemos varias alternativas:

Listado 3.

SELECT
   192.7611 / 2.2200
FROM
   RDB$DATABASE

Le quitamos los ceros al numerador y funciona sin problemas porque ahora la escala es de 8.

Listado 4.

SELECT
   192.76110000000000 / 2.22
FROM
   RDB$DATABASE

Le quitamos los ceros al denominador y funciona sin problemas porque ahora la escala es de 16.

Listado 5.

SELECT
   CAST(192.76110000000000 AS NUMERIC(18, 13)) / 2.2200
FROM
   RDB$DATABASE

Empleamos la función CAST() para disminuir la escala del numerador y funcionó sin problemas.

Listado 6.

SELECT
   CAST(192.761100000000000 AS FLOAT) / 2.2200
FROM
   RDB$DATABASE

Empleamos la función CAST() para cambiar el tipo de datos del numerador a FLOAT y funcionó sin problemas.

Conclusión:

Tal y como se dijo en el artículo antes citado: “La precisión del resultado siempre es 18. La escala del resultado es la suma de las escalas del dividendo y del divisor. Esto implica que la escala del cociente siempre será mayor que las del dividendo y del divisor. Debes tener cuidado con esto si los números que empleas tienen muchos decimales o podrías sobrepasar la escala máxima que es 18 o necesitar una precisión mayor que 18 y en ambos casos eso te ocasionaría un error de overflow.”

Lo importante a recordar aquí por lo tanto es que si divides números que tienen muchos decimales puedes sobrepasar la escala máxima de 18 o necesitar una precisión mayor que 18 y en ambos casos tendrás un error de overflow.

Hay varios métodos para realizar la división de todos modos, algunos de los cuales vimos en los últimos listados de arriba (hay varios más, pero ya tienes la idea).

Artículos relacionados:

Usando NUMERIC y DECIMAL

El índice del blog Firebird21

El foro del blog Firebird21