Masalah:
Anda ingin mencari sisa (non-negatif).
Contoh:
Dalam tabel numbers , Anda memiliki dua kolom bilangan bulat:a dan b .
| a | b |
|---|---|
| 9 | 3 |
| 5 | 3 |
| 2 | 3 |
| 0 | 3 |
| -2 | 3 |
| -5 | 3 |
| -9 | 3 |
| 5 | -3 |
| -5 | -3 |
| 5 | 0 |
| 0 | 0 |
Anda ingin menghitung sisa dari pembagian a oleh b . Setiap sisa harus berupa nilai bilangan bulat non-negatif yang lebih kecil dari b .
Solusi 1 (tidak sepenuhnya benar):
SELECT a, b, a % b AS remainder FROM numbers;
Hasilnya adalah:
| a | b | sisa |
|---|---|---|
| 9 | 3 | 0 |
| 5 | 3 | 2 |
| 2 | 3 | 2 |
| 0 | 3 | 0 |
| -2 | 3 | -2 |
| -5 | 3 | -2 |
| -9 | 3 | 0 |
| 5 | -3 | 2 |
| -5 | -3 | -2 |
| 5 | 0 | kesalahan |
| 0 | 0 | kesalahan |
Diskusi:
Solusi ini bekerja dengan benar jika a adalah non-negatif. Namun, jika negatif, tidak mengikuti definisi matematika dari sisanya.
Secara konseptual, sisa adalah apa yang tersisa setelah pembagian bilangan bulat a oleh b . Secara matematis, sisa dua bilangan bulat adalah bilangan bulat tak negatif yang lebih kecil dari pembagi b . Lebih tepatnya, ini adalah bilangan r∈{0,1,...,b - 1} yang memiliki beberapa bilangan bulat k sehingga a =k * b + r.
Beginilah cara a % b bekerja untuk dividen non-negatif di kolom a :
5 = 1 * 3 + 2 , jadi sisa 5 dan 3 sama dengan 2 .
9 = 3 * 3 + 0 , jadi sisa 9 dan 3 sama dengan 0 .
5 = (-1) * (-3) + 2 , jadi sisa 5 dan -3 sama dengan 2 .
Jelas, kesalahan ditampilkan jika pembagi b adalah 0 , karena Anda tidak dapat membagi dengan 0 .
Mendapatkan sisa yang benar bermasalah ketika dividen a adalah bilangan negatif. Sayangnya, a % b dapat mengembalikan nilai negatif ketika a adalah negatif. Mis.:
-2 % 5 mengembalikan -2 kapan seharusnya mengembalikan 3 .
-5 % -3 mengembalikan -2 kapan seharusnya mengembalikan 1 .
Solusi 2 (benar untuk semua angka):
SELECT
a,
b,
CASE WHEN a % b >= 0
THEN a % b
ELSE
a % b + ABS(b)
END AS remainder
FROM numbers;
Hasilnya adalah:
| a | b | sisa |
|---|---|---|
| 9 | 3 | 0 |
| 5 | 3 | 2 |
| 2 | 3 | 2 |
| 0 | 3 | 0 |
| -2 | 3 | 1 |
| -5 | 3 | 1 |
| -9 | 3 | 0 |
| 5 | -3 | 2 |
| -5 | -3 | 1 |
| 5 | 0 | kesalahan |
| 0 | 0 | kesalahan |
Diskusi:
Untuk menghitung sisa pembagian apa saja dua bilangan bulat (negatif atau non-negatif), Anda dapat menggunakan CASE WHEN konstruksi. Jika a % b non-negatif, sisanya hanya a % b . Jika tidak, kita perlu memperbaiki hasil yang dikembalikan oleh a % b .
Jika a % b mengembalikan nilai negatif, Anda harus menambahkan nilai absolut pembagi ke a % b . Yaitu, buat a % b + ABS(b) :
-2 % 5 mengembalikan -2 kapan seharusnya mengembalikan 3 . Anda dapat memperbaikinya dengan menambahkan 5 .
-5 % (-3) mengembalikan -2 kapan seharusnya mengembalikan 1 . Anda dapat memperbaikinya dengan menambahkan 3 .
Ketika a % b mengembalikan nilai negatif, CASE WHEN hasilnya harus a % b + ABS(b) . Ini adalah bagaimana Anda mendapatkan Solusi 2. Jika Anda membutuhkan penyegaran tentang bagaimana ABS() berfungsi, lihat buku masak Cara menghitung nilai absolut dalam SQL.
Tentu saja, jika b = 0 , Anda masih akan mendapatkan kesalahan.
Solusi 3 (benar untuk semua angka):
SELECT a, b, a % b + ABS(b) * (1 - SIGN(a % b + 0.5)) / 2 AS remainder FROM numbers;
Hasilnya adalah:
| a | b | sisa |
|---|---|---|
| 9 | 3 | 0 |
| 5 | 3 | 2 |
| 2 | 3 | 2 |
| 0 | 3 | 0 |
| -2 | 3 | 1 |
| -5 | 3 | 1 |
| -9 | 3 | 0 |
| 5 | -3 | 2 |
| -5 | -3 | 1 |
| 5 | 0 | kesalahan |
| 0 | 0 | kesalahan |
Diskusi:
Ada cara lain untuk mengatasi masalah ini. Alih-alih CASE WHEN , gunakan rumus matematika satu baris yang lebih kompleks:
a % b + ABS(b) * (1 - SIGN(a % b + 0.5)) / 2
Dalam Solusi 2, a % b + ABS(b) dikembalikan untuk kasus ketika a % b < 0 . Perhatikan bahwa a % b + ABS(b) = a % b + ABS(b) * 1 when a % b < 0 .
Jadi, kita dapat mengalikan ABS(b) dengan ekspresi yang sama dengan 1 untuk nilai negatif a % b dan 0 untuk nilai non-negatif a % b . Sejak a % b selalu bilangan bulat, ekspresi a % b + 0.5 selalu positif untuk a % b >= 0 dan negatif untuk a % b < 0 . Anda dapat menggunakan bilangan positif apa pun yang kurang dari 1 bukannya 0.5 .
Fungsi tanda SIGN() mengembalikan 1 jika argumennya benar-benar positif, -1 jika benar-benar negatif, dan 0 jika sama dengan 0 . Namun, Anda memerlukan sesuatu yang hanya mengembalikan 0 dan 1 , bukan 1 dan -1 . Tapi jangan khawatir! Inilah cara Anda memperbaikinya:
(1 - 1) / 2 = 0
(1 - (-1)) / 2 = 1
Kemudian, ekspresi yang benar untuk mengalikan ABS(b) adalah:
(1 - SIGN(a % b + 0.5)) / 2
Jadi, seluruh rumusnya adalah:
a % b + ABS(b) * (1 - SIGN(a % b + 0.5)) / 2