‘壹’ 如何快捷计算大数乘法
首先,编程是最快的方法。
如果有计算器,可以将两个30 位的数自右侧起,每 7 位分割一次,
相当于把两个数转化为10000000 进制。
0000014 1592653 5897932 3846264 3383279
0000050 2884197 1693993 7510582 0974944
然后按照笔算乘法的规则,列竖式,把每个 7 位数当作一个 1 位数,
乘法和加法用前文提及的15位计算器计算。
比如最右侧一位就是 3383279*0974944 = (进位 0329850) 7561376
这样作 25 次乘法即可完成。
‘贰’ 如何实现大数相乘
网上搜的,评分较高的。
/*--------------------------------------------------------------------------
*函数名称: 大数乘法
*函数过程:1 输入两个大数作为字符串
* 2 作一个双向链表
* 3 两个指针分别指向数字字符串的最低位
* 4 以第一个数的最低的一个位乘以第二个数的所有项存于链表中
* 5 链表首指针移
* 6 重复4,5依次从最低位乘到最高位
* 7 乘完后因为最低位是链表首,最后一位是链表尾。所以在逆顺输出链表。
* 4 直到循环结束
*入口参数:numa,numb,result字符串
*出口参数:无
*--------------------------------------------------------------------------*/
void multiply(char *numa, char *numb ,char *result)//用来储结果的)//计算乘积
{
char *pna = findend(numa);//指向numa的一个指针。point numa pna 指向乘数的最低位,
char *pnb = findend(numb);//指向numb的一个指针 //pnb 指向被乘数的最低位,
int along=(int)strlen(numa);//标记数字a的长度;
int blong=(int)strlen(numb);//标记数字b的长度;
int carry=0,temp_result;//存贮进位 和临时结果的
Node *head, // 用于存贮头指针
*pstart, // 用于存贮计算时的首指针
*pnew, //作于申请新结点
*pgo; //作为每计算完一行时,回到下一行起始节点用,移位标致来用
head = pstart =new Node;//初始化首结点和头结点。
pstart -> data = 0;
pstart -> next = NULL;
pstart -> ahead = NULL;
while (along--)
{
pgo = pstart;//保存进位点
blong = (int)strlen(numb);//初始化长度
pnb = findend(numb); //初始化指针
while ((blong-- && (blong>=0))|| carry != 0)
{
if(!pstart->next)//如果当前为空结点,则申请新结点
{
pnew = new Node;
pnew -> data = 0;
pnew -> next = NULL;
pnew -> ahead = pstart;
pstart -> next = pnew;
}
if(blong<0)temp_result = carry ;//处理只有进位的情况
else temp_result =(pstart->data+(*pna-48)*(*pnb-48)+carry);//自身值+新值+进位作为新值
pstart -> data = temp_result%10; //存贮个位
carry = temp_result/10; //存贮进位
pstart = pstart -> next; //结点移动
pnb--; //指针移向被乘数高位
}
pstart = pgo->next; //前进一个位置;
pna--; //指针移向乘数高位
}
pstart =head;//寻找链表的结尾点
while(pstart->next != 0)
{
pstart->data += 48;//!!<<<因为我们的输出是字符。所以再此加上48>>>> 逆顺输出
pstart = pstart->next ;
}
int tip = 0;//转为字符串用
pstart = pstart->ahead ;//找有效字
while(pstart != 0)//输出正序的结果;
{
result[tip++] = pstart->data;
pstart = pstart->ahead ;
}
result[tip] = '\0';
pstart =head; //释放空间
while(pstart->next != 0)
{
pnew = pstart->next ;delete pstart;
pstart =pnew;
}
return ;
}
‘叁’ 大数相乘 快速算法
大数乘的最快算法是快速傅立叶变换法,这有一个,但不是我本人写的。
#include <iostream>
#include <cmath>
#include <complex>
#include <cstring>
using namespace std;
const double PI = acos(-1);
typedef complex<double> cp;
typedef long long int64;
const int N = 1 << 16;
int64 a[N], b[N], c[N << 1];
void bit_reverse_(cp a[], int n, cp b[])
{
int i, j, k, u, m;
for (u = 1, m = 0; u < n; u <<= 1, ++m);
for (i = 0; i < n; ++i)
{
j = i; k = 0;
for (u = 0; u < m; ++u, j >>= 1)
k = (k << 1) | (j & 1);
b[k] = a[i];
}
}
void FFT(cp _x[], int n, bool flag)
{
static cp x[N << 1];
bit_reverse_(_x, n, x);
int i, j, k, kk, p, m;
for (i = 1, m = 0; i < n; i <<= 1, ++m);
double alpha = 2 * PI;
if (flag) alpha = -alpha;
for (i = 0, k = 2; i < m; ++i, k <<= 1)
{
cp wn = cp(cos(alpha / k), sin(alpha / k));
for (j = 0; j < n; j += k)
{
cp w = 1, u, t;
kk = k >> 1;
for (p = 0; p < kk; ++p)
{
t = w * x[j + p + kk];
u = x[j + p];
x[j + p] = u + t;
x[j + p + kk] = u - t;
w *= wn;
}
}
}
memcpy(_x, x, sizeof(cp) * n);
}
void polynomial_multiply(int64 a[], int na, int64 b[], int nb, int64 c[], int &nc)
{
int i, n;
i = max(na, nb) << 1;
for (n = 1; n < i; n <<= 1);
static cp x[N << 1], y[N << 1];
for (i = 0; i < na; ++i) x[i] = a[i];
for (; i < n; ++i) x[i] = 0;
FFT(x, n, 0);
for (i = 0; i < nb; ++i) y[i] = b[i];
for (; i < n; ++i) y[i] = 0;
FFT(y, n, 0);
for (i = 0; i < n; ++i) x[i] *= y[i];
FFT(x, n, 1);
for (i = 0; i < n; ++i)
{
c[i] =(int64)(x[i].real() / n + 0.5);
}
for (nc = na + nb - 1; nc > 1 && !c[nc - 1]; --nc);
}
const int LEN = 5, MOD = 100000;
void convert(char *s, int64 a[], int &n)
{
int len = strlen(s), i, j, k;
for (n = 0, i = len - LEN; i >= 0; i -= LEN)
{
for (j = k = 0; j < LEN; ++j)
k = k * 10 + (s[i + j] - '0');
a[n++] = k;
}
i += LEN;
if (i)
{
for (j = k = 0; j < i; ++j)
k = k * 10 + (s[j] - '0');
a[n++] = k;
}
}
void print(int64 a[], int n)
{
printf("%I64d", a[--n]);
while (n) printf("%05I64d", a[--n]);
puts("");
}
char buf[N + 10];
int main()
{
int na, nb, nc;
while (scanf("%s", buf) != EOF)
{
bool sign = false;
if (buf[0] == '-')
{
sign = !sign;
convert(buf + 1, a, na);
}
else convert(buf, a, na);
scanf("%s", buf);
if (buf[0] == '-')
{
sign = !sign;
convert(buf + 1, b, nb);
}
else convert(buf, b, nb);
polynomial_multiply(a, na, b, nb, c, nc);
int64 t1, t2;
t1 = 0;
for (int i = 0; i < nc; ++i)
{
t2 = t1 + c[i];
c[i] = t2 % MOD;
t1 = t2 / MOD;
}
for (; t1; t1 /= MOD) c[nc++] = t1 % MOD;
if (sign) putchar('-');
print(c, nc);
}
return 0;
}
‘肆’ 乘法的简便方法
乘法的简便方法有:结合法,折数法,分解法,改数法。如计算下列算式:16×25×25
因为4×25=100,而16=4×4,由此可将两个4分别与两个25相乘,即原式可转化为(4×25)x(4×25)。
16×25×25=(4×25)x(4×25)
=100×100
=10000
‘伍’ 乘法简便计算的方法规律
乘法(multiplication),是指将相同的数加起来的快捷方式。其运算结果称为积,“x”是乘号。从哲学角度解析,乘法是加法的量变导致的质变结果。整数(包括负数),有理数(分数)和实数的乘法由这个基本定义的系统泛化来定义。
乘法也可以被视为计算排列在矩形(整数)中的对象或查找其边长度给定的矩形的区域。 矩形的区域不取决于首先测量哪一侧,这说明了交换属性。 两种测量的产物是一种新型的测量,例如,将矩形的两边的长度相乘给出其面积,这是尺寸分析的主题。
乘法是四则运算之一
例如4乘5,就是4增加了5倍率,也可以说成5个4连加。
使用铅笔和纸张乘数的常用方法需要一个小数字(通常为0到9的任意两个数字)的存储或查询产品的乘法表,但是一种农民乘法算法的方法不是。
将数字乘以多于几位小数位是繁琐而且容易出错的。发明了通用对数以简化这种计算。幻灯片规则允许数字快速乘以大约三个准确度的地方。从二十世纪初开始,机械计算器,如Marchant,自动倍增多达10位数。现代电子计算机和计算器大大减少了用手倍增的需要。
3×5表示5个3相加
5x3表示3个5相加。
注意:1.在如上乘法表示什么中,常把乘号后面的因数做为乘号前因数的倍数。
2.参见wiki中对乘数和被乘数的定义
另:乘法的新意义:乘法不是加法的简单记法
Ⅰ 乘法原理:如果因变量f与自变量x1,x2,x3,….xn之间存在直接正比关系并且每个自变量存在质的不同,缺少任何一个自变量因变量f就失去其意义,则为乘法。
在概率论中,一个事件,出现结果需要分n个步骤,第1个步骤包括M1个不同的结果,第2个步骤包括M2个不同的结果,……,第n个步骤包括Mn个不同的结果。那么这个事件可能出现N=M1×M2×M3×……×Mn个不同的结果。
Ⅱ 加法原理:如果因变量f与自变量(z1,z2,z3…, zn)之间存在直接正比关系并且每个自变量存在相同的质,缺少任何一个自变量因变量f仍然有其意义,则为加法。
在概率论中,一个事件,出现的结果包括n类结果,第1类结果包括M1个不同的结果,第2类结果包括M2个不同的结果,……,第n类结果包括Mn个不同的结果,那么这个事件可能出现N=M1+M2+M3+……+Mn个不同的结果。
以上所说的质是按照自变量的作用来划分的。
此原理是逻辑乘法和逻辑加法的定量表述。
法则
两数相乘,同号得正,异号得负,并把绝对值相乘。
运算定律
整数的乘法运算满足:交换律,结合律, 分配律,消去律。
随着数学的发展, 运算的对象从整数发展为更一般群。
群中的乘法运算不再要求满足交换律。 最有名的非交换例子,就是哈密尔顿发现的四元数群。 但是结合律仍然满足。
1.乘法交换律: ,注:字母与字母相乘,乘号不用写,或者可以写成·。
2.乘法结合律: ,
3.乘法分配律: 。
‘陆’ 乘法简便运算技巧
乘法简便运算方法
一、结合法
一个数连续乘两个一位数,可根据情况改写成用这个数乘这两个数的积的形式,使计算简便。
例1 计算:19×4×5
19×4×5
=19×(4×5)
=19×20
=380
在计算时,添加一个小括号可以使计算简便。因为括号前是乘号,所以括号内不变号。
二、分解法
一个数乘一个两位数,可根据情况把这个两位数分解成两个一位数相乘的形式,再用这个数连续乘两个一位数,使计算简便。
例2 计算:45×18
48×18
=45×(2×9)
=45×2×9
=90×9
=810
将18分解成2×9的形式,再将括号去掉,使计算简便。
三、拆数法
有些题目,如果一步一步地进行计算,比较麻烦,我们可以根据因数及其他数的特征,灵活运用拆数法进行简便计算。
例3 计算:99×99+199
(1)在计算时,可以把199写成99+100的形式,由此得到第一种简便算法:
99×99+199
=99×99+99+100
=99×(99+1)+100
=99×100+100
=10000
(2)把99写成100-1的形式,199写成100+(100-1)的形式,可以得到第二种简便算法:
99×99+199
=(100-1)×99+(100-1)+100
=(100-1)×(99+1)+100
=(100-1)×100+100
=10000
四、改数法
有些题目,可以根据情况把其中的某个数进行转化,创造条件化繁为简。
例4 计算:25×5×48
25×5×48
=25×5×4×12
=(25×4)×(5×12)
=100×60
=6000
把48转化成4×12的形式,使计算简便。
例5 计算:16×25×25
因为4×25=100,而16=4×4,由此可将两个4分别与两个25相乘,即原式可转化为:(4×25)×(4×25)。
16×25×25
=(4×25)×(4×25)
=100×100
=10000
‘柒’ 乘法的简便方法是什么
一、30以内的两个两位数乘积的心算速算
1、两个因数都在20以内,任意两个20以内的两个两位数的积,都可以将其中一个因数的”尾数”移加到另一个因数上,然后补一个0,再加上两“尾数”的积。例如:
11×11=120+1×1=121 12×13=150+2×3=156 13×13=160+3×3=169 14×16=200+4×6=224 16×18=240+6×8=288
2、两个因数分别在10至20和20至30之间对于任意这样两个因数的积,都可以将较小的一个因数的“尾数”的2倍移加到另一个因数上,然后补一个0,再加上两“尾数”的积。例如:
22×14=300+2×4=308
23×13=290+3×3=299
26×17=400+6×7=442
28×14=360+8×4=392
29×13=350+9×3=377
多位数乘法的快速计算方法如下:
1、 十几乘十几:口诀:头乘头,尾加尾,尾乘尾。例:12×14=?解: 1×1=12+4=62×4=812×14=168注:个位相乘,不够两位数要用0占位。
2、 头相同,尾互补(尾相加等于10):口诀:一个头加1后,头乘头,尾乘尾。例:23×27=?解:2+1=32×3=63×7=2123×27=621注:个位相乘,不够两位数要用0占位。
3、 第一个乘数互补,另一个乘数数字相同:口诀:一个头加1后,头乘头,尾乘尾。例:37×44=?解:3+1=44×4=167×4=2837×44=1628注:个位相乘,不够两位数要用0占位。
4、 几十一乘几十一:口诀:头乘头,头加头,尾乘尾。例:21×41=?解:2×4=82+4=61×1=121×41=861
5、 11乘任意数:口诀:首尾不动下落,中间之和下拉。例:11×23125=?解:2+3=53+1=41+2=32+5=72和5分别在首尾11×23125=254375注:和满十要进一。
乘法原理:
如果因变量f与自变量x1,x2,x3,….xn之间存在直接正比关系并且每个自变量存在质的不同,缺少任何一个自变量因变量f就失去其意义,则为乘法。
在概率论中,一个事件,出现结果需要分n个步骤,第1个步骤包括M1个不同的结果,第2个步骤包括M2个不同的结果,……,第n个步骤包括Mn个不同的结果。那么这个事件可能出现N=M1×M2×M3×……×Mn个不同的结果。
设 A是 m×n 的矩阵。
可以通过证明 Ax=0 和A'Ax=0 两个n元齐次方程同解证得 r(A'A)=r(A)
1、Ax=0 肯定是 A'Ax=0 的解,好理解。
2、A'Ax=0 → x'A'Ax=0 → (Ax)' Ax=0 →Ax=0
故两个方程是同解的。
同理可得 r(AA')=r(A')
另外 有 r(A)=r(A')
所以综上 r(A)=r(A')=r(AA')=r(A'A)
‘玖’ 大数乘法 用什么算法啊
大数乘法基本上是乘法竖式笔算的代码化。
基本功能有3个
1.
大数的数组表示。
2.
大数乘以小数,得到大数。
3.
大数加大数,得到大数。
对于1,其实就是int数组的每个元素存储若干位。比如每个元素保存4个十进制位。[0]存储个十百千,[1]存储万、十万、百万、千万,诸如此类。一个数组保存一个大数。因此需要一个额外的int变量记录当前数组用了多少个元素(类似于字符串长度)。
对于2,“小数”指的是能用一个int保存的数。注意这里只限4个二进制位(和1里提到的位数一致)。
比如1
2345
6789这个数字,[0]保存6789,[1]保存2345,[2]保存1。长度3。
这个大数乘以小数,比如9999,过程就是[0]
*
9999,即6789
*
9999
=
6788
3211,积的低四位(%10000)3211保存到积(大数)的[0],剩下6788的进位到[1]。
然后2345
*
9999
= 2344
7655,加上刚才进位上来的6788得到2345
4443,其中4443保存到积(大数)的[1]中,2345进位到[2]。
以此类推。
对于3,基本只要一个for,对位相加然后注意进位就行了。
大数乘以大数,其实就是第一个大数先乘以第二个大数的[0](大数乘小数,上面的2),得到一个大数a0;然后第一个大数乘以第二个大数的[1],又得到一个大数a1……最后再将a0、a1、……加起来(也就是大数加法,上面的3)。加的时候要注意,a1的[0]要和a0的[1]对齐,a2的[0]要和a1的[1]和a0的[2]对齐……这个也和我们竖式笔算一样。
ps:上面的算法基本上是“10000进制数”的计算方式。如果数组的每个元素只保存1个十进制位,那就是10进制数。之所以用10000进制,纯粹是程序员感觉上好一些。最有效的利用,是每个int保存2的15次方,也就是32768进制。要注意到,如果用10进制计算的话,程序的计算耗时会变成10000进制的16倍,也就是效率变成1/16。
ps2:用int数组的话,位数最多只能是4位。因为5位数相乘可能得到11位数,超出了int表示范围。