使用按位运算符相乘

2024-05-18

我想知道如何使用按位运算符将一系列二进制位相乘。但是,我有兴趣这样做来查找二进制值的十进制小数值。这是我正在尝试做的一个例子:

假设:1010010,

我想使用每个单独的位,以便将其计算为:

1*(2^-1) + 0*(2^-2) + 1*(2^-3) + 0*(2^-4).....

虽然我对在 ARM 汇编中执行此操作感兴趣,但在 C/C++ 中提供示例仍然会有所帮助。

我正在考虑使用计数器执行循环,每次循环迭代时,计数器都会递增,该值将逻辑左移,以便获取第一位,并乘以 2^-计数器。

然而,我并不完全确定如何仅让第一位/MSB 相乘,而且我很困惑如何将该值乘以基数 2 得到某个负幂。

我知道逻辑左移会将其乘以基数 2,但它们通常具有正指数。前任。 LSL r0, 2 表示 r0 中的值将乘以 2^2 = 4。

提前致谢!


仅使用按位运算将两个数字相乘 (AND, OR, XOR, <<, >>)是完全可能的,尽管可能不是很有效。您可能想阅读相关的维基百科文章加法器(电子) http://en.wikipedia.org/wiki/Adder_(electronics) and 二进制乘法器 http://en.wikipedia.org/wiki/Binary_multiplier.

自下而上的乘法方法是首先创建一个二进制加法器。对于最低位(位 0)a半加器 http://en.wikipedia.org/wiki/Adder_%28electronics%29#Half_adder工作正常。 S表示和,C表示进位。

对于其余的部分,您需要全加器 http://en.wikipedia.org/wiki/Adder_%28electronics%29#Full_adder对于每一位。 Cin 的意思是“带入”,Cout 的意思是“执行”:

对几个位求和的最简单的逻辑电路称为纹波进位加法器 http://en.wikipedia.org/wiki/Adder_(electronics)#Ripple-carry_adder:

纹波进位加法器基本上是一系列全加器,进位被传播到全加器计算下一个更高的有效位。确实存在其他更有效的方法,但由于简单的原因,我跳过它们。现在我们有了一个二进制加法器。

二进制乘法器是一个更困难的情况。但由于我认为这更多的是概念证明,而不是两个数字相乘的实用方法,所以让我们走一个更简单的弯路。

假设我们要计算的乘积a and b, a = 100, b = 5. a and b都是 16 位无符号整数(也可以是定点)。我们可以创建一个被加数数组,在其中写入值a (100) b(5) 次,反之亦然。由于 16 位可表示的最高无符号值是 2^16-1 (65535),因此我们希望创建一个由 65535 个无符号整数组成的数组,并用零填充。然后我们需要仅使用按位运算将数组中的 5 个值设置为 100。

我们可以这样做:首先我们填充一个数组(我们称之为a_array) 的值为a(100)。然后我们想要将一些值归零a_array基于的价值b, 以便b的值a_array保持不变,其余值a_array被归零。为此,我们使用二进制掩码和AND按位运算。

所以我们循环遍历这些位b。对于每一位b我们根据该位的值创建一个二进制掩码b。创建这样的二进制掩码只需要位移位(<<, >>),按位AND和按位OR.



0 -> 0b0000 0000 0000 0000
1 -> 0b1111 1111 1111 1111
  

所以,现在我们有了一个二进制掩码。但我们如何使用它呢?好吧,位 0b对应数值0或1。位1b对应数值0或2。位2b对应于数值 0 或 4。所以位 nb对应于0或2^n的数值。所以,当我们循环遍历这些位时b并为每个位创建一个二进制掩码,我们AND2^n 个值a_array与相应的二进制掩码。对应的值在a_array要么归零,要么保持不变。在C代码中我使用for循环AND通过a_array,以及递增和递减计数器。增量和减量分别是not一个按位运算。但是for循环不是必需的,它仅用于可读性(从人类的角度来看)。实际上,我首先在 x86-64 程序集中编写了一个 4 位 * 4 位 = 4 位乘法器来尝试这个概念,仅使用and, or, xor, shl(左移位),以及shr(右移一位)和call. call是函数或过程调用,即not按位运算,但您可以内联所有这些函数或过程,从而仅使用AND, OR, XOR, << and >>。所以而不是for循环,对于每一位b, 你可以ANDn (n = 1, 2, 4, 8 ...) 的对应值a_array使用基于相应位的按位掩码b。对于 16 位 * 16 位 = 16 位乘法,需要 65535AND命令(无循环)。计算机对这样的输入没有问题,但人类在阅读这样的代码时往往会遇到问题。由于这个原因for使用循环。

现在我们有a_array洋溢着b的值a,其余为零。剩下的很简单:我们只需将所有值相加a_array使用按位加法器(这是函数my_add在下面的 C 代码中)。

这是 16 位 * 16 位 = 16 位无符号整数乘法的代码。请注意该函数memset16假定采用小端架构。转换memset16对于大端架构来说应该是微不足道的。该代码也适用于定点乘法,您只需要在最后添加一位移位即可。转换为不同的变量大小以及实现溢出检测也应该很简单。任务留给读者。使用 GCC 编译,在 x86-64 Linux 中测试。

#include <stdio.h>
#include <stdint.h>
#include <string.h>

#define NUMBER_OF_BITS 16
#define MAX_VALUE 65535

typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;

typedef int8_t s8;
typedef int16_t s16;
typedef int32_t s32;

typedef struct result_struct{
    u16 result;
    u16 carry;
} result_struct;

u16 extend_lowest_bit(u16 a)
{
    /* extends lowest bit (bit 0) to all bits. */
    u16 a_extended;
    a = (a & 1);
    a_extended = a | (a << 1) | (a << 2) | (a << 3) | (a << 4);
    a_extended = a_extended | (a << 5) | (a << 6) | (a << 7) | (a << 8);
    a_extended = a_extended | (a << 9) | (a << 10) | (a << 11) | (a << 12);
    a_extended = a_extended | (a << 13) | (a << 14) | (a << 15);
    return a_extended;
}

result_struct my_add(u16 a, u16 b)
{
    /* computes (a + b). */
    result_struct add_results;

    u16 a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15;
    u16 b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15;
    u16 carry, result = 0;
    /* prepare for bitwise addition by separating
     * each bit of summands a and b using bitwise AND. */
    a0 = a & 1;
    a1 = a & (1 << 1);
    a2 = a & (1 << 2);
    a3 = a & (1 << 3);
    a4 = a & (1 << 4);
    a5 = a & (1 << 5);
    a6 = a & (1 << 6);
    a7 = a & (1 << 7);
    a8 = a & (1 << 8);
    a9 = a & (1 << 9);
    a10 = a & (1 << 10);
    a11 = a & (1 << 11);
    a12 = a & (1 << 12);
    a13 = a & (1 << 13);
    a14 = a & (1 << 14);
    a15 = a & (1 << 15);

    b0 = b & 1;
    b1 = b & (1 << 1);
    b2 = b & (1 << 2);
    b3 = b & (1 << 3);
    b4 = b & (1 << 4);
    b5 = b & (1 << 5);
    b6 = b & (1 << 6);
    b7 = b & (1 << 7);
    b8 = b & (1 << 8);
    b9 = b & (1 << 9);
    b10 = b & (1 << 10);
    b11 = b & (1 << 11);
    b12 = b & (1 << 12);
    b13 = b & (1 << 13);
    b14 = b & (1 << 14);
    b15 = b & (1 << 15);

    add_results.result = a0 ^ b0;
    /* result: 0000 0000 0000 000x */
    carry = (a0 & b0) << 1;
    add_results.result = add_results.result | (a1 ^ b1 ^ carry);
    /* result: 0000 0000 0000 00xx */
    carry = ((carry & (a1 ^ b1)) | (a1 & b1)) << 1;
    add_results.result = add_results.result | (a2 ^ b2 ^ carry);
    /* result: 0000 0000 0000 0xxx */
    carry = ((carry & (a2 ^ b2)) | (a2 & b2)) << 1;
    add_results.result = add_results.result | (a3 ^ b3 ^ carry);
    /* result: 0000 0000 0000 xxxx */
    carry = ((carry & (a3 ^ b3)) | (a3 & b3)) << 1;
    add_results.result = add_results.result | (a4 ^ b4 ^ carry);
    /* result: 0000 0000 000x xxxx */
    carry = ((carry & (a4 ^ b4)) | (a4 & b4)) << 1;
    add_results.result = add_results.result | (a5 ^ b5 ^ carry);
    /* result: 0000 0000 00xx xxxx */
    carry = ((carry & (a5 ^ b5)) | (a5 & b5)) << 1;
    add_results.result = add_results.result | (a6 ^ b6 ^ carry);
    /* result: 0000 0000 0xxx xxxx */
    carry = ((carry & (a6 ^ b6)) | (a6 & b6)) << 1;
    add_results.result = add_results.result | (a7 ^ b7 ^ carry);
    /* result: 0000 0000 xxxx xxxx */
    carry = ((carry & (a7 ^ b7)) | (a7 & b7)) << 1;
    add_results.result = add_results.result | (a8 ^ b8 ^ carry);
    /* result: 0000 000x xxxx xxxx */
    carry = ((carry & (a8 ^ b8)) | (a8 & b8)) << 1;
    add_results.result = add_results.result | (a9 ^ b9 ^ carry);
    /* result: 0000 00xx xxxx xxxx */
    carry = ((carry & (a9 ^ b9)) | (a9 & b9)) << 1;
    add_results.result = add_results.result | (a10 ^ b10 ^ carry);
    /* result: 0000 0xxx xxxx xxxx */
    carry = ((carry & (a10 ^ b10)) | (a10 & b10)) << 1;
    add_results.result = add_results.result | (a11 ^ b11 ^ carry);
    /* result: 0000 xxxx xxxx xxxx */
    carry = ((carry & (a11 ^ b11)) | (a11 & b11)) << 1;
    add_results.result = add_results.result | (a12 ^ b12 ^ carry);
    /* result: 000x xxxx xxxx xxxx */
    carry = ((carry & (a12 ^ b12)) | (a12 & b12)) << 1;
    add_results.result = add_results.result | (a13 ^ b13 ^ carry);
    /* result: 00xx xxxx xxxx xxxx */
    carry = ((carry & (a13 ^ b13)) | (a13 & b13)) << 1;
    add_results.result = add_results.result | (a14 ^ b14 ^ carry);
    /* result: 0xxx xxxx xxxx xxxx */
    carry = ((carry & (a14 ^ b14)) | (a14 & b14)) << 1;
    add_results.result = add_results.result | (a15 ^ b15 ^ carry);
    /* result: xxxx xxxx xxxx xxxx */
    add_results.carry = ((carry & (a15 ^ b15)) | (a15 & b15)) << 1;
    return add_results;
}

result_struct add_array(void* array, s32 size)
{
    /* adds together all u16 values of the array. */
    result_struct add_results;
    u16* i;
    u16* top_address;

    add_results.result = 0;
    add_results.carry = 0;

    for (i = array; i < ((u16*)array + size); i++)
    {
        add_results = my_add(add_results.result, *i);
    }
    return add_results;
}

void memset16(void* dest, u16 value, s32 size)
{
    /* does a 16-bit memset. size is the number of u16's (words). */
    u8* i;

    for (i = (u8*)dest; i < ((u8*)dest+(2*size)); i+=2)
    {
        memset(i, (int)(value & 0xff), 1);
        memset(i+1, (int)(value >> 8), 1);
    }  
}

result_struct my_mul(u16 a, u16 b)
{
    /* computes (a * b) */
    u16 bitmask, a_array[MAX_VALUE];
    u32 block_length;
    s16 bit_i;
    s32 count, size;
    u16* i;
    void* p_a_array; 
    p_a_array = a_array;

    result_struct mul_results;
    mul_results.result = 0;

    size = MAX_VALUE;
    memset16(p_a_array, a, size);   // can be replaced with AND.

    /* mask the summands. can be unrolled to
     * use only bitwise operations. */
    i = p_a_array;

    for (bit_i = 0, block_length = 1; bit_i < NUMBER_OF_BITS; bit_i++)
    {
        bitmask = extend_lowest_bit(b >> bit_i);

        for (count = block_length; count > 0; count--)
        {
            *i = (*i & bitmask);
            i++;
        }
        block_length <<= 1;
    }
    /* the array of summands is now masked. */

    /* add the values of the array together. */
    mul_results = add_array(p_a_array, MAX_VALUE);
    return mul_results;
}

int main(void)
{
    int a, b;
    result_struct multiply_results;

    printf("Enter the 1st unsigned 16-bit integer.\n");
    scanf("%d", &a);
    printf("Enter the 2nd unsigned 16-bit integer.\n");
    scanf("%d", &b);
    multiply_results = my_mul((u16)a, (u16)b);
    printf("%d * %d = %d\n", a, b, multiply_results.result);
    return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用按位运算符相乘 的相关文章

  • 在 LINQ 查询中返回不带时间的日期

    我正在编写一个查询 我想计算按日期联系我们的呼叫中心的次数 看起来很简单 但由于联系日期字段是日期时间字段 我得到了时间 因此当我按联系日期 时间 分组时 每个联系日期实例的计数为 1 所以 我想只按日期分组 而不按时间分组 下面是我用来查
  • 自动从 C# 代码进行调试过程并读取寄存器值

    我正在寻找一种方法来读取某个地址的 edx 注册表 就像这个问题中所问的那样 读取eax寄存器 https stackoverflow com questions 16490906 read eax register 虽然我的解决方案需要用
  • Func 方法参数的首选命名约定是什么?

    我承认这个问题是主观的 但我对社区的观点感兴趣 我有一个缓存类 它采用类型的缓存加载器函数Func
  • 嵌入式系统中的malloc [重复]

    这个问题在这里已经有答案了 我正在使用嵌入式系统 该应用程序在 AT91SAMxxxx 和 cortex m3 lpc17xxx 上运行 我正在研究动态内存分配 因为它会极大地改变应用程序的外观 并给我更多的力量 我认为我唯一真正的路线是为
  • Cygwin 下使用 CMake 编译库

    我一直在尝试使用 CMake 来编译 TinyXML 作为一种迷你项目 尝试学习 CMake 作为补充 我试图将其编译成动态库并自行安装 以便它可以工作 到目前为止 我已经设法编译和安装它 但它编译成 dll 和 dll a 让它工作的唯一
  • C# 中可空类型是什么?

    当我们必须使用nullable输入 C net 任何人都可以举例说明 可空类型 何时使用可空类型 https web archive org web http broadcast oreilly com 2010 11 understand
  • 如何在 WPF RichTextBox 中跟踪 TextPointer?

    我正在尝试了解 WPF RichTextBox 中的 TextPointer 类 我希望能够跟踪它们 以便我可以将信息与文本中的区域相关联 我目前正在使用一个非常简单的示例来尝试弄清楚发生了什么 在 PreviewKeyDown 事件中 我
  • A* 之间的差异 pA = 新 A;和 A* pA = 新 A();

    在 C 中 以下两个动态对象创建之间的确切区别是什么 A pA new A A pA new A 我做了一些测试 但似乎在这两种情况下 都调用了默认构造函数 并且仅调用了它 我正在寻找性能方面的任何差异 Thanks If A是 POD 类
  • 线程、进程和 Application.Exit()

    我的应用程序由主消息循环 GUI 和线程 Task Factory 组成 在线程中我调用一些第三方应用程序var p new Process 但是当我调用Application Exit 在消息循环中 我可以看到在线程中启动的进程仍在内存中
  • 初始化变量的不同方式

    在 C 中初始化变量有多种方法 int z 3 与 int 相同z 3 Is int z z 3 same as int z z 3 您可以使用 int z z 3 Or just int z 3 Or int z 3 Or int z i
  • 更改窗口的内容 (WPF)

    我创建了一个简单的 WPF 应用程序 它有两个 Windows 用户在第一个窗口中填写一些信息 然后单击 确定 这会将他们带到第二个窗口 这工作正常 但我试图将两个窗口合并到一个窗口中 这样只是内容发生了变化 我设法找到了这个更改窗口内容时
  • 可空属性与可空局部变量

    我对以下行为感到困惑Nullable types class TestClass public int value 0 TestClass test new TestClass Now Nullable GetUnderlyingType
  • AccessViolationException 未处理

    我正在尝试使用史蒂夫 桑德森的博客文章 http blog stevensanderson com 2010 01 28 editing a variable length list aspnet mvc 2 style 为了在我的 ASP
  • 已过时 - OpenCV 的错误模式

    我正在使用 OpenCV 1 进行一些图像处理 并且对 cvSetErrMode 函数 它是 CxCore 的一部分 感到困惑 OpenCV 具有三种错误模式 叶 调用错误处理程序后 程序终止 Parent 程序没有终止 但错误处理程序被调
  • 如何在sphinx中启用数学?

    我在用sphinx http sphinx pocoo org index html与pngmath http sphinx pocoo org ext math html module sphinx ext pngmath扩展来记录我的代
  • GDK3/GTK3窗口更新的精确定时

    我有一个使用 GTK 用 C 语言编写的应用程序 尽管该语言对于这个问题可能并不重要 这个应用程序有全屏gtk window与单个gtk drawing area 对于绘图区域 我已经通过注册了一个刻度回调gtk widget add ti
  • 方法参数内的变量赋值

    我刚刚发现 通过发现错误 你可以这样做 string s 3 int i int TryParse s hello out i returns false 使用赋值的返回值是否合法 Obviously i is but is this th
  • 窗体最大化时自动缩放子控件

    有没有办法在最大化屏幕或更改分辨率时使 Windows 窗体上的所有内容自动缩放 我发现手动缩放它是正确的 但是当切换分辨率时我每次都必须更改它 this AutoScaleDimensions new System Drawing Siz
  • 将变量分配给另一个变量,并将一个变量的更改反映到另一个变量中

    是否可以将一个变量分配给另一个变量 并且当您更改第二个变量时 更改会瀑布式下降到第一个变量 像这样 int a 0 int b a b 1 现在 b 和 a 都 1 我问这个问题的原因是因为我有 4 个要跟踪的对象 并且我使用名为 curr
  • 将 viewbag 从操作控制器传递到部分视图

    我有一个带有部分视图的 mvc 视图 控制器中有一个 ActionResult 方法 它将返回 PartialView 因此 我需要将 ViewBag 数据从 ActionResult 方法传递到 Partial View 这是我的控制器

随机推荐

  • C 中的异或运算符

    在进行按位操作时 我在确定何时使用 XOR 运算符时遇到一些困难 按位与和或非常简单 当您想要屏蔽位时 请使用按位 AND 常见用例是 IP 寻址和子网掩码 当您想要打开位时 请使用包含或 然而 XOR 总是让我明白 我觉得如果在面试中被问
  • 如何在不声明新数据的情况下更改类型(String,Int)元组的 Ord 实例?

    我正在尝试对类型列表进行排序 String Int 默认情况下 它按字符串排序 然后按整数排序 如果字符串相等 我希望它是相反的 首先比较整数 然后如果相等则比较字符串 另外 我不想切换到 Int String 我找到了一种通过定义实例来实
  • 如何在 C++ BOOST 中像图形一样加载 TIFF 图像

    我想要加载一个 tiff 图像 带有带有浮点值的像素的 GEOTIFF 例如 boost C 中的图形 我是 C 的新手 我的目标是使用从源 A 到目标 B 的双向 Dijkstra 来获得更高的性能 Boost GIL load tiif
  • 限制C#中的并行线程数

    我正在编写一个 C 程序来生成并通过 FTP 上传 50 万个文件 我想并行处理4个文件 因为机器有4个核心 文件生成需要更长的时间 是否可以将以下 Powershell 示例转换为 C 或者是否有更好的框架 例如 C 中的 Actor 框
  • 如何在 Jquery/Javascript 中绑定模糊和更改,但只触发一次函数?

    我试图在选择元素更改时触发函数 由于 Ipad 在 on change 方面遇到问题 我还想绑定到 blur 这在 Ipad 上工作得很好 但是我不希望两个事件都触发该函数两次 所以我需要某种挂钩来确保两个事件是否都触发change and
  • 使用 z = f(x, y) 形式的 B 样条方法来拟合 z = f(x)

    作为一个潜在的解决方案这个问题 https stackoverflow com questions 76476327 how to avoid creating many binary switching variables in gekk
  • Ruby 中的 url_encode

    I read 的文档url encode http rdoc info stdlib erb 1 9 3 ERB Util 3Aurl encode 是否有一个表可以准确地告诉我哪个字符被编码为什么 使用url encode ERB s u
  • jolt变换后json对象的排序

    Input The input json object 所需输出 Event1 Value1 Event2 collection of json objects Event3 The input json object 所以基本上输入 js
  • AWS DynamoDB 写后读一致性 - 理论上它是如何工作的?

    大多数nosql解决方案仅使用最终一致性 并且考虑到DynamoDB将数据复制到三个数据中心 如何保持写后读一致性 解决此类问题的通用方法是什么 我认为这很有趣 因为即使在 MySQL 复制中 数据也是异步复制的 我将详细告诉您 Dynam
  • 张量流中的复杂卷积

    我正在尝试运行一个简单的卷积 但包含复数 r np random random 1 10 10 10 i np random random 1 10 10 10 x tf complex r i conv layer tf layers c
  • Kivy - 单击按钮时编辑标签

    我希望 Button1 在单击时编辑标签 etykietka 但我不知道如何操作 你有什么想法吗 class Zastepstwa App def build self lista WebOps getList layout BoxLayo
  • CGImage/UIImage 在 UI 线程上延迟加载会导致卡顿

    我的程序显示一个水平滚动表面 从左到右平铺有 UIImageViews 代码在 UI 线程上运行 以确保新可见的 UIImageView 分配有新加载的 UIImage 加载发生在后台线程上 一切工作几乎都很好 除了每个图像变得可见时出现口
  • 使用 AppleScript 运行另一个应用程序而不将其显示在扩展坞上

    使用 AppleScript 您可以创建运行另一个应用程序的脚本 然后将该脚本本身另存为应用程序并将其放置在 Dock 中 问题 不是真正的问题 是 当您单击它时 它仍然会在扩展坞上显示其他应用程序 是否可以阻止其他应用程序在扩展坞中显示
  • 防止索引超出范围错误

    我想编写对某些条件的检查 而不必使用 try catch 并且我想避免出现 Index Out of Range 错误的可能性 if array Element 0 Object Length gt 0 array Element 1 Ob
  • 如何在 PHP 中从字符串类名实例化? [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 如何创建返回方法名称的新实例 不幸的是我收到这个错误 错误 类名必须是有效的对象或字符串 这是我的代码 class Foo public f
  • Git 提交失败:“请使用 -m 或 -F 选项提供消息。”

    当我键入 git commit 命令来提交文件时 我收到以下错误消息 Microsoft Visual Studio 微软 找不到命令 错误 核心编辑器 Microsoft Visual Studio 存在问题 请使用 m 或 F 选项提供
  • 如何使用配置文件 (.ebextensions) 在 AWS Elastic Beanstalk 上安装 PHP IMAP 扩展?

    有谁知道如何使用配置文件 ebextensions 在 AWS Elastic Beanstalk 上安装和启用 PHP IMAP 扩展 我使用的是 64 位 Amazon Linux 2017 03 v2 4 0 运行 PHP 7 0 1
  • 使用随机放置的 NaN 创建示例 numpy 数组

    出于测试目的 我想创建一个M by Nnumpy 数组与c随机放置的 NaN import numpy as np M 10 N 5 c 15 A np random randn M N A mask np nan 我在创建时遇到问题mas
  • 使用 libcurl 检查 SFTP 站点上是否存在文件

    我使用 C 和 libcurl 进行 SFTP FTPS 传输 在上传文件之前 我需要检查文件是否存在而不实际下载它 如果该文件不存在 我会遇到以下问题 set up curlhandle for the public private ke
  • 使用按位运算符相乘

    我想知道如何使用按位运算符将一系列二进制位相乘 但是 我有兴趣这样做来查找二进制值的十进制小数值 这是我正在尝试做的一个例子 假设 1010010 我想使用每个单独的位 以便将其计算为 1 2 1 0 2 2 1 2 3 0 2 4 虽然我