Resposta do wiki da comunidade :
Você pode se decepcionar com os resultados no SQL Server em comparação com o PostgreSQL (que é capaz de lidar com números muito grandes, como 30000! Sem perda de precisão).
Em SQL Server 33!
é tão alto quanto você pode ir com precisão exata enquanto 170!
é tão alto quanto você pode ir a todos ( 171!
é1.24E309
o que ultrapassa os limites da float
).
Então você pode pré-calculá-los e armazená-los em uma tabela com valores 0 ... 170
. Isso cabe em uma única página de dados se a compactação for usada.
CREATE TABLE dbo.Factorials
(
N TINYINT PRIMARY KEY WITH (DATA_COMPRESSION = ROW),
FactorialExact NUMERIC(38, 0) NULL,
FactorialApprox FLOAT NOT NULL
);
WITH R(N, FactorialExact, FactorialApprox)
AS (SELECT 0,
CAST(1 AS NUMERIC(38, 0)),
1E0
UNION ALL
SELECT R.N + 1,
CASE WHEN R.N < 33 THEN ( R.N + 1 ) * R.FactorialExact END,
CASE WHEN R.N < 170 THEN ( R.N + 1 ) * R.FactorialApprox END
FROM R
WHERE R.N < 170)
INSERT INTO dbo.Factorials
(N,
FactorialExact,
FactorialApprox)
SELECT N,
FactorialExact,
FactorialApprox
FROM R
OPTION (MAXRECURSION 170);
Alternativamente, o seguinte irá dar resultados precisos para @N até 10 - e aproximado para 11+ (seria mais preciso se as várias funções / constantes ( PI()
, EXP()
, POWER()
) trabalhou com DECIMAL
tipos, mas eles trabalham com FLOAT
apenas):
DECLARE @N integer = 10;
SELECT
CONVERT
(
DECIMAL(38,0),
SQRT(2 * PI() * @N) *
POWER(@N/EXP(1), @N) *
EXP(1.0/12.0/@N + 1.0/360.0/POWER(@N, 3))
);