首页 > 其他分享 >大整数的乘法

大整数的乘法

时间:2022-11-28 20:01:26浏览次数:36  
标签:long BigNum parseLong Long b1 b2 整数 乘法


大整数的乘法

(这里主要讨论的是两个较大的数相乘的效率问题,实际上并不是真正意义上的大数相乘。在java中有个BigInteger类已经可以储存大数,并提供了大数相乘的方法了。)

【分析】

X、Y(位数分别为n、m)进行相乘时,我们可以将这两个整数分别进行分割。

n == m 并且 n 是2的幂,将n位的整数X和Y都分为2段,分别记为A、B和C、D。这时每段长为 n / 2位。

X = A10^(n/2) + B,Y = C10^(n/2) + D。

XY = AC10^n + ((A - B)(D - C) + AC + BD)10^(n/2) + BD。

T(n) = O(n^log3)。

 

       这里我们要考虑几个问题:

问题1:当n 不等于 m时,我们如何使得两个整数的位数保持相等又不影响结果呢?

0,此时并不会影响到最终的结果。

 

问题2:当我们用字符串存储这两个整数的时候,又应该如何考虑整数的符号问题呢?当出现负整数的时候,我们将要考虑到如何截取整数的问题。

BigNum类,用一个字符串类型存储这个整数的值,用一个int类型存储这个整数的符号。在创建对象的时候,如果字符串存储的是负整数,那么就应该将这个字符串截取出除符号外的部分来初始化这个对象的字符串属性,并且符号根据具体整数赋值1或0,1表示正整数,0表示负整数。

 

问题3:假如n不是2的幂,那我们应该怎么做呢?

0,直到这两个字符串的长度为奇数为止。

 

       此外,根据上述所提出来的公式

XY = AC10^n + ((A - B)(D - C) + AC + BD)10^(n/2) + BD

采用分治法设计算法,定义一个multi(BigNum x, BigNum y)方法,那么有以下伪代码:

BigNum multi(BigNum x, BigNum y) {

x和y的字符串属性(适当补0操作);

x的字符串为两段A和B、分y的字符串为两段C和D;

A、B、C、D创建相应的BigNum对象a, b, c, d;

计算AC的值;

AC进行后面补0的操作,相当于乘以10^n;

计算BD的值;

计算AC10^n + ((A - B)(D - C) + AC + BD)10^(n/2) + BD的值;

}

【程序】

用java语言编写程序,代码如下:

import java.util.Scanner;

public class BigIntMul {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);

while(input.hasNext()) {
String s1 = input.next();
String s2 = input.next();

BigNum b1 = new BigNum(s1);
BigNum b2 = new BigNum(s2);

BigNum r = multi(b1, b2);
String s = r.n == 0 ? "-" : "";
System.out.println(s + r.s);
}
}
//定义大整数类
static class BigNum {
String s;
int n;//存储大整数的正负号,1表示正,0表示负

//定义BigNum对象,根据字符串的值,定义符号
public BigNum(String s) {
if(s.charAt(0) == '-') {
n = 0;
this.s = s.substring(1, s.length());
}
else {
n = 1;
this.s = s;
}

if(Long.parseLong(s) == 0)
n = 1;
}
//定义BigNum对象,符号自定义
public BigNum(String s, int n) {
if(s.charAt(0) == '-')
this.s = s.substring(1, s.length());
else
this.s = s;
this.n = n;

if(Long.parseLong(s) == 0)
n = 1;
}

public BigNum() {
}

public int len() {
return s.length();
}
}
//初始化两个BigNum对象,使得两个对象的值位数相等,且位数为偶数。不足的话前面为补0,并返回长度。
//当两个数的长度相等,并且长度为1时,则直接返回长度值1
public static int init(BigNum b1, BigNum b2) {
int n;
int len1 = b1.s.length();
int len2 = b2.s.length();

if(len1 > len2) {
if(len1 % 2 != 0) {
b1.s = "0" + b1.s;
len1++;
}
n = len1;

for(int i = 0; i < len1 - len2; i++)
b2.s = "0" + b2.s;
}
else if(len1 < len2) {
if(len2 % 2 != 0) {
b2.s = "0" + b2.s;
len2++;
}
n = len2;

for(int i = 0; i < len2 - len1; i++)
b1.s = "0" + b1.s;
}
else {
if(len1 == 1)
return 1;

if(len1 % 2 != 0) {
b1.s = "0" + b1.s;
b2.s = "0" + b2.s;
len1++;
}
n = len1;
}

return n;
}

public static BigNum multi(BigNum b1, BigNum b2) {
int n = init(b1, b2);
//当两个数的长度为1时,直接让这两个数相乘,返回BigNum对象。
if(n == 1) {
BigNum r = new BigNum();
if((b1.n == 0 && b2.n == 1) || (b1.n == 1 && b2.n == 0))
r.n = 0;
else
r.n = 1;

long n1 = Long.parseLong(b1.s);
long n2 = Long.parseLong(b2.s);
r.s = (n1 * n2) + "";

if(n1 == 0 || n2 == 0)
r.n = 1;
return r;
}
//将整数分为两个数,且不论这个整数是否为正数或负数,都将分解出来的数的符号定义为正号。
//根据公式计算结果。
BigNum a = new BigNum(b1.s.substring(0, n / 2), 1);
BigNum b = new BigNum(b1.s.substring(n / 2, n), 1);

BigNum c = new BigNum(b2.s.substring(0, n / 2), 1);
BigNum d = new BigNum(b2.s.substring(n / 2, n), 1);

BigNum ac = multi(a, c);
BigNum bd = multi(b, d);

long aa1 = /*a.n == 0 ? (-1) * Long.parseLong(a.s) : */Long.parseLong(a.s);
long bb1 = /*b.n == 0 ? (-1) * Long.parseLong(b.s) : */Long.parseLong(b.s);
long a_bl = aa1 - bb1;
BigNum a_b = new BigNum(a_bl + "");

long dd1 = /*d.n == 0 ? (-1) * Long.parseLong(d.s) : */Long.parseLong(d.s);
long cc1 = /*c.n == 0 ? (-1) * Long.parseLong(c.s) : */Long.parseLong(c.s);
long d_cl = dd1 - cc1;
BigNum d_c = new BigNum(d_cl + "");

BigNum abcd = multi(a_b, d_c);

BigNum r1 = new BigNum(ac.s);
for(int i = 0; i < n; i++) {
r1.s = r1.s + "0";
}

long labcd = abcd.n == 0 ? (-1) * Long.parseLong(abcd.s) : Long.parseLong(abcd.s);
long lac = ac.n == 0 ? (-1) * Long.parseLong(ac.s) : Long.parseLong(ac.s);
long lbd = bd.n == 0 ? (-1) * Long.parseLong(bd.s) : Long.parseLong(bd.s);
long lr2 = labcd + lac + lbd;
BigNum r2 = new BigNum(lr2 + "");

for(int i = 0; i < n / 2; i++)
r2.s = r2.s + "0";

long lr3 = lac * (long)(Math.pow(10, n)) + lr2 * (long)(Math.pow(10, n / 2)) + lbd;
BigNum r3 = new BigNum(lr3 + "");
if((b1.n == 0 && b2.n == 1) || (b1.n == 1 && b2.n == 0))
r3.n = 0;
else
r3.n = 1;

if(lr3 == 0)
r3.n = 1;

return r3;
}
}

运行结果如下:


大整数的乘法_递归


标签:long,BigNum,parseLong,Long,b1,b2,整数,乘法
From: https://blog.51cto.com/u_15894233/5893619

相关文章

  • 【C语言】实现两个整数相加
    用C语言实现两个整数相加1.首先出于目的我们需要输入两个整数和输出两个整数相加的值,需要用到printf()函数所以需要引头文件stdio.h#include<stdio.h>2.声明两个整形......
  • 【白话模型量化系列一】矩阵乘法量化
    模型量化是模型加速方向一个很重要的方法,主要思想就是用int8数据格式来存储和进行计算。这样做有两点好处:可以减小模型存储的体积。原本float32存储需要4个字节,现在int8存储......
  • 补码4×4阵列乘法器设计
    视频讲解:https://www.bilibili.com/video/BV1ye4y1H7Ao/一、简述乘法运算在全部算数运算中大约占据三分之一,因此采用高速乘法部件,无论从速度上还是效率上,都十分必要。本......
  • mul乘法指令
    assumecs:code,ss:stackstacksegmentdb16dup(0)stackendscodesegments:moval,5movbl,3ret;returntoblockclodebeh......
  • 一种计算整数位1个数的新方法
    tags:DSAPython前言最近看阮一峰老师的每周科技周刊,发现一个有意思的算法​​1​​,具体的方法文章中都写了,不过这里还是介绍一下具体的思路以及其Python版的实现.算......
  • 九九乘法表
    #include<iostream>usingnamespacestd;intmain(intargc,char**argv){ for(inti=1;i<=9;i++){ for(intj=1;j<=i;j++){ cout<<j<<"*"<<i<<"="<<j*i<<"";......
  • 九九乘法表
    publicclassMath1{//九九乘法表publicstaticvoidmain(String[]args){//需要输出九行for(inti=1;i<=9;i++){//......
  • 九九乘法表
    这边提供了两种格式可自行选择#include<stdio.h>intmain(){intn=1;intm=1;intz=0;for(n=1;n<=9;n++){for(m=1;m<=n;m++){prin......
  • 实现字符串转整数
    inttonum(char*str)//-1代表失败{char*istr=str;//保留副本intnum=0;while(*str!='\0'){if((*str)<'0'||(*str)>'9'){......
  • 整数二分查找
    总的来说使用二分的条件:具有单调性注意:二分的思想看似简单,但其实很容易出错整数二分模板以单调递增序列的二分为例给出两个模板:在单调递增序列中找到x或x的后继(大于......