Java利用位运算实现乘法运算详解

作者:Java星辰 时间:2023-03-19 20:29:24 

前言

在上一篇中,我们介绍了使用位运算实现加法和减法运算,接下来本文主要介绍如何用位运算实现乘法运算,在实现乘法时要用位运算实现,并且不能出现加减乘除任何符号。

之前介绍过一篇如何用位运算实现加法和减法: 如何用位运算实现加减运算?

在用位运算实现之前,我们先来回忆一下小学时,学乘法时用的十字相乘法。

十进制相乘

例如,26 * 15,在进行乘法操作时,我们一般这样算,先用5乘以6得到30,把0写下把3记在一边,再用5乘以2得到10再加上之前的3写在下面,得到130;计算完5再计算1分别乘以62把得到的结果26记在下面,然后把13026相加(有错位)得到390

Java利用位运算实现乘法运算详解

二进制相乘

看完了十进制的相乘,再来看下二进制的相乘,基本原理是一样的,也是以十字相乘法为例,计算 5 * 7

5的二进制为1017的二进制为111,来看下二进制的十字相乘法。

Java利用位运算实现乘法运算详解

可以看到二进制为101和二进制111用传统的方式来计算,得到的结果为100011,而二进制100011对应的十进制为35
所以说,在计算的过程中,十进制和二进制的计算方式是一样的,当然这里就不进行举例和证明了。

思路分析

既然计算过程有了,那么怎么样用代码来实现呢?

我们再来看下上图中二进制的计算过程:

  • 先用二进制111的最后一位1 乘上 101 得到 101

  • 再用二进制111的倒数第2位1 乘上 101 得到 101

  • 再用二进制111的倒数第3位1 乘上 101 得到 101

  • 得到的三个101进行二进制相加,得到 100011

注意,第2步和第3步得到的结果101都往前挪了一位,相当于101010100,也就是最后相加的计算为:10100 + 1010 + 101 = 100011

再来看得到最终相加的计算10100 + 1010 + 101 = 100011,也就是只要我们找到如何把数据转换为几位数的相加就可以了,因为之前已经实现了如何用位运算实现加法操作。

这三个数101101010100的数量刚好与二进制111的个数相同,也就是二进制(上图下面那个乘数111)有几位就会产生几个数相加,如果是与11111相乘就会产生5个数相加。

再来看数据之前的关系:

  • 第一次相乘结果:101 = 101 + 0

  • 第二次相乘结果:1111 = 101 < 1 + 101 = 1010 + 101

  • 第三次相乘结果:100011 = 101 < 2 + 1111 = 10100 + 1010 + 101

从这里我们可以看到,每计算一次,101只需要向左移一次再加上上一次的计算结果就可以了。

那么,怎么知道要左移多少次呢?从这里例子中看,111每次计算后,向右移动一次,101也跟着向左移动一次,直到111只剩最后一位,则停止计算就好了。

代码实现

根据上面的思路,来实现一下代码:

// 用位运算实现加法
public static int add(int a, int b) {
   int sum = 0;
   while (b != 0) {
       sum = a ^ b;
       b = (a & b) << 1;
       a = sum;
   }
   return sum;
}

// 用位运算实现减法
public static int multi(int a, int b) {
   int res = 0;
   while (b != 0) {
       if ((b & 1) != 0) {
           res = add(res, a);
       }
       a <<= 1;
       b >>>= 1;
   }
   return res;
}

运行一下代码,看下结果:

Java利用位运算实现乘法运算详解

可以看到计算是正确的,而且还支持负数。

来源:https://juejin.cn/post/7221113101591445565

标签:Java,位运算,乘法
0
投稿

猜你喜欢

  • 简述Java中的四种引用类型

    2023-11-29 00:46:56
  • Spring注解驱动之BeanDefinitionRegistryPostProcessor原理解析

    2023-11-24 23:24:21
  • Android UI实现底部切换标签fragment

    2023-03-17 10:16:59
  • .net使用Aspose.Words进行Word替换操作的实现代码

    2023-03-23 21:28:59
  • c#多进程通讯的实现示例

    2022-09-06 02:43:23
  • Java集合ArrayList与LinkedList详解

    2022-11-11 12:14:31
  • Springboot通过谷歌Kaptcha 组件生成图形验证码功能

    2021-07-24 23:42:47
  • Springmvc返回html页面问题如何解决

    2021-07-05 09:29:45
  • Android 快速实现防止网络重复请求&按钮重复点击的方法

    2023-08-29 17:31:45
  • 详解Spring框架下向异步线程传递HttpServletRequest参数的坑

    2021-05-31 04:45:21
  • Flutter进阶之实现动画效果(九)

    2023-04-11 12:20:06
  • Java equals 方法与hashcode 方法的深入解析

    2022-03-05 19:20:15
  • Java两种常用的随机数生成方式(小白总结)

    2023-02-16 16:54:19
  • Android中单例模式的一些坑小结

    2021-11-02 22:33:11
  • 一文让你搞懂如何手写一个redis分布式锁

    2023-11-29 02:46:30
  • c# 组合模式

    2022-07-07 09:04:09
  • redisson实现分布式锁原理

    2023-11-29 00:00:00
  • java编程约瑟夫问题实例分析

    2022-04-05 22:32:08
  • 深入剖析Android系统中Service和IntentService的区别

    2023-06-29 17:55:16
  • JAVA IO API使用详解

    2021-07-27 14:45:48
  • asp之家 软件编程 m.aspxhome.com