BINARY(1024) フィールドのハミング重み/人口カウント/「1 ビットの数」を計算する高速な方法を探しています。MySQL には、そのようなことを行う BIT_COUNT 関数があります。T-SQL で同様の関数を見つけることができませんでしたか?
または、バイナリ データを別のタイプのフィールドに格納することをお勧めしますか?
何を言っているのかわからない場合は、ハミングの重みに関するウィキペディアの記事をご覧ください。
BINARY(1024) フィールドのハミング重み/人口カウント/「1 ビットの数」を計算する高速な方法を探しています。MySQL には、そのようなことを行う BIT_COUNT 関数があります。T-SQL で同様の関数を見つけることができませんでしたか?
または、バイナリ データを別のタイプのフィールドに格納することをお勧めしますか?
何を言っているのかわからない場合は、ハミングの重みに関するウィキペディアの記事をご覧ください。
バイトなどの小さな数値に対して事前に計算されたハミング重みを持つヘルパー テーブルを使用し、それに応じて値を分割し、ヘルパー テーブルに結合して、部分的なハミング重みの合計を値のハミング重みとして取得できます。
-- define Hamming weight helper table
DECLARE @hwtally TABLE (byte tinyint, hw int);
INSERT INTO @hwtally (byte, hw) VALUES (0, 0);
INSERT INTO @hwtally (byte, hw) SELECT 1 - byte, 1 - hw FROM @hwtally;
INSERT INTO @hwtally (byte, hw) SELECT 3 - byte, 2 - hw FROM @hwtally;
INSERT INTO @hwtally (byte, hw) SELECT 7 - byte, 3 - hw FROM @hwtally;
INSERT INTO @hwtally (byte, hw) SELECT 15 - byte, 4 - hw FROM @hwtally;
INSERT INTO @hwtally (byte, hw) SELECT 31 - byte, 5 - hw FROM @hwtally;
INSERT INTO @hwtally (byte, hw) SELECT 63 - byte, 6 - hw FROM @hwtally;
INSERT INTO @hwtally (byte, hw) SELECT 127 - byte, 7 - hw FROM @hwtally;
INSERT INTO @hwtally (byte, hw) SELECT 255 - byte, 8 - hw FROM @hwtally;
-- calculate
WITH split AS (
SELECT SUBSTRING(@value, number, 1) AS byte
FROM master.dbo.spt_values
WHERE type = 'P' AND number BETWEEN 1 AND LEN(@value)
)
SELECT
Value = @value,
HammingWeight = SUM(t.hw)
FROM split s
INNER JOIN @hwtally t ON s.byte = t.byte
小さい値 (最大 16 ビットなど) で遊んでいる場合、SQL Server でそれを行う最も効率的な方法は、すべての結果が計算されたテーブルを使用し、結合を使用することです。
17'000 行で 4 ビット値のハミング重みを計算する必要があるクエリでこの種のことを行うことにより、クエリを 30 秒から 0 秒に高速化しました。
WITH HammingWeightHelper AS (
SELECT x, Fx
FROM (VALUES(0,0),(1,1),(2,1),(3,2),
(4,1),(5,2),(6,2),(7,3),
(8,1),(9,2),(10,2),(11,3),
(12,2),(13,3),(14,3),(15,4)) AS HammingWeight(x, Fx)
)
SELECT HammingWeight.Fx As HammingWeight, SomeTable.Value As bitField
FROM SomeTable INNER JOIN
HammingWeightHelper ON HammingWeightHelper.x = SomeTable.Value
もちろん、これは醜い解決策であり、おそらく長いビット フィールドには適していません。
いい方法が思いつきませんでした。最後に、Java でハミングの重みを計算し、データベースのビット数を定期的に更新しました。
ハミングの重みについては特に何も見つかりませんでしたが、ハミングの距離については次のとおりです。
create function HamDist(@value1 char(8000), @value2 char(8000))
returns int
as
begin
declare @distance int
declare @i int
declare @len int
select @distance = 0,
@i =1,
@len = case when len(@value1) > len(@value2)
then len(@value1)
else len(@value2) end
if (@value1 is null) or (@value2 is null)
return null
while (@i <= @len)
select @distance = @distance +
case when substring(@value1,@i,1) != substring(@value2,@i,1)
then 1
else 0 end,
@i = @i +1
return @distance
end
これは、2 つの値の間のハミング距離を計算します。単一の値のハミング重みは、その値とゼロ値の配列の間のハミング距離になります。