問題:
(負ではない)剰余を見つけたい。
例:
表のnumbers
、整数の2つの列があります: a
および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 |
a
を除算して余りを計算したい b
による 。各余りは、 b
よりも小さい非負の整数値である必要があります 。
解決策1(完全に正しいわけではありません):
SELECT a, b, MOD(a, b) AS remainder FROM numbers;
結果は次のとおりです。
a | b | 残り |
---|---|---|
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 | エラー |
0 | 0 | エラー |
ディスカッション:
aが負でない場合、このソリューションは正しく機能します。ただし、負の場合は、余りの数学的定義に従いません。
概念的には、剰余は a
の整数除算の後に残るものです。 b
による 。数学的には、2つの整数の余りは、除数 b
よりも小さい非負の整数です。 。より正確には、それは数r∈{0,1、...、 b -1} a =k * b + rのような整数kが存在する 。例:
5 =1 * 3 + 2
、したがって、5と3の余りは 2
に等しくなります 。
9 =3 * 3 + 0
、したがって、9と3の余りは 0
に等しくなります 。
5 =(-1)*(-3)+ 2
、したがって、5と-3の余りは 2
に等しくなります 。
これがMOD(a、b)
の方法です a
列の負でない配当に対して機能します 。明らかに、除数が b
の場合、エラーが表示されます。 0
です 、 0
で除算できないため 。
被除数aが負の数の場合、正しい剰余を取得することは問題があります。残念ながら、 MOD(a、b)
aが負の場合、負の値を返すことができます。例:
MOD(-2、5)
-2
を返します 3
を返す必要がある場合 。
MOD(-5、-3)
-2
を返します 1
を返す必要がある場合 。
解決策2(すべての数値に対して正しい):
SELECT a, b, CASE WHEN MOD(a, b) >= 0 THEN MOD(a, b) ELSE MOD(a, b) + ABS(b) END AS remainder FROM numbers;
結果は次のとおりです。
a | b | 残り |
---|---|---|
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 | エラー |
0 | 0 | エラー |
ディスカッション:
任意間の除算の余りを計算するには 2つの整数(負または非負)の場合、 CASE WHEN
を使用できます 工事。 MOD(a、b)
の場合 は負ではなく、余りは単純に MOD(a、b)
。それ以外の場合は、 MOD(a、b)
によって返される結果を修正する必要があります 。
MOD()
の場合、どのようにして正しい余りを取得しますか 負の値を返しますか?除数の絶対値をMOD(a、b)
に追加する必要があります 。つまり、 MOD(a、b)+ ABS(b)
にします。 :
MOD(-2、5)
-2
を返します 3
を返す必要がある場合 。これを修正するには、 5
を追加します 。
MOD(-5、-3)
-2
を返します 1
を返す必要がある場合 。これは、 3
を追加することで修正できます 。
MOD(a、b)
の場合 負の数、 CASE WHEN
を返します 結果はMOD(a、b)+ ABS(b)
になります 。これがソリューション2の取得方法です。ABS()
の方法について復習が必要な場合 関数が機能する場合は、クックブック「SQLで絶対値を計算する方法」を参照してください。
もちろん、数値を 0
で割ることはできません。 。したがって、 b =0
の場合 、エラーが発生します。
解決策3(すべての数値に対して正しい):
SELECT a, b, MOD(a, b) + ABS(b) * (1 - SIGN(MOD(a, b) + 0.5)) / 2 AS remainder FROM numbers;
結果は次のとおりです。
a | b | 残り |
---|---|---|
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 | エラー |
0 | 0 | エラー |
ディスカッション:
この問題を解決する別の方法があります。 CASE WHEN
の代わりに 、より複雑な1行の数式を使用します:
MOD(a、b)+ ABS(b)*(1-SIGN(MOD(a、b)+ 0.5))/ 2
ソリューション2では、 MOD(a、b)+ ABS(b)
MOD(a、b)<0
の場合に返されました 。 MOD(a、b)<0 の場合、 MOD(a、b)+ ABS(b)=MOD(a、b)+ ABS(b)*1であることに注意してください。 。
対照的に、 MOD(a、b)
を返します。 MOD(a、b)> =0
の場合 。 MOD(a、b)=MOD(a、b)+ ABS(b)* 0(MOD(a、b)> =0の場合)
。
したがって、 ABS(b)
を乗算できます。 負のMOD(a、b)
の場合は1に等しい式によって および0
非負のMOD(a、b)
の場合 。 MOD(a、b)
以降 は常に整数であり、式 MOD(a、b)+ 0.5
MOD(a、b)≥0
の場合は常に正です MOD(a、b)<0
の場合は負 。 1
未満の任意の正の数を使用できます 0.5
の代わりに 。
符号関数SIGN()
1
を返します 引数が厳密に正の場合、 -1
厳密に負の場合、 0
0
に等しい場合 。ただし、 0
のみを返すものが必要です。 および1
、 1
ではありません および-1
。これを修正する方法は次のとおりです。
(1-1)/ 2 =0
(1-(-1))/ 2 =1
次に、 ABS(b)
を乗算する正しい式 は:
(1-SIGN(MOD(a、b)+ 0.5))/ 2
したがって、式全体は次のようになります。
MOD(a、b)+ ABS(b)*(1-SIGN(MOD(a、b)+ 0.5))/ 2