トップページに戻る    次のSQLパズルへ    前のSQLパズルへ

10-162 ビット演算(AND,OR,XOR)

SQLパズル

numBinTable
num  bin
---  ----
  0  0000
  1  0001
  2  0010
  3  0011
  4  0100
  5  0101
  6  0110
  7  0111
  8  1000

numBinTableから、
2レコード選ぶ、全ての組み合わせの
ビットでの、AND,OR,XORを求める

出力結果
num  bin   num  bin   BitAND  BitOR  BitXOR
---  ----  ---  ----  ------  -----  ------
  0  0000    0  0000    0000   0000    0000
  0  0000    1  0001    0000   0001    0001
  0  0000    2  0010    0000   0010    0010
  0  0000    3  0011    0000   0011    0011
  0  0000    4  0100    0000   0100    0100
  0  0000    5  0101    0000   0101    0101
  0  0000    6  0110    0000   0110    0110
  0  0000    7  0111    0000   0111    0111
  0  0000    8  1000    0000   1000    1000
  1  0001    1  0001    0001   0001    0000
  1  0001    2  0010    0000   0011    0011
  1  0001    3  0011    0001   0011    0010
  1  0001    4  0100    0000   0101    0101
  1  0001    5  0101    0001   0101    0100

こちらを参考にさせていただきました(英語)


データ作成スクリプト

create table numBinTable as
select 0 as num,'0000' as bin from dual
union select 1,'0001' from dual
union select 2,'0010' from dual
union select 3,'0011' from dual
union select 4,'0100' from dual
union select 5,'0101' from dual
union select 6,'0110' from dual
union select 7,'0111' from dual
union select 8,'1000' from dual;

create or replace function to_base( p_dec in number, p_base in number )
return varchar2
is
    l_str   varchar2(255) default NULL;
    l_num   number  default p_dec;
    l_hex   varchar2(50) default '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
begin
    if ( trunc(p_dec) <> p_dec OR p_dec < 0 ) then
        raise PROGRAM_ERROR;
    end if;
    loop
        l_str := substr( l_hex, mod(l_num,p_base)+1, 1 ) || l_str;
        l_num := trunc( l_num/p_base );
        exit when ( l_num = 0 );
    end loop;
    return l_str;
end to_base;
/


SQL

col anum for 999
col bnum for 999
col BitAND for a6
col BitOR  for a6
col BitXOR for a6

--■■■UTL_RAWパッケージを使わない方法■■■
select a.num as anum,a.bin,
b.num as bnum,b.bin,
LPad(to_base(bitand(a.num,b.num),2),4,'0') as "BitAND",
LPad(to_base(a.num+b.num-bitand(a.num,b.num),2),4,'0') as "BitOR",
LPad(to_base(a.num+b.num-2*bitand(a.num,b.num),2),4,'0') as "BitXOR"
  from numBinTable a,numBinTable b
 where a.num <= b.num;

--■■■UTL_RAWパッケージを使う方法■■■
select a.num as anum,a.bin,
b.num as bnum,b.bin,
LPad(to_base(bitand(a.num,b.num),2),4,'0') as "BitAND",
LPad(to_base(
utl_raw.cast_to_binary_integer(
    utl_raw.bit_or(
      utl_raw.cast_from_binary_integer(a.num),
      utl_raw.cast_from_binary_integer(b.num)))
,2),4,'0') as "BitOR",
LPad(to_base(
utl_raw.cast_to_binary_integer(
    utl_raw.bit_xor(
      utl_raw.cast_from_binary_integer(a.num),
      utl_raw.cast_from_binary_integer(b.num)))
,2),4,'0') as "BitXOR"
  from numBinTable a,numBinTable b
 where a.num <= b.num;


解説

ビットORは、
ビット加算 - ビットAnd
で求めることができます

場合に分けて証明すると

■■■■■■■■■■■■■■■■■■
場合1
0と0の場合

ビット加算  ビットAnd   ビットOR
        0          0          0
      + 0   BitAnd 0    BitOR 0
      ---   --------   --------
        0          0          0

ビットOR = 0
ビット加算 - ビットAnd = 0 - 0 = 0

なので
ビットOR = ビット加算 - ビットAnd
は、成り立つ

■■■■■■■■■■■■■■■■■■
場合2
0と1の場合(交換法則より、1と0の場合も含む)

ビット加算  ビットAnd   ビットOR
        0          0          0
      + 1   BitAnd 1    BitOR 1
      ---   --------   --------
        1          0          1

ビットOR = 1
ビット加算 - ビットAnd = 1 - 0 = 1

なので
ビットOR = ビット加算 - ビットAnd
は、成り立つ

■■■■■■■■■■■■■■■■■■
場合3
1と1の場合

ビット加算  ビットAnd   ビットOR
        1          1          1
      + 1   BitAnd 1    BitOR 1
      ---   --------   --------
       10          1          1

ビットOR = 1
ビット加算 - ビットAnd = 10 - 1 = 1

なので
ビットOR = ビット加算 - ビットAnd
は、成り立つ

■■■■■■■■■■■■■■■■■■
以上により、
ビットOR = ビット加算 - ビットAnd
が成り立ちます。

ビット加算で、繰り上がりが発生したとしても
ビットAndを引いているので、繰り下がりが発生して、
結果として、上位桁への繰り上がりが、発生しないのです


ビットXORは、 ビットOR - ビットAND で求めることができます 場合に分けて証明すると ■■■■■■■■■■■■■■■■■■ 場合1 0と0の場合 ビットOR ビットAnd ビットXOR 0 0 0 BitOR 0 BitAnd 0 BitXOR 0 -------- -------- --------- 0 0 0 ビットXOR = 0 ビットOR - ビットAND = 0 - 0 = 0 なので ビットXOR = ビットOR - ビットAND は、成り立つ ■■■■■■■■■■■■■■■■■■ 場合2 0と1の場合(交換法則より、1と0の場合も含む) ビットOR ビットAnd ビットXOR 0 0 0 BitOR 1 BitAnd 1 BitXOR 1 -------- -------- --------- 1 0 1 ビットXOR = 1 ビットOR - ビットAND = 1 - 0 = 0 なので ビットXOR = ビットOR - ビットAND は、成り立つ ■■■■■■■■■■■■■■■■■■ 場合3 1と1の場合 ビットOR ビットAnd ビットXOR 1 1 1 BitOR 1 BitAnd 1 BitXOR 1 -------- -------- --------- 1 1 0 ビットXOR = 0 ビットOR - ビットAND = 0 - 0 = 0 ■■■■■■■■■■■■■■■■■■ 以上により、 ビットXOR = ビットOR - ビットAND が成り立ちます。 8-20 集合関数のBitAND,BitOR,BitXOR 10-163 ビット演算(NOT)

UTL_RAWパッケージの資料
BITAND、BITOR、BITXOR - オラクル・Oracle SQL 関数リファレンス