求 a的b次方对c求余 的结果

求 a的b次方对c求余 的结果,其中a b c都是非负整数

求 a的b次方 最简单的方法是
    s = 1;
    for( i=0; i!=b; ++i ) s*=a;
    return s;
这个算法效率太低,假如只能想到这个算法,出门别说自己是搞软件的^_^
考虑到 a^b = (a的平方)^(b的一半) 这个公式,可以写成
    if(b==0) return 1;
    if(b==1) return b;
    s = 递归( a*a, b/2 );
    if(b%2==1) s*=a;
    return s;
这个递归算法在long long取值范围内,最多递归64次,是可以接受的。
追求完美的人是不用递归的
    递归时 a^21 = (a^2)^10 * a = ((a^2)^2)^5 * a = ((a^2)^2)^2 * ((a^2)^2) * a
    从中可以看出是不是需要再多乘一个自身,取决于21的二进制10101中对应bit是否为1
即算法为:
    s = 1;
    for( t=a; b; t*=t,b>>=1 ) if(b&1)s*=t;
    return s;
写得完整点是:

typedef  unsigned   int  T;
T foo( T a, T b ) // 求a的b次方
{
    T s 
=   1 ;
    
for ( T t = a; b; t *= t,b >>= 1  )
    
{
        
if ( (b & 1 !=   0  )
            s 
*=  t;
    }

    
return  s;
}


在上述所有代码中,都用到乘法运算,即数据可能溢出
解决方法是通过公式 (a*b)%c = ( a%c * b%c )%c 使中间值(即a%c,b%c)保持在一定范围内。
估计这个公式是题目唯一的考点,假如a,b在uint64_t范围内取值,那么c可以在uint32_t范围内取值而不出现溢出
所以我窃以为题目没写完整,应该有个对c取值范围的限制

假如对c不作限制,我将(a*b)%c转化为(a+a+a+……共b个)%c,用(a+b)%c=(a%c+b%c)%c使得中间值(即a%c,b%c)保持在一定范围内。
此时只要保证(a+b)%c不溢出就行了,我搞了好久,算法都不简洁,给出两个差强人意的算法
    if(a+b>=a) return (a+b)%c;
    return (a%c+b%c-c);
这个算法要点在于,形如a+b-c,如果最终结果不溢出,则不会因为a+b临时溢出而使最终结果变得错误。
    if(a+b>=a) return (a+b)%c;
    return ((a+b)%c + m%c + 1)%c;
式中m指类型的最大值,比如uint32_t是0xFFFFFFFFu,可以用uint32_t(-1)来表示
(
    求证 a<=m, b<=m, c<=m 时 (a+b)%c + m%c + 1 <= m
    因为 (a+b)%c+1 最大值为 c
    所以只需要求证 c + m%c <= m
    设 m = n*c + d,其中n>=1,d<c,则上式变为
    c + (n*c+d)%c <= n*c + d;
    c + d <= n*c + d;
    1<=n
)

最终代码是:

//  typedef unsigned long long T;
typedef unsigned   int  T;

T MyPlus( T a, T b, T c ) 
//  (a+b)%c
{
    
if (a + b >= a)  return  (a + b) % c;  //  不溢出
     return  (a % c + b % c - c);
}


T MyMultiplies( T a, T b, T c ) 
//  (a*b)%c
{
    
if (a * b / a == b)  return  (a * b) % c;  //  不溢出

    T s 
=   0 ;
    
for ( T t = a; b; t = MyPlus(t,t,c),b >>= 1  )
    
{
        
if ( (b & 1 !=   0  )
            s 
=  MyPlus(s,t,c);
    }

    
return  s;
}


T MyPower( T a, T b, T c ) 
//  (a^b)%c
{
    T s 
=   1 ;
    
for ( T t = a; b; t = MyMultiplies(t,t,c),b >>= 1  )
    
{
        
if ( (b & 1 !=   0  )
            s 
=  MyMultiplies(s,t,c);
    }

    
return  s;
}


#include  
< iostream >
int  main( void )
{
    std::cout 
<<  MyPower( 79 , 13 , 127 <<  std::endl;  //  26

    
return   0 ;
}


不怎么好验证,所以没测试

进一步,windy0will 说 a^b%c 的结果具有周期性。
但我没找到合适的算法求得这个周期,以及周期开始处

 

http://blog.vckbase.com/bruceteen/archive/2010/07/15/50550.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值