select POWER(2.,64.)
mengembalikan 18446744073709552000
bukan 18446744073709551616
. Tampaknya hanya memiliki 16 digit presisi (pembulatan ke-17).
Bahkan dengan membuat presisi eksplisit, select power(cast(2 as numeric(38,0)),cast(64 as numeric(38,0)))
ia tetap mengembalikan hasil yang bulat.
Sepertinya ini adalah operasi yang cukup mendasar untuk bisa keluar sembarangan dengan 16 digit presisi seperti ini. Yang tertinggi yang dapat dihitung dengan benar hanya POWER(2.,56.)
, gagal untuk POWER(2.,57.)
. Apa yang terjadi disini?
Yang benar-benar mengerikan adalah bahwa 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.;
sebenarnya mengembalikan nilai yang benar. Begitu banyak untuk kesederhanaan.
sumber
Jawaban:
Dari dokumentasi online :
Implikasinya adalah bahwa apa pun yang Anda lewati sebagai parameter pertama akan secara implisit dilemparkan ke
float(53)
sebelum fungsi dijalankan. Namun, ini bukan (selalu?) Kasusnya .Jika itu masalahnya, itu akan menjelaskan hilangnya presisi:
Di sisi lain, literalnya
2.
adalah tipenumeric
...:Aku di sini
... dan operator multiply mengembalikan tipe data dari argumen dengan prioritas yang lebih tinggi .
Tampaknya pada 2016 (SP1), semua presisi dipertahankan:
Aku di sini
... tetapi pada 2014 (SP2), mereka bukan:
Aku di sini
sumber
POWER(2.,56.) = 72057594037927936
tetapi tidak lebih tinggi. Saya kira saya harus menulis fungsi POWER saya sendiri yang hanya berlipat ganda dalam satu lingkaran, lol.Hasil dari 2 64 tepat diwakili dalam
float
(danreal
dalam hal ini).Masalah muncul ketika hasil yang tepat ini dikonversi kembali ke
numeric
(jenisPOWER
operan pertama ).Sebelum tingkat kompatibilitas database 130 diperkenalkan, SQL Server dibulatkan
float
menjadinumeric
konversi implisit hingga maksimum 17 digit.Di bawah tingkat kompatibilitas 130, sebanyak mungkin presisi dipertahankan selama konversi. Ini didokumentasikan dalam artikel Pangkalan Pengetahuan:
SQL Server 2016 peningkatan dalam menangani beberapa tipe data dan operasi yang tidak umum
Untuk memanfaatkan ini di Azure SQL Database, Anda perlu mengatur
COMPATIBILITY_LEVEL
ke 130:Pengujian beban kerja diperlukan karena pengaturan baru bukanlah obat mujarab. Sebagai contoh:
... harus melempar kesalahan karena 10 38 tidak dapat disimpan
numeric
(presisi maksimum 38). Kesalahan overflow menghasilkan di bawah 120 kompatibilitas, tetapi hasil di bawah 130 adalah:sumber
Dengan sedikit matematika kita dapat menemukan solusinya. Untuk aneh
n
:Bahkan untuk
n
:Salah satu cara untuk menulis itu di T-SQL:
Diuji pada SQL Server 2008, hasilnya adalah 144115188075855872 bukannya 144115188075855870.
Ini berfungsi sampai eksponen 113. Sepertinya NUMERIC (38,0) dapat menyimpan hingga 2 ^ 126 sehingga tidak ada cakupan yang cukup penuh, tetapi rumus dapat dibagi menjadi beberapa bagian jika perlu .
sumber
Hanya untuk bersenang-senang, solusi CTE rekursif:
sumber