if (value and 1) = 0 then
っというのは偶数というところまでは調べましたが、なぜ?というレベルで
す。教えてください。
質問を例にすれば
8 = 1000 (10進数の 8 は2進数では 1000 で表される)
ですから、 1 が立っている位置の値が 1 の数値
(8以外に 9 10 11 12 13 14 15 24 .. などの数値)
で条件が成立します。
※ メモリを効率よく利用するために考えられた方法だと
思います。
どのバージョンをお使いかわかりませんが、Del6では
and と入力して F1 ヘルプで「ビット演算」のヘルプ
が表示されます。
> __________ NOD32 3605 (20081112) 情報 __________
>
> このメールはNOD32によって検査済みです。
> http://canon-sol.jp
>
--
takashi <taka...@csjpn.com>
近藤 さんは書きました:
これはビット演算とかビットフィールド演算とか、「ビットをマスクする」というやつです。
例えば $5F and $48 は
$5F は 2進で表すと 0000 0000 0000 0000 0000 0000 0101 1111
$48 は 2進で表すと 0000 0000 0000 0000 0000 0000 0100 1000
ですからビット単位で論理積を取ると
0000 0000 0000 0000 0000 0000 0100 1000 ⇒ $48
になります。特定のビット(2進の一桁)のON/OFF をチェックしたい場合は
例えば下から4番目のビットをテストしたい場合
a and 8 と書けば a の下から4ビット目が 1 の場合
XXXX XXXX XXXX XXXX XXXX XXXX XXXX 1XXX
0000 0000 0000 0000 0000 0000 0000 1000
---------------------------------------
結果 0000 0000 0000 0000 0000 0000 0000 1000
a の下から4ビット目が 0 の場合
XXXX XXXX XXXX XXXX XXXX XXXX XXXX 0XXX
0000 0000 0000 0000 0000 0000 0000 1000
---------------------------------------
結果 0000 0000 0000 0000 0000 0000 0000 0000
となるので、 (a and 8) <> 0 とかけば、aの下から4番目のビットのON/OFF を
True/False の論理値に変換できます。
また or を使って特定のビットをONにしたり
a := a or 8
XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX
0000 0000 0000 0000 0000 0000 0000 1000
---------------------------------------
結果 XXXX XXXX XXXX XXXX XXXX XXXX XXXX 1XXX
and で特定のビット(この場合下から7番目)を OFF にしたり
a := a and $FFFFFFBF または a := a and not $00000040
XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX
1111 1111 1111 1111 1111 1111 1011 1111
---------------------------------------
結果 XXXX XXXX XXXX XXXX XXXX XXXX X0XX XXXX
できます。
同じような感じで、ビットシフトと組み合わせて、数ビットの情報を
整数値に埋め込んだり、取り出したりすることもできます。
ビットフィールドはひとつの整数値にたくさんのON/OFF情報やたくさんの数ビットの情報を
詰め込みたいときに使われます。ものすごく一般的な技法です。
ただ、少々判りにくいので、Delphi では、ON/OFF情報を詰め込む場合、ビットフィールドより
「集合」(Set)が使われます。
----------
東京都 日野市 中村拓男
最終的にはエンコードの変換をする必要がありましたので、しかたなくビット
演算を調べていました。この手の演算処理はCの頃から逃げていましたので、今
になって苦労しています。
お二人の説明でよくわかりました。
で、もしよろしければさらに教えていただきたいのですが、
>ただ、少々判りにくいので、Delphi では、ON/OFF情報を詰め込む場合、ビットフィー
>ルドより
>「集合」(Set)が使われます。
Cのソースを見るとビットフィールドを使っていますが、Delphiだと集合型へ
のキャストを行ってビット演算を行った例もあります。
どちらが処理としては早いのでしょうか?という疑問もありますし、なぜ
Delphiは集合型なの?という疑問と同時に、今のぼくにとっては、集合型の方が
わかりずらい、どちらかというと集合型でどうしてビット演算ができるの?とい
うものあります。
Quoting 近藤 <t_k...@hazimesoft.com>:
> Cのソースを見るとビットフィールドを使っていますが、Delphiだと集合型へ
> のキャストを行ってビット演算を行った例もあります。
> どちらが処理としては早いのでしょうか?という疑問もありますし、なぜ
> Delphiは集合型なの?という疑問と同時に、今のぼくにとっては、集合型の方が
> わかりずらい、どちらかというと集合型でどうしてビット演算ができるの?とい
> うものあります。
>
Delphi の集合型の内部的な実装はビットフィールドです。
違いは
1) ON/OFF 情報に簡単に名前が付けられる。ビット位置を意識する必要はない。
2) ON/OFF を、集合に要素が含まれているか/いないか(要素の有無)に
置き換えて考える。
3) 要素の有無を判断するための演算子 in が用意されている。
例) ssShift in ShiftState
4) 集合に要素を加えるための専用の手続き Include が用意されている。
Include(MyFontStyle, fsBold); // フォントスタイルにボールドを加える
5) 集合から要素を削除するための専用の手続き Exclude が用意されている。
Exclude(MyFontStyle, fsStrikeOut); // フォントスタイルから打ち消し線を外
す。
6) 集合専用のコンストラクタが用意されている。
MyFontStyle := [fsItalic, fsUnderLine]; // イタリックで下線付きのフォント
後 +, - * 演算子も使えて、一般的な集合演算をサポートしています。
和集合
[fsStrikeOut, fsItalic] + [fsStrikeOut, fsUnderline] ⇒
[fsStrikeOut, fsItalic, fsUnderline]
は 両集合のどちらかに含まれる要素を全ての含む集合を返す。
#無ければ加える。
ビット演算の a or b と同じ
差集合
[fsStrikeOut, fsItalic] - [fsStrikeOut, fsUnderline] ⇒
[fsItalic]
は 左の集合に含まれ右の集合に含まれない要素を持つ集合を返す。
#あればとる。
ビット演算の a and not b と同じ
積集合
[fsStrikeOut, fsItalic] - [fsStrikeOut, fsUnderline] ⇒
[fsStrikeOut]
は両集合に含まれる要素のみを含む集合を返す。
#共通のものをくくりだす。
ビット演算の a and b と同じ。
ビット演算はその意味をよく考えないと使えませんが、集合演算には明確な
意味づけがあるので、慣れれば分わかりやすいです。
----------
(株)ブレーン 中村拓男
し細な説明ありがとうございます。
>Delphi の集合型の内部的な実装はビットフィールドです。
集合型のサイズは1バイト(8bit)ということですね。
type
TMyBit = (mbBit_01, mbBit_02, mbBit_04, mbBit_08);
TMyBits = set of TMyBit;
として
ShowMessage(IntToStr(sizeOf(TMyBits)));
を実行すると1という数字が返ってきます。
[] 00000000
[mbBit_01] 00000001
[mbBit_02] 00000010
[mbBit_04] 00000100
[mbBit_08] 00001000
そこで以上のような関係かなと理解しました。
で、
以下は、http://mrxray.on.coocan.jp/Halbow/Notes/N016.html からの引用
ですが、それを集合型に書き換えたものとを比較します。
function NibbleToBinaryStr(value:Byte):string;
begin
SetLength(result,4);
if (value and 8) = 0 then result[1] := '0' else result[1] := '1';
if (value and 4) = 0 then result[2] := '0' else result[2] := '1';
if (value and 2) = 0 then result[3] := '0' else result[3] := '1';
if (value and 1) = 0 then result[4] := '0' else result[4] := '1';
end;
//集合型に書き換えたもの
function aNibbleToBinaryStr(MyBits: TMyBits):string;
begin
SetLength(result,4);
if (mbBit_08 in MyBits) then result[1] := '1' else result[1] := '0';
if (mbBit_04 in MyBits) then result[2] := '1' else result[2] := '0';
if (mbBit_02 in MyBits) then result[3] := '1' else result[3] := '0';
if (mbBit_01 in MyBits) then result[4] := '1' else result[4] := '0';
end;
procedure TForm1.Button1Click(Sender: TObject);
var
i:Byte;
begin
Memo1.Clear;
for i := $0 to $F do
Memo1.Lines.Add(Format(' %.2d = %s = $%.1x',[i,NibbleToBinaryStr
(i),i]));
//集合型に書き換えたもの
for i := $0 to $F do
Memo1.Lines.Add(Format(' %.2d = %s = $%.1x',[i,aNibbleToBinaryStr
(TMyBits(i)),i]));
end;
実行すると、期待通りの結果が表示されました。どうもありがとうございまし
た。
Quoting 近藤 <t_k...@hazimesoft.com>:
> >Delphi の集合型の内部的な実装はビットフィールドです。
>
> 集合型のサイズは1バイト(8bit)ということですね。
>
集合型のサイズは最大 32 バイトです。たしか 255要素まで
可能だったと思います。
----------
(株)ブレーン 中村拓男
----- Original Message -----
From: "近藤" <t_k...@hazimesoft.com>
To: <Del...@ml.users.gr.jp>
Sent: Thursday, November 13, 2008 6:12 PM
Subject: [Delphi:90880] Re: ビット演算のif文で
>>Delphi の集合型の内部的な実装はビットフィールドです。
>
> 集合型のサイズは1バイト(8bit)ということですね。
デフォルトでは int型 (32bit) だったはず...
# デフォルトでは,構造化型の値はアクセスを速くするためにワード境界または
# ダブルワード境界にアラインメントされます。
Packed を付けて最適化すると 8要素以下は Byte にアラインメントされるはずです。(コンパイラのバージョンによりますが)
# 構造化型を宣言するときは,予約語 packed を使用するとデータを圧縮して格納できます。
---- (-_-)(-_-)(-_-) THE REAL PROGRAMMER (-_-)(-_-)(-_-) ----
At the beach, The Real Programmer is the one drawing flowcharts in the sand.
戸田 英夫 mailto: Hideo...@hiroshima.ntt-west.jp
戸田 英夫 さんは書きました:
>戸田@お仕事中です
>
>----- Original Message -----
>From: "近藤" <t_k...@hazimesoft.com>
>To: <Del...@ml.users.gr.jp>
>Sent: Thursday, November 13, 2008 6:12 PM
>Subject: [Delphi:90880] Re: ビット演算のif文で
>
>
>>>Delphi の集合型の内部的な実装はビットフィールドです。
>>
>> 集合型のサイズは1バイト(8bit)ということですね。
>
>デフォルトでは int型 (32bit) だったはず...
>
># デフォルトでは,構造化型の値はアクセスを速くするためにワード境界または
># ダブルワード境界にアラインメントされます。
>
>Packed を付けて最適化すると 8要素以下は Byte にアラインメントされるはずです。(コンパイラのバージョンによりますが)
>
># 構造化型を宣言するときは,予約語 packed を使用するとデータを圧縮して格納できます。
ヘルプだとたしかにそう読める箇所もあるのですが、
「構造化型」
ms-help://embarcadero.rs2009/devcommon/structuredtypes_xml.html
実態は全然違ってます。
「集合型変数の内部構造が知りたい/数値として処理したい。」
http://www2.big.or.jp/~osamu/Delphi/Tips/search.cgi#0277.txt
集合型のアライメントは基本は1で、サイズが 2, 4 のときのみ 2,4 になります。
蛇足ですが、型のアライメントをその型の本来のアライメントより大きくする方法はありません。
Packed や $ALIGN で狭めることのみ可能です。
このあたりの話は大昔からヘルプが変で、いい加減直して欲しいと思います。
アライメントのデフォルトが {$A8} なので、Delphi では全ての型のアライメントが 8 だと
信じている人がたくさんいるみたいです。
さらに蛇足:
published な property の集合型の要素数は 32 個までです。これは、
Delphi の RTTI(実行時方情報)の都合で、集合型を内部的に 4バイト 整数で処理
するからです。
----------
東京都 日野市 中村拓男
Quoting 中村拓男 <tknak...@brain-tokyo.jp>:
すいません。URL を書き損ねました。
>
> 実態は全然違ってます。
>
> 「集合型変数の内部構造が知りたい/数値として処理したい。」
> http://www2.big.or.jp/~osamu/Delphi/Tips/search.cgi#0277.txt
「集合型変数の内部構造が知りたい/数値として処理したい。」
http://www2.big.or.jp/~osamu/Delphi/tips.cgi?index=0277.txt
----------
(株)ブレーン 中村拓男