181 lines
3.3 KiB
C++
181 lines
3.3 KiB
C++
/*
|
|
LA: linear algebra C++ interface library
|
|
Copyright (C) 2008-2023 Jiri Pittner <jiri.pittner@jh-inst.cas.cz> or <jiri@pittnerovi.com>
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "numbers.h"
|
|
|
|
|
|
namespace LA {
|
|
|
|
template<typename N>
|
|
N primefactor(const N &x, const N &last)
|
|
{
|
|
N i,t;
|
|
if ( x <= 2 ) return x;
|
|
if ( !(x & 1) ) return 2;
|
|
i = last >3 ? last : 3;
|
|
for (;;) {
|
|
t = x / i;
|
|
if ( t < i ) break;
|
|
if ( t * i == x )
|
|
return i;
|
|
i += 2;
|
|
}
|
|
return x;
|
|
}
|
|
|
|
|
|
template<typename N>
|
|
FACTORIZATION<N> factorization(const N &x)
|
|
{
|
|
FACTORIZATION<N> f;
|
|
N y=x;
|
|
N last=0;
|
|
while(y>1)
|
|
{
|
|
N z=primefactor(y,last);
|
|
if(z!=last)
|
|
{
|
|
std::pair<N,N> p;
|
|
p.first=z;
|
|
p.second=1;
|
|
f.push_back(p);
|
|
}
|
|
else
|
|
++f.back().second;
|
|
last=z;
|
|
y/=z;
|
|
}
|
|
return f;
|
|
}
|
|
|
|
|
|
template<typename N>
|
|
N nextprime(N x)
|
|
{
|
|
if ( x < 2 ) return 2;
|
|
if ( !(x & 1) ) x--;
|
|
while ( !isprime(x += 2) );
|
|
return x;
|
|
}
|
|
|
|
|
|
template <typename N>
|
|
std::ostream & operator<<(std::ostream &s, const FACTORIZATION<N> &x)
|
|
{
|
|
for(auto p=x.begin(); p!=x.end(); ++p) s<<"("<<p->first<<","<<p->second<<") ";
|
|
return s;
|
|
}
|
|
|
|
|
|
template <typename N>
|
|
N eulerphi(const FACTORIZATION<N> &x)
|
|
{
|
|
N e=1;
|
|
for(auto p=x.begin(); p!=x.end(); ++p)
|
|
{
|
|
e *= (p->first-1);
|
|
if(p->second>1) e*= pow(p->first, p->second-1);
|
|
}
|
|
return e;
|
|
}
|
|
|
|
|
|
template <typename N>
|
|
N pow(const N &x, N i)
|
|
{
|
|
if(i==0) return 1;
|
|
if(i==1) return x;
|
|
N y,z;
|
|
z=x;
|
|
while(!(i&1))
|
|
{
|
|
z = z*z;
|
|
i >>= 1;
|
|
}
|
|
y=z;
|
|
while((i >>= 1)/*!=0*/)
|
|
{
|
|
z = z*z;
|
|
if(i&1) y = y*z;
|
|
}
|
|
return y;
|
|
}
|
|
|
|
|
|
//avoiding overflow which would occur very soon in (x*y)%m
|
|
template <typename N>
|
|
N multmod(N x, N y, const N &m)
|
|
{
|
|
N sum=0;
|
|
if(y==0) return 0;
|
|
while(x)
|
|
{
|
|
if(x&1) sum= (sum+y)%m;
|
|
x>>=1;
|
|
y = (y<<1)%m; //still can overflow here but for much larger numbers
|
|
}
|
|
return sum;
|
|
}
|
|
|
|
|
|
|
|
template <typename N>
|
|
N powmod(const N &x, N i, const N &m)
|
|
{
|
|
if(i==0) return 1;
|
|
if(i==1) return x%m;
|
|
N y,z;
|
|
z=x%m;
|
|
while(!(i&1))
|
|
{
|
|
z = multmod(z,z,m);
|
|
i >>= 1;
|
|
}
|
|
y=z;
|
|
while((i >>= 1)/*!=0*/)
|
|
{
|
|
z = multmod(z,z,m);
|
|
if(i&1) y = multmod(y,z,m);
|
|
}
|
|
return y;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//force instantization
|
|
|
|
#define INSTANTIZE(N) \
|
|
template N primefactor(const N &x, const N &last); \
|
|
template FACTORIZATION<N> factorization(const N &x); \
|
|
template N nextprime(N x); \
|
|
template std::ostream & operator<<(std::ostream &s, const FACTORIZATION<N> &x); \
|
|
template N pow(const N &x, N i); \
|
|
template N powmod(const N &x, N i, const N &m); \
|
|
template N multmod(N x, N i, const N &m); \
|
|
template N eulerphi(const FACTORIZATION<N> &f); \
|
|
|
|
|
|
|
|
|
|
|
|
INSTANTIZE(uint64_t)
|
|
|
|
}//namespace
|