select POWER(2.,64.)vuelve en 18446744073709552000lugar de 18446744073709551616. Parece tener solo 16 dígitos de precisión (redondeando el 17).
Incluso haciendo explícita la precisión select power(cast(2 as numeric(38,0)),cast(64 as numeric(38,0))), aún devuelve el resultado redondeado.
Esto parece una operación bastante básica para que se descarte arbitrariamente a 16 dígitos de precisión como esta. Lo más alto que puede calcular correctamente es solo POWER(2.,56.), fallando POWER(2.,57.). ¿Que esta pasando aqui?
Lo que es realmente terrible es que en select 2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.;realidad devuelve el valor correcto. Demasiado para la brevedad.
fuente

Respuestas:
De la documentación en línea :
La implicación es que lo que pase como primer parámetro se convertirá implícitamente en a
float(53)antes de que se ejecute la función. Sin embargo, este no es (¿siempre?) El caso .Si fuera el caso, explicaría la pérdida de precisión:
Por otro lado, el literal
2.es tiponumeric...:dbfiddle aquí
... y el operador de multiplicación devuelve el tipo de datos del argumento con mayor precedencia .
Parece que en 2016 (SP1), se conserva toda la precisión:
dbfiddle aquí
... pero en 2014 (SP2), no son:
dbfiddle aquí
fuente
POWER(2.,56.) = 72057594037927936pero no superior. Supongo que tendré que escribir mi propia función POWER que simplemente se multiplica en un bucle, jajaja.El resultado de 2 64 es exactamente representable en
float(yrealpara el caso).El problema surge cuando este resultado preciso se convierte de nuevo a
numeric(el tipo del primerPOWERoperando).Antes de que se introdujera el nivel de compatibilidad de la base de datos 130, SQL Server redondeó
floatanumericconversiones implícitas a un máximo de 17 dígitos.Bajo el nivel de compatibilidad 130, se conserva la mayor precisión posible durante la conversión. Esto está documentado en el artículo de Knowledge Base:
Mejoras de SQL Server 2016 en el manejo de algunos tipos de datos y operaciones poco comunes
Para aprovechar esto en Azure SQL Database, debe establecer
COMPATIBILITY_LEVEL130 en:La prueba de carga de trabajo es necesaria porque el nuevo arreglo no es una panacea. Por ejemplo:
... debería arrojar un error porque no se puede almacenar 10 38
numeric(precisión máxima de 38). Un error de desbordamiento da como resultado una compatibilidad inferior a 120, pero el resultado por debajo de 130 es:fuente
Con un poco de matemática podemos encontrar una solución. Por impar
n:Para incluso
n:Una forma de escribir eso en T-SQL:
Probado en SQL Server 2008, el resultado es 144115188075855872 en lugar de 144115188075855870.
Esto funciona hasta un exponente de 113. Parece que un NUMÉRICO (38,0) puede almacenar hasta 2 ^ 126, por lo que no hay una cobertura completa, pero la fórmula podría dividirse en más partes si es necesario .
fuente
Solo por diversión, una solución recursiva de CTE:
fuente