LA_library/numbers.cc

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