select POWER(2.,64.)
retorna em 18446744073709552000
vez de 18446744073709551616
. Parece ter apenas 16 dígitos de precisão (arredondando o dia 17).
Mesmo explicitando a precisão, select power(cast(2 as numeric(38,0)),cast(64 as numeric(38,0)))
ele ainda retorna o resultado arredondado.
Isso parece ser uma operação bastante básica para que ele seja exibido arbitrariamente com 16 dígitos de precisão como este. O valor mais alto que ele pode calcular corretamente é apenas o que POWER(2.,56.)
falhar POWER(2.,57.)
. O que está acontecendo aqui?
O que é realmente terrível é que 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.;
realmente retorna o valor certo. Tanta coisa para a concisão.
fonte
Respostas:
Na documentação online :
A implicação é que tudo o que você passar como o primeiro parâmetro será implicitamente convertido em a
float(53)
antes que a função seja executada. No entanto, este não é (sempre?) O caso .Se fosse o caso, explicaria a perda de precisão:
Por outro lado, o literal
2.
é do tiponumeric
…:dbfiddle aqui
… E o operador multiply retorna o tipo de dados do argumento com maior precedência .
Parece que em 2016 (SP1), toda a precisão é mantida:
dbfiddle aqui
… Mas em 2014 (SP2), eles não são:
dbfiddle aqui
fonte
POWER(2.,56.) = 72057594037927936
mas não superior. Eu acho que vou ter que escrever minha própria função POWER que se multiplica em um loop, lol.O resultado de 2 64 é exatamente representável em
float
(e,real
nesse caso).O problema surge quando esse resultado preciso é convertido novamente em
numeric
(o tipo do primeiroPOWER
operando).Antes da introdução do nível 130 de compatibilidade de banco de dados, o SQL Server arredondado
float
paranumeric
conversões implícitas para um máximo de 17 dígitos.No nível de compatibilidade 130, o máximo de precisão possível é preservado durante a conversão. Isso está documentado no artigo da Base de Dados de Conhecimento:
Melhorias no SQL Server 2016 no tratamento de alguns tipos de dados e operações incomuns
Para tirar proveito disso no Banco de Dados SQL do Azure, você precisa definir o valor
COMPATIBILITY_LEVEL
130:O teste de carga de trabalho é necessário porque o novo arranjo não é uma panacéia. Por exemplo:
... deve gerar um erro porque 10 38 não pode ser armazenado em
numeric
(precisão máxima de 38). Um erro de estouro resulta em compatibilidade com 120, mas o resultado em 130 é:fonte
Com um pouco de matemática, podemos encontrar uma solução alternativa. Para impar
n
:Para pares
n
:Uma maneira de escrever isso em T-SQL:
Testado no SQL Server 2008, o resultado é 144115188075855872 em vez de 144115188075855870.
Isso funciona até um expoente de 113. Parece que um NUMÉRICO (38,0) pode armazenar até 2 ^ 126, portanto não há uma cobertura completa, mas a fórmula pode ser dividida em mais partes, se necessário .
fonte
Apenas por diversão, uma solução CTE recursiva:
fonte