BC number theory programs
BC (version 1.06) (see the manual) is a language that supports arbitrary precision
integer arithmetic calculations with interactive execution of statements.
It is an idiosyncratic programming language which closely resembles parts
of the C language. While it is somewhat slow for some purposes (all code is
executed as it is read), the author has found bc very useful in
teaching and research. The code is very easy to read and students can see
directly how an algorithm has been implemented. It is also useful as a template
for harder-to-write, but faster C code.
bc-1.06 is a superior version of the basic bc program which comes with the UNIX operating system.
To run a bc program such as gcd below, type bc gcd.
This loads the bc program and the bc program gcd.
As a calculator, bc has a number of standard functions eg.
5+3, 5*3, 5/3, (=integer part), 5%3, (=least remainder), 5^3, sqrt(n).
global array variables can be entered: m[0]=5;m[1]=3;m[2]=7
Typing z=lcma(m[ ],3) and then z, prints and stores z, the
lcm of 5, 3 and 7.
Consult the bc manual for more information.
Bugs and idiosyncrasies:
- When using the if-else construction, insert a "\", as follows:
if(expression){statement1}\
else{ statement2}
Alternatively, as pointed out by Anton Stiglic, use the construction
if(expression){
statement1
}else{
statement2
}
- There is a bug in bc-1.06 under some Solaris platforms, which causes my program squareroot below to give a bus error, though not under linux. Hopefully the bug will not be present when bc-1.07 is released.
- The maximum number of auto variables allowed in a bc function seems to be 24!
- The continue statement only works for for loops.
BC PROGRAMS WRITTEN BY KEITH MATTHEWS
These are downloadable as a gzipped tar file.
They may contain bugs, both on the algorithmic and programming side.
- gcd:
- sign(n).
- abs(n).
- mod(a,b), (b > 0): returns a(mod b).
- int(a,b): returns the integer part of a/b, b nonzero.
- gcd(m,n).
- gcd1(m,n): gcd(m,n)=gcd1(m,n)·m+gcd2(m,n)·n.
- gcd2(m,n).
- lcm(m,n).
- inv(a,n): returns the inverse of a mod m.
- cong(a,b,m): solves ax ≡ b (mod m).
- chinese(a,b,m,n): solves x ≡ a(mod m) and x ≡ b(mod n).
- gcda(m[],n): finds gcd(m[0],...,m[n-1]) and expresses it
as a linear combination of m[0],...,m[n-1].
- lcma(m[],n): finds lcm(m[0],...,m[n-1]).
- chinesea(a[],m[ ],n): solves x ≡ a[i](mod m[i]), i=1,...,n-1.
- chineseb(a[],b[],m[],n): solves a[i]x ≡ b[i](mod m[i]),
i=1,...,n-1.
- mpower(a,b,c): returns ab (mod c).
- exp(a,b): returns ab.
- mthroot(a,b,m): returns the integer part of the mth-root of a/b.
Here a,b and m are positive integers, m > 1. (See K.R. Matthews, Computing mth roots, College Mathematics Journal 19 (1988) 174-176.)
- mthrootr(a,b,m,r): this gives the mth-root of a/b
truncated to r places.
- binomial(n,m): returns the binomial coefficient.
- gcd3(a,b,c): returns gcd(a,b,c).
- euclid: euclid(m,n) performs Euclid's algorithm.
- euclid1: euclid(m,n) returns the length of Euclid's algorithm.
- jacobi:
- jacobi(m,n) calculates the Jacobi symbol
- peralta(a,p) finds a square root of a quadratic
residue a mod p, using an algorithm of Rene Peralta.
- serret: serret(p) expresses a prime of the form
4n+1 as the sum of two squares using Serret's algorithm.
- 3x+1: collatz(n) tests the 3x+1 conjecture.
- 3x+371: s(n) tests the 3x+371 conjecture.
- phi: (slow-uses Brent-Pollard only)
- omega(n) returns the number of distinct prime factors of n.
- phi(n) returns the value of Euler's function.
- tau(n) returns the number of divisors of n.
- sigma(n) returns the sum of the divisors of n.
- mu(n) returns the value of the Mobius Function.
- lprimroot(p) returns the least primitive root mod p.
- orderm(a,m) returns the order of a mod m.
- factors: factor(n) attempts to factor n using
Brent-Pollard (slow).
- lucas: lucas(n) performs the strong base 2
pseudoprime test and Lucas pseudoprime test on n.
(Needs jacobi).
- decimal: period(m,n,b) outputs the period
digits of the base b expansion of m/n, where m,n,b (b > 1) are
positive integers, 1≤m < n.
- pell: pell(d,e) finds the least solution of Pell's
equations x2-d*y2=±1,±2,±3 and least primitive solution of x2-d*y2=±4. If e=1, the complete and partial quotients are printed; if e=0, this detail is suppressed.
- surd: surd(d,t,u,v) finds the continued fraction
expansion of a quadratic irrational (u+t*sqrt(d))/v, where d > 1 is not a square, t,u,v integers, v nonzero.
- unit: unit(d) finds the fundamental unit of
Q(sqrt(d)).
- fibonacci: f(m,n) prints the Fibonacci numbers
F(m),...,F(n). l(m,n) prints the Lucas numbers L(m),...,L(n).
- rootd: root(d) finds the continued fraction
expansion of sqrt(d).
- cfrac: cfrac(m,n) finds the continued fraction
expansion of m/n.
- proth: proth(h,m) investigates the primality of
h*2m+1, h < 2m, using Proth's test.
(Needs jacobi,lucas).
- pollard: pollard(n) attempts to find a factor
of n using the Pollard p-1 method.
- 3branch: s(n) tests a 3-branched generalized 3x+1
conjecture.
- challenge: s(n) tests another 3-branched
generalized 3x+1 conjecture.
- mordell: f(a,k) finds the integer solutions of
y2=x3+a with x ≤ k. (Needs gcd.)
- venturini1: s(n) tests a 6-branched generalized
3x+1 function of G. Venturini.
- lra: (needs gcd)
- lnearint(m,n) returns the (left) nearest integer to m/n.
- rnearint(m,n) returns the (right) nearest integer to m/n.
- lmodd(m,n) returns the (left) least remainder of sign(n)m mod |n|.
- rmodd(m,n) returns the right) least remainder of sign(n)m mod |n|.
- lra(m,n) performs the least remainder algorithm on m, n.
- nicf(m,n) prints the nearest integer continued fraction of m/n:
m/n = [a0 - 1/a1 - ··· - 1/an].
We write this as (a0,a1,...,an).
- convergents: pn(a[],n) and qn(a[],n) compute the numerator and denominator of the continued fraction [a[0];a[1],...,a[n]].
- lagrange: lagrange(a[],n,m)
uses the method of Lagrange (1797) to find the first m+1 partial
quotients of t, where f(x)=a[n]xn+···+a[0], a[n] > 0, is a polynomial with integer coefficients, having no rational roots
and having exactly one real positive root t, this being > 1.
- lupei: s(n) tests Lu Pei's 3-branched generalized 3x+1 mapping.
- recursion (Recursive bc programs)
- fib(n): returns the nth Fibonacci number, n ≥ 0.
- luc(n): returns the nth Lucas number, n ≥ 0.
- fac(n): returns factorial(n) if n ≥ 1.
- tonelli: x=tonelli(a,p) returns a square root of a (mod p), deterministically.
- discrete_log: r=shanks(n,g,p).
Here g is a primitive root (mod p) and gr ≡ n (mod p), 0 ≤ r < p-1.
Note: p < 232-216=4294901760, in order to satisy BC array upper bound length of 216-1.
If r does not exist, we return -1.
We use Shanks' giant steps-baby steps approach as described in Algorithmische Zahlentheorie by Otto Forster, pp 65-66.
- forster_log: r=shanks(n,g,p).
Similar to discrete_log, except that p is no longer necessarily a prime. Now needs phi to provide orderm(a,m).
- leastqnr: leastqnr(p) returns np, the least quadratic nonresidue mod p. (Needs gcd).
- rootd_modn: rootd_modn(d,n) finds all solutions of the congruence x2 ≡ d (mod n) with 0 ≤ x ≤ n/2 for small n.
- thue: Here d>1, is not a square, n > 1 an odd integer not dividing d-1. u2 ≡ d (mod n), 1 < u < n. Then thue(d,u,p) finds x,y such that x2-dy2=kn, with small k.
- sqroot: sqroot(d,n), n > 1, finds all solutions of x2 ≡ d (mod n). It returns -1 if there is no solution, otherwise returns the number of solutions (mod n).
- tomas1 and tomas2: These are generalised 3x+1 examples studied by Tomás Oliveira e Silva, where all trajectories are eventually periodic.
- log: log(a,b,d,r,e) performs a discrete variant of Shank's logba algorithm. Here 1 < r is an integer. Also d > 1. We do not guarantee the correctness of the output. Bigger (d,r) give more partial quotients. e=1 prints the A[i] and AA[i], while e=0 prints only the m[i] and mm[i]. See paper.
I suggest the user runs test(a,b,d,m,n), over a range (m,n), where m ≤ n, to get an idea of the correct partial quotients. This
runs log1(a,b,d,r) for r=m,...,n.
To get an idea of the correct answer when m=n=r, we recommend taking m=r-t, n=r+t, with 1 ≤ t ≤ (say) 2.
- base: f(b,n), n > 0, b > 1, gives the base b expansion of n.
- perfect_power: perfect_power(n) produces 0 if n is not a perfect power; otherwise returns x and p, where n=xp and p is the least prime with this property.
- primes: primes(m,n) prints the primes in the interval [m,n], if ma and n lie between 1 and 1010.
- nprime: nprime(m) finds the least Lucas-base2 strong pseudoprime p satisfying p ≥ m.
- nprimeap: nprimeap(m,a,b) finds the least Lucas-base2 strong pseudoprime p of the form p=ak+b and satisfying p ≥ m. Here 0 < b < a and gcd(a,b)=1.
- sturm: sturm(a[],n,b,e) prints a sturm polynomial sequence for the (squarefree) polynomial a[n]xn+···+a[0], evaluates the sequence at x=b and calculates its sign variation. e=0 suppresses printing.
- john: johna(b[],n) takes an array of positive integers b[0],...,b[n-1] and replaces them by an array of positive integers a[0],...,a[n-1], where
- a[i] divides b[i] for 0 ≤ i < n;
- gcd(a[i],a[j])=1 for 0 ≤ i < j< n;
- lcm(b[0],...,b[n-1])=a[0]·a[1]···a[n-1].
john(a,b) does the case n=2.
The program is due to John Campbell. Needs the program gcd.
- reducepos: reduce(a,b,c) takes as input an indefinite binary quadratic form ax2+bxy+cy2 and uses the PQa algorithm to find a cycle of reduced forms. (See explanation.)
- classnoneg: class_number(d,flag,table_flag) lists the reduced binary quadratic forms of negative discriminant d and returns their number h(d) if flag=0. If flag=1, only the primitive forms are counted. Only the class number is printed if table_flag=0.
If d is the discriminant of an imaginary quadratic field K, then the primitive forms class-number h(d) is also the class number of K.
Algorithm 5.3.5 of Henri Cohen's A course in computational algebraic number theory is used.
table(m,n) prints h(-d) for all squarefree d in the range m ≤ d < n,
where n<106.
- reduceneg: reduce(a,b,c) takes as input a positive definite binary quadratic form ax2+bxy+cy2 and uses an algorithm of Gauss to find the equivalent reduced form and unimodular transforming matrix.
- classnopos: class_number(d) (1 < d < 106 and squarefree) finds the class number of the real quadratic field Q(
) and the sign of the fundamental unit. A list of reduced binary quadratic forms corresponding to the ideal classes is also given.
table(m,n) prints h(d) for all squarefree d in the range m ≤ d < n,where n < 106.
class_number0(d) (d > 0, not a perfect square and 0 or 1 (mod 4))
returns the class-number of binary quadratic forms of discriminant d. Also the solubility of x2-d*y2=-4 is determined.
This is basically the same program as class_number(d), except that in
the case of non-solubility of x2-d*y2=-4, we count the form (-a,b,c) as well as (a,b,c), a > 0 and this means we return twice the value that class_number(d) would otherwise have returned. Regarding this point, see G.B. Mathews, Theory of Numbers, pp. 80-81.
- unimodular: unimodular(p,q,r,s) expresses a unimodular matrix A ≠ I2 or U=[0,1,1,0] with non-negative coefficients, as a product of one of the following forms:
P, UP, PU, or UPU, where P is a product of matrices of the form Ua=[a,1,1,0], a>0.
The representation is unique. See Kjell Kolden, Continued fractions and linear substitutions, Arch. Math. Naturvid. 50 (1949), 141-196.
The number n of matrices in the product U0
Un-1 is returned.
- binomial: binomial_p(n,k,p) finds the power of a prime p dividing the binomial coefficient
.
binomial(n,k) prints the prime power factorization of the binomial coefficient
.
- factorial: factorial_p(n,p) finds the power of a prime p dividing n!
factorial(n) finds n!
- p-adic:
2adic(a,n) returns the first n binary digits of a 2-adic sqroot x of a positive integer a=8k+1. Here x=1 or 5 (mod 8).
padic(a,p,n) returns the first n p-adic digits of a p-adic sqroot x of a positive integer a which is a quadratic residue (mod p). Here x=b (mod p), where b2=a (mod p) and 0 < b < p.
- raney: raney(p,q,r,s) expresses a nonsingular matrix A=[p,q;r,s] (≠ I_2 or U=[0,1;1,0]) as a product of positive powers of R=[1,1;0,1] and L=[1,0;1,1], followed by a row-balanced matrix D=[a,b;c,d]. ie. a < c & b > d or a > c & b < d. The number of terms L and R is returned.
With Ua=[a,1;1,0], note that
Ua0...Ua2n=Ra0La1...Ra2nU0 and that Ua0...Ua2n+1=Ra0La1...La2n+1I2.
- davison: davison(l,m,n) performs the algorithm of J.L. Davison's paper An algorithm for the continued fraction of el/m, Proceedings of the Eighth Manitoba Conference on Numerical Mathematics and Computing (Univ. Manitoba, Winnipeg, 1978), 169--179, Congress. Numer., XXII, Utilitas Math.
With n ≥ 0, we first find the n* of Davison's Proposition 4.1 and apply Raney's factorisation to A0...Ak, for n* ≤ k ≤ n*+n.
The number (count) of partial quotients of el/m found is returned. count becomes positive for all large n.
- squareroot: This is an improved version of sqroot and contains cornacchia(a,b,m). This finds all positive primitive solutions of ax2+by2=m, where a > 0, b > 0, a+b > m > 0, gcd(a,b)=1=gcd(a,m). If a=b=1, we get solutions with y ≤ x.
r=sqroot(d,n,e) returns the solutions of x2=d (mod n).
r is the number of solutions (mod n).
If e=1, we print the solutions (mod reduced_modulus) as
reduced_solution[0],...,reduced_solution[count-1].
If e=0, solutions are not printed. Used eg. in cornacchia().
If omega(n) > 1, we use the Chinese remainder theorem after solving mod
qglobal[i]kglobal[i], i=0,...,omega(n)-1.
The array solution[0],...,solution[numbr-1] consists of the solutions
(mod n) in the range 0 ≤ x ≤ n/2 and is used in cornacchia().
See A. Nitaj, L'algorithme de Cornacchia, Expositiones Mathematicae 13 (1995), 358-365.
- phi now contains sigmak(k,n) and tau(n), where r=sigmak(k,n), k > 0,n > 0, returns the sum of the k-th powers of the divisors of n and u=tau(n) returns Ramanujan's tau function.
We use the simplest formula for tau(n) given on page 140 of T.M. Apostol, Modular functions and Dirichlet series in number theory, 20-22, 140.
- patz: patz(d,n,e) finds fundamental solutions for the diophantine equation x2-dy2=n, d > 0, d not a perfect square. We only find the fundamental solutions for classes P satisfying P2 ≡ d (mod |n|) with 0 ≤ P ≤ |n|/2.
e=1 is verbose and prints the partial quotients, complete quotients and convergents up to the period (resp. double period) according as the period-length of omega[j] and omega*[j] is even or odd. e=0 prints only the fundamental solutions.
Needs squareroot.
- squareroot now contains quadratic(a,b,c,n,flag). This returns the number k of solutions of the congruence ax2+bx+c ≡ 0 (mod n), where gcd(a,n)=1. The solutions in the range 0 ≤ x < n are returned as global variables quadratic_solution[0],...,quadratic_solution[k-1]. flag=1 prints the solutions.
- patz now contains binary(a,b,c,n). This solves ax2+bxy+cy2=n, where n is non-zero and b2-4ac is positive and not a perfect square. The method is from the paper The Diophantine equation ax2+bxy+cy2=N, D=b2-4ac > 0, Journal de Théorie des Nombres de Bordeaux, 14 (2002) 257-270 by K.R. Matthews.
- decimal2rational.
Typing d2r(pre[],per[],k,r,b) will output the rational number with base b preperiod given by pre[k-1],...,pre[0] (if present) and period per[r-1],...,per[0] consisting of integers in the range [0,b-1].
If there is no preperiod, we let pre[0]=0 and k=0.
Example: Take pre[0]=0, per[0]=2, per[1]=1, k=0, r=2, b=10.
Then typing d2r(pre[],per[],k,r,b) outputs .1212···=4/33.
- sqrt_period. Typing z=period(d) outputs the period-length z of the continued fraction of √d. We use the Pohst-Zassenhaus half-period trick. See paper.
- nipell. (a) Typing nipell(61,0) finds the smallest solution of Pell equation x2-61y2=1 or -1, using the nearest integer continued fraction of √61. The period (or semi-period in the case that the negative Pell equation is soluble) is also printed.
Typing nipell(61,1) prints partial quotients, complete convergents and convergents.
(b) Typing nicf_pqa(d,t,u,v,e), e=0 or 1, finds the nearest integer continued fraction of (u + t√d)/v of Hurwitz.
Typing nicf_pqa0(d,t,u,v,e), e=0 or 1, finds the nearest integer continued fraction of (u + t√d)/v in Perron's book. When e=1, the period partial numerators and denominators are in capitals.
- nscf_pell. This program solves the Pell equations x2 - dy2 = ±1, using the NSCF algorithm - nearest square continued fraction algorithm. We follow the algorithm of A.A. Krisnaswami Ayyangar.
(a) Typing nscf_pell(d,1) prints the partial quotients, convergents, complete convergents of the period of the nearest square continued fraction of sqrt(d), as well as the Pell equation solutions, whereas nscf_pell(d,0) prints only the continued fraction and solutions of the Pell equation.
(b) Typing nscf_pqa(d,t,u,v,e), e=0 or 1, finds the nearest square continued fraction of (u + t√d)/v.
Email
http://www.numbertheory.org/keith.html
Last modified 11th March 2008