【问题标题】:How to find the nearest match for an integer in a given matrix?如何找到给定矩阵中整数的最接近匹配?
【发布时间】:2024-01-11 21:34:01
【问题描述】:

我有两个矩阵。矩阵A(2048,64) 和矩阵B(10000,64)。这些矩阵的每个元素中的值都是一个二进制位,所以每一行都是一个 64 位二进制值的表示,所以矩阵的每一行的大小在2^632^0 之间;分别从最高有效位到最低有效位。

问题:

对于A 的每一行,我想在B 中找到在绝对数字意义上最接近它的值。

考虑A(i,1:64) 是十进制值Xi 的二进制表示,B(j,1:64) 是十进制值Yj 的二进制表示。所以第一步我想找到最好的j,这样X1A(1,1:64)的数值最接近Yj处的元素,即abs(X1-Yj)j的所有可能值中最小化.

下图来自here,很好地描述了我的问题,但不同之处在于我的每个值都包含在包含 64 个元素的矩阵的一行中。

我尝试将 64 位值转换为十进制,但 dec2bin 仅支持高达 56 位的值。

【问题讨论】:

  • 矩阵中不能有单元格。你可以在一个单元格中有一个矩阵
  • 手动转换为小数,然后使用 Mathworks Central 上给出的答案
  • @SardarUsama 我现在区分单元格数组和矩阵。可能我应该使用其他词,例如矩阵房间(而不是单元格),但我不知道正确的词以避免误解。如果您知道,请编辑问题。
  • @Adriaan 我写了一个手动转换函数,但是它确实会导致精度损失,即对于大值,不保留二进制值的低位并且不精确计算距离。

标签: matlab matrix type-conversion distance unsigned-integer


【解决方案1】:

您可以将您的 64 位数字分成两个 32 位部分,b1b2,将它们转换为十进制值 d1d2,然后将它们组合成一个具有足够精度的 uint64 值保存结果。

bin2uint64 = @(b) uint64(bin2dec(b(:,1:32)))*(2^32) + uint64(bin2dec(b(:,33:64))); 

(假设您的数据格式与bin2dec 要求的格式相同,即字符向量。如果您有数值向量,只需添加b = char(b+'0');

给定一个初始值

>> b = 1100110010111100101101111010100010101010010011010010000110011010
>> d = bin2uint64(b)
d = 14752868414398472602
>> r = dec2bin(d, 64)
r = 1100110010111100101101111010100010101010010011010010000110011010
>> any(b-r)
ans = 0

由于b-r 全部为零,因此值相同。您可以将整个nx64 矩阵作为b 传递,它会一次转换所有值。

>> bin2uint64(char(randi([0 1], 20, 64) + '0'))
ans =

   4169100589409210726
   8883634060077187622
  15399652840620725530
  12845470998093501747
  14561257795005665153
   1133198980289431407
  13360302497937328511
    563773644115232568
   8825360015701340662
   2543400693478304607
  11786523850513558107
   8569436845019332309
   2720129551425231323
   5937260866696745014
   4974981393428261150
  16646060326132661642
   5943867124784820058
   2385960312431811974
  13146819635569970159
   6273342847731389380

您会注意到我手动将随机数组转换为char。假设您的输入是数字,您必须先将其转换:

Achar = char(A + '0');

是的,这很痛苦,MATLAB 应该在bin2dec 中包含目标类型参数,但他们没有。现在您可以使用您的链接解决方案来查找匹配项。

【讨论】:

    【解决方案2】:

    转换你的价值观:

    假设您的矩阵 AB 包含 numeric01,您可以使用 @ 轻松将行转换为 uint64 数据类型而不会丢失精度987654322@ 和 sum 函数(和 bsxfun 用于小幅提高效率):

    result = sum(bsxfun(@(bit, V) bitset(uint64(0), bit, V), 64:-1:1, A), 2, 'native');
    

    solution from beaker 相比,对于 10,000 行矩阵来说,这个速度要快 4 倍以上:

    % Sample data:
    A = randi([0 1], 10000, 64);
    
    % Test functions:
    bin2uint64 = @(b) uint64(bin2dec(b(:,1:32)))*(2^32) + uint64(bin2dec(b(:,33:64)));
    beaker_fcn = @(A) bin2uint64(char(A+'0'));
    gnovice_fcn = @(A) sum(bsxfun(@(b, V) bitset(uint64(0), b, V), 64:-1:1, A), 2, 'native');
    
    % Accuracy test:
    isMatch = isequal(beaker_fcn(A), gnovice_fcn(A));  % Return "true"
    
    % Timing:
    timeit(@() beaker_fcn(A))
    
    ans =
       0.022865378234183
    
    timeit(@() gnovice_fcn(A))
    
    ans =
       0.005434031911843
    

    计算最近匹配:

    您提供link to some solutions 用于在B 中查找与A 最接近的匹配项。但是,您使用 unsigned 整数类型这一事实需要进行一些修改。具体来说,由于integer overflow 而减去值时,顺序很重要。例如uint64(8) - uint64(1) 给你7,但uint64(1) - uint64(8) 给你0

    以下是修改后的无符号整数解决方案,适用于您提供的示例数据:

    A = uint64([1 5 7 3 2 8]);
    B = uint64([4 12 11 10 9 23 1 15]);
    delta = bsxfun(@(a, b) max(a-b, b-a), A(:), reshape(B, 1, []));
    [~, index] = min(delta, [], 2);
    result = B(index)
    
    result =
      1×6 uint64 row vector
    
       1   4   9   4   1   9   % As expected!
    

    【讨论】:

      最近更新 更多