C语言 快速乘法与快速幂

关于快速乘

这里说的快速乘并不是计算两数的乘法, 而是计算 a * b % p
主要利用公式:

( a × b ) m o d    c = ( a m o d    c ∗ b m o d    c ) m o d    c (a×b) \mod c=(a \mod c * b \mod c) \mod c (a×b)modc=(amodcbmodc)modc
( a + b ) m o d    c = ( a m o d    c + b m o d    c ) m o d    c (a+b) \mod c=(a \mod c+ b \mod c) \mod c (a+b)modc=(amodc+bmodc)modc

计算a * b % p时, 若直接计算a * b可能会溢出, 所以会把乘法转为加法
每一步都进行mod运算, 这样会减小乘法计算中溢出的几率

将乘法转换为加法:

123 ∗ 567 = 123 ∗ 7 ∗ 1 0 0 + 123 ∗ 6 ∗ 1 0 1 + 123 ∗ 5 ∗ 1 0 2 123*567 = 123*7*10^0+123*6*10^1+123*5*10^2 123567=1237100+1236101+1235102

对于二进制来说同理:
6 ∗ 5 ( 二 进 制 101 ) = 6 ∗ 1 ∗ 2 0 + 6 ∗ 0 ∗ 2 1 + 6 ∗ 1 ∗ 2 2 6*5(二进制101) = 6*1*2^0+6*0*2^1+6*1*2^2 65(101)=6120+6021+6122

所以会得到快速乘的计算方法, 求幂同理

#include <stdio.h>

// 快速乘: a * b % p 
int mul_mod(int a, int b, int p)
{
    int r=0;
    while(b)
	{
        if(b&1) r=(r+a)%p;
        a=a*2%p;
		b>>=1; 
    }
    return r;
}

// 快速幂: a ^ b % p 
int pow_mod(int a, int b, int p)
{
	int r=1;
	while(b)
	{
		if(b&1) r=r*a%p;
		a=a*a%p;
		b=b>>1;
	}
	return r;
}

// 另一种计算快速幂方法, 与快速乘结合
int pow_mod2(int a, int b, int p)
{
	int r=1;
	while(b)
	{
		if(b&1) r=mul_mod(r, a, p);
		a=mul_mod(a, a, p);
		b=b>>1;
	}
	return r;
}

int main()
{
	// 12345678 * 12345678 会发生溢出
	printf("int类型大小: %d\n", sizeof(int));
	printf("快速乘: %d\n", mul_mod(12345678, 12345678, 1234));
	printf("普通乘: %d\n", 12345678*12345678%1234); // 溢出
	printf("快速幂: %d\n", pow_mod(12345678, 12345678, 1234)); // 溢出
	printf("方法二: %d\n", pow_mod2(12345678, 12345678, 1234));
	return 0;
}

总结

上面的计算结果为:

	int类型大小: 4
	快速乘: 200
	普通乘: 1144
	快速幂: 1118
	方法二: 1204

实际上 快速乘 还有 快速幂 这样的说法有一定误导性, 将乘法转换为加法, 幂转换为乘法并不一定能提高计算速度, 主要还是为了溢出的考虑, 更像是对大数的运算.

  • 8
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值