diff --git a/collects/math/private/bigfloat/bigfloat-mpfr.rkt b/collects/math/private/bigfloat/bigfloat-mpfr.rkt index b859a81dd1..0ab57d4c48 100644 --- a/collects/math/private/bigfloat/bigfloat-mpfr.rkt +++ b/collects/math/private/bigfloat/bigfloat-mpfr.rkt @@ -137,6 +137,15 @@ (define bits (bf-precision)) (bf (random-bits bits) (- bits))) +(: bigfloat->fl2 (Bigfloat -> (Values Flonum Flonum))) +(define (bigfloat->fl2 x) + (define x2 (bigfloat->flonum x)) + (values x2 (bigfloat->flonum (bf- x (flonum->bigfloat x2))))) + +(: fl2->bigfloat (Flonum Flonum -> Bigfloat)) +(define (fl2->bigfloat x2 x1) + (bf+ (flonum->bigfloat x1) (flonum->bigfloat x2))) + (provide ;; Library stuffs mpfr-available? @@ -159,10 +168,12 @@ integer->bigfloat rational->bigfloat real->bigfloat + fl2->bigfloat bigfloat->flonum bigfloat->integer bigfloat->rational bigfloat->real + bigfloat->fl2 ;; String conversion bigfloat->string string->bigfloat diff --git a/collects/math/private/bigfloat/mpfr.rkt b/collects/math/private/bigfloat/mpfr.rkt index 63098193bc..a7e158cf95 100644 --- a/collects/math/private/bigfloat/mpfr.rkt +++ b/collects/math/private/bigfloat/mpfr.rkt @@ -1001,24 +1001,6 @@ (set! 0ary-funs (list* #'phi.bf #'epsilon.bf #'-max.bf #'-min.bf #'+min.bf #'+max.bf 0ary-funs))) -;; =================================================================================================== -;; Extra functions - -(define (random-bits bits) - (let loop ([bits bits] [acc 0]) - (cond [(= 0 bits) acc] - [else - (define new-bits (min 24 bits)) - (loop (- bits new-bits) - (bitwise-ior (random (arithmetic-shift 1 new-bits)) - (arithmetic-shift acc new-bits)))]))) - -(define (bfrandom) - (define bits (bf-precision)) - (bf (random-bits bits) (- bits))) - -(provide bfrandom) - ;; =================================================================================================== ;; Number Theoretic Functions ;; http://gmplib.org/manual/Number-Theoretic-Functions.html#Number-Theoretic-Functions diff --git a/collects/math/private/flonum/expansion/expansion-base.rkt b/collects/math/private/flonum/expansion/expansion-base.rkt index f12ba2355e..7c0a244aab 100644 --- a/collects/math/private/flonum/expansion/expansion-base.rkt +++ b/collects/math/private/flonum/expansion/expansion-base.rkt @@ -9,10 +9,9 @@ Discrete & Computational Geometry 18(3):305–363, October 1997 |# (require "../flonum-functions.rkt" - "../flonum-syntax.rkt" - "../../bigfloat/bigfloat-struct.rkt") + "../flonum-syntax.rkt") -(provide fl2 bigfloat->fl2 fl2->real fl2->bigfloat +(provide fl2 fl2->real fl2+ fl2- fl2*split-fl fl2* fl2/ flsqrt/error fl2sqrt) @@ -31,11 +30,6 @@ Discrete & Computational Geometry 18(3):305–363, October 1997 [(x y) (fast-fl+/error x y)])) -(: bigfloat->fl2 (Bigfloat -> (Values Flonum Flonum))) -(define (bigfloat->fl2 x) - (define x2 (bigfloat->flonum x)) - (values x2 (bigfloat->flonum (bf- x (bf x2))))) - (: fl2->real (Flonum Flonum -> Real)) (define (fl2->real x2 x1) (cond [(and (x1 . fl> . -inf.0) (x1 . fl< . +inf.0) @@ -43,10 +37,6 @@ Discrete & Computational Geometry 18(3):305–363, October 1997 (+ (inexact->exact x2) (inexact->exact x1))] [else (fl+ x1 x2)])) -(: fl2->bigfloat (Flonum Flonum -> Bigfloat)) -(define (fl2->bigfloat x2 x1) - (bf+ (bf x1) (bf x2))) - (: fl3->fl2 (Flonum Flonum Flonum -> (Values Flonum Flonum))) (define (fl3->fl2 e3 e2 e1) (values e3 (fl+ e2 e1))) diff --git a/collects/math/private/number-theory/divisibility.rkt b/collects/math/private/number-theory/divisibility.rkt index d9c3706312..bb57c1764a 100644 --- a/collects/math/private/number-theory/divisibility.rkt +++ b/collects/math/private/number-theory/divisibility.rkt @@ -7,9 +7,10 @@ ;;; (: divides? : Integer Integer -> Boolean) -; For b<>0: ( a divides b <=> exists k s.t. a*k=b ) +; a divides b <=> exists unique k s.t. a*k=b (define (divides? a b) - (= (remainder b a) 0)) + (cond [(zero? a) #f] + [else (= (remainder b a) 0)])) ; DEF (Coprime, relatively prime) ; Two or more integers are called coprime, if their greatest common divisor is 1. diff --git a/collects/math/private/number-theory/modular-arithmetic-base.rkt b/collects/math/private/number-theory/modular-arithmetic-base.rkt index 4af133b111..182945606b 100644 --- a/collects/math/private/number-theory/modular-arithmetic-base.rkt +++ b/collects/math/private/number-theory/modular-arithmetic-base.rkt @@ -23,8 +23,12 @@ (provide (all-defined-out)) - (: current-modulus-param (Parameterof Positive-Integer)) - (define current-modulus-param (make-parameter 1)) + (: current-modulus-param (Parameterof Integer Positive-Integer)) + (define current-modulus-param + (make-parameter + 1 (λ: ([n : Integer]) + (cond [(n . <= . 0) (raise-argument-error 'with-modulus "Positive-Integer" n)] + [else n])))) (: current-modulus (-> Positive-Integer)) (begin-encourage-inline diff --git a/collects/math/private/number-theory/number-theory.rkt b/collects/math/private/number-theory/number-theory.rkt index 4ff2ccfa7e..8b1d6864fb 100644 --- a/collects/math/private/number-theory/number-theory.rkt +++ b/collects/math/private/number-theory/number-theory.rkt @@ -107,8 +107,10 @@ ; Example : (solve-chinese '(2 3 2) '(3 5 7)) = 23 -(: solve-chinese : Zs (Listof N+) -> N) +(: solve-chinese : Zs (Listof Z) -> N) (define (solve-chinese as ns) + (unless (andmap positive? ns) + (raise-argument-error 'solve-chinese "(Listof Positive-Integer)" 1 as ns)) ; the ns should be coprime (let* ([n (apply * ns)] [cs (map (λ: ([ni : Z]) (quotient n ni)) ns)] @@ -245,35 +247,43 @@ (prev-prime n-2)))])) -(: next-primes : Z N -> Zs) +(: next-primes : Z Z -> Zs) (define (next-primes m primes-wanted) - (: loop : Z Z -> Zs) - (define (loop n primes-wanted) - (if (= primes-wanted 0) - '() - (let ([next (next-prime n)]) - (if next - (cons next (loop next (sub1 primes-wanted))) - '())))) - (loop m primes-wanted)) + (cond + [(primes-wanted . < . 0) (raise-argument-error 'next-primes "Natural" 1 m primes-wanted)] + [else + (: loop : Z Z -> Zs) + (define (loop n primes-wanted) + (if (= primes-wanted 0) + '() + (let ([next (next-prime n)]) + (if next + (cons next (loop next (sub1 primes-wanted))) + '())))) + (loop m primes-wanted)])) -(: prev-primes : Z N -> Zs) +(: prev-primes : Z Z -> Zs) (define (prev-primes m primes-wanted) - (: loop : Z Z -> Zs) - (define (loop n primes-wanted) - (if (= primes-wanted 0) - '() - (let ([prev (prev-prime n)]) - (if prev - (cons prev (loop prev (sub1 primes-wanted))) - '())))) - (loop m primes-wanted)) + (cond + [(primes-wanted . < . 0) (raise-argument-error 'prev-primes "Natural" 1 m primes-wanted)] + [else + (: loop : Z Z -> Zs) + (define (loop n primes-wanted) + (if (= primes-wanted 0) + '() + (let ([prev (prev-prime n)]) + (if prev + (cons prev (loop prev (sub1 primes-wanted))) + '())))) + (loop m primes-wanted)])) -(: nth-prime : N -> Prime) +(: nth-prime : Z -> Prime) (define (nth-prime n) - (for/fold: ([p : Prime 2]) ([m (in-range n)]) - (next-prime p))) + (cond [(n . < . 0) (raise-argument-error 'nth-prime "Natural" n)] + [else + (for/fold: ([p : Prime 2]) ([m (in-range n)]) + (next-prime p))])) ;;; diff --git a/collects/math/private/number-theory/quadratic-residues.rkt b/collects/math/private/number-theory/quadratic-residues.rkt index 1d8bc5244b..06eab941f3 100644 --- a/collects/math/private/number-theory/quadratic-residues.rkt +++ b/collects/math/private/number-theory/quadratic-residues.rkt @@ -13,12 +13,13 @@ ; The number s is called a squre root of a modulo n. ; p is prime -(: quadratic-character : Integer Integer -> Integer) +(: quadratic-character : Integer Integer -> (U -1 0 1)) (define (quadratic-character a p) (cond [(a . < . 0) (raise-argument-error 'quadratic-character "Natural" 0 a p)] [(p . <= . 0) (raise-argument-error 'quadratic-character "Positive-Integer" 1 a p)] [else (let ([l (modular-expt a (quotient (- p 1) 2) p)]) - (if (<= 0 l 1) l -1))])) + (cond [(or (eqv? l 0) (eqv? l 1)) l] + [else -1]))])) (: quadratic-residue? : Integer Integer -> Boolean) (define (quadratic-residue? a n) diff --git a/collects/math/scribblings/math-number-theory.scrbl b/collects/math/scribblings/math-number-theory.scrbl index 18356df8aa..aab9e239db 100644 --- a/collects/math/scribblings/math-number-theory.scrbl +++ b/collects/math/scribblings/math-number-theory.scrbl @@ -1,8 +1,12 @@ -#lang scribble/doc +#lang scribble/manual @(require (for-label racket/flonum racket/fixnum racket/unsafe/ops racket/require + racket/base + (only-in typed/racket/base + Integer Exact-Rational Boolean Listof Natural U List + Positive-Integer) math) scribble/extract scribble/eval @@ -13,107 +17,88 @@ "utils.rkt") @(define untyped-eval (make-untyped-math-eval)) +@interaction-eval[#:eval untyped-eval (require racket/list + racket/function)] @(define math-style tt) -@(define math-eval - (parameterize ([sandbox-output 'string] - [sandbox-error-output 'string]) - (make-evaluator 'racket))) -@;(interaction-eval #:eval math-eval (require racket math)) - - -@title[#:tag "number-theory" #:style '(toc)]{Number Theory} +@title[#:tag "number-theory"]{Number Theory} @(author-jens-axel) +@defmodule[math/number-theory] + @local-table-of-contents[] @; ---------------------------------------- @section[#:tag "congruences"]{Congruences and Modular Arithmetic} @margin-note{Wikipedia: @hyperlink["http://en.wikipedia.org/wiki/Divisor"]{Divisor}} -@defproc[(divides? [m Integer] [n Integer]) boolean?]{ - Returns @racket[#t] if @racket[m] divides @racket[n], - @racket[#f] otherwise. +@defproc[(divides? [m Integer] [n Integer]) Boolean]{ + Returns @racket[#t] if @racket[m] divides @racket[n], @racket[#f] otherwise. + + Formally, an integer @racket[m] divides an integer @racket[n] when there + exists a unique integer @racket[k] such that @racket[(* m k) = n]. - Note: That a non-zero integer @racket[m] divides an integer @racket[n] - means there exists an integer @racket[k] such that m*k=n. - - Test whether 2 divides 9: + @examples[#:eval untyped-eval + (divides? 2 9) + (divides? 2 8)] + + Note that @racket[0] cannot divide anything: @interaction[#:eval untyped-eval - (require math) - (divides? 2 9)] -} + (divides? 0 5) + (divides? 0 0)] + + Practically, if @racket[(divides? m n)] is @racket[#t], then @racket[(/ n m)] will return + an integer and will not raise @racket[exn:fail:contract:divide-by-zero]. + +} @margin-note{Wikipedia: @hyperlink["http://en.wikipedia.org/wiki/B%C3%A9zout's_identity"]{Bezout's Identity}} @defproc[(bezout [a Integer] [b Integer] [c Integer] ...) (Listof Integer)]{ - Given integers @racket[a], @racket[b], @racket[c] ... - returns a list of integers @racket[u], @racket[v], @racket[q] ... - such that @racket[gcd](@racket[a],@racket[b],@racket[c],...) - = @racket[au + bv + cw + ...] + Given integers @racket[a b c ...] returns a list of integers @racket[(list u v w ...)] + such that @racket[(gcd a b c ...) = (+ (* a u) (* b v) (* c w) ...)]. - The greatest common divisor of 6 and 15 is 3. - @interaction[#:eval untyped-eval - (bezout 6 15) - (+ (* -2 6) (* 1 15))] + @examples[#:eval untyped-eval + (bezout 6 15) + (+ (* -2 6) (* 1 15)) + (gcd 6 15)] } - -@margin-note{Wikipedia: @hyperlink["http://en.wikipedia.org/wiki/Coprime"]{Coprime}} -@defproc[(coprime? [a Integer] [b Integer] ...) boolean?]{ - Returns @racket[#t] if the integers @racket[a],@racket[b],... are coprime. - Note: A set of integers are considered coprime (also called relatively prime) +@margin-note{Wikipedia: @hyperlink["http://en.wikipedia.org/wiki/Coprime"]{Coprime}} +@defproc[(coprime? [a Integer] [b Integer] ...) Boolean]{ + Returns @racket[#t] if the integers @racket[a b ...] are coprime. + Formally, a set of integers is considered coprime (also called relatively prime) if their greatest common divisor is 1. - The numbers 2, 6, and, 15 are coprime. - @interaction[#:eval untyped-eval - (coprime? 2 6 15)] -} - + @examples[#:eval untyped-eval + (coprime? 2 6 15)] +} @margin-note{Wikipedia: @hyperlink["http://en.wikipedia.org/wiki/Pairwise_coprime"]{Pairwise Coprime}} -@defproc[(pairwise-coprime? [a Integer] [b Integer] ...) boolean?]{ - Returns @racket[#t] if the integers @racket[a],@racket[b],... are pairwise coprime. +@defproc[(pairwise-coprime? [a Integer] [b Integer] ...) Boolean]{ + Returns @racket[#t] if the integers @racket[a b ...] are @italic{pairwise} coprime, meaning + that each adjacent pair of integers is coprime. - The numbers 2, 6, and, 15 are not pairwise coprime, since 2 and 6 share the factor 3. - @interaction[#:eval untyped-eval - (pairwise-coprime? 2 6 15)] -} +The numbers 2, 6 and 15 are coprime, but not @italic{pairwise} coprime, because 2 and 6 share the +factor 3: +@interaction[#:eval untyped-eval + (pairwise-coprime? 2 6 15)] +} -@margin-note{Wikipedia: @hyperlink["http://en.wikipedia.org/wiki/Modular_multiplicative_inverse"]{Multiplicative Inverse}} -@defproc[(modular-inverse [a Integer] [n Integer]) natural?]{ - Returns the inverse of @racket[a] module @racket[n], - if @racket[a] and @racket[n] are coprime, - otherwise @racket[#f] is returned. +@margin-note{Wikipedia: @hyperlink["http://en.wikipedia.org/wiki/Chinese_remainder_theorem"]{Chinese Remainder Theorem}} +@defproc[(solve-chinese [as (Listof Integer)] [ns (Listof Integer)]) Natural]{ + Given a length-@racket[k] list of integers @racket[as] and a length-@racket[k] list of coprime + moduli @racket[ns], @racket[(solve-chinese as ns)] returns the least natural number @racket[x] + that is a solution to the equations + + @racketblock[x = #,(elem @racket[a] @subscript{1}) #,(elem "(mod " @racket[n] @subscript{1} ")") + ... + x = #,(elem @racket[a] @subscript{@racket[k]}) #,(elem "(mod " @racket[x] @subscript{@racket[k]} ")")] + + The solution @racket[x] is less than + @racket[(* #,(elem @racket[n] @subscript{1}) ... #,(elem @racket[n] @subscript{@racket[k]}))]. - Note: If @racket[a] and @racket[n] are coprime, then - the inverse, @racket[b], is a number in the set @racket[{0,...,n-1}] - such that @racket[ab=1 mod n]. - - The number 3 is an inverse to 2 modulo 5. - @interaction[(require math) - (modular-inverse 2 5) - (modulo (* 2 3) 5)] - The number 0 has no inverse modulo 5. - @interaction[(require math) - (modular-inverse 0 5)] -} - - - -@defproc[(solve-chinese [as (Listof Integer)] [bs (Listof Integer)]) natural?]{ - @margin-note{Wikipedia: @hyperlink["http://en.wikipedia.org/wiki/Chinese_remainder_theorem"]{Chinese Remainder Theorem}} - Given a list of integers @racket[as] and a list of coprime moduli @racket[ns] - the function @racket[solve-chinese] will return - the single natural solution @racket[x] in @racket[{0,...,n-1}] - to the equations - - @racket[x=a1 mod n1, ..., x=ak mod nk] - - where @racket[a1], ... are the elements of @racket[as], - and @racket[n1], ... are the elements of @racket[ns], - and @racket[n=n1*...*nk]. - + The moduli @racket[ns] must all be positive. What is the least number @racket[x] that when divided by 3 leaves a remainder of 2, when divided by 5 leaves a remainder of 3, and @@ -122,57 +107,187 @@ (solve-chinese '(2 3 2) '(3 5 7))] } -@defproc[(quadratic-residue? [a natural?] [n natural?]) boolean?]{ -Returns @racket[#t] if @racket[a] is a quadratic residue modulo @racket[n], -otherwise @racket[#f] is returned. +@defproc[(quadratic-residue? [a Integer] [n Integer]) Boolean]{ +Returns @racket[#t] if @racket[a] is a quadratic residue modulo @racket[n], otherwise @racket[#f]. +The modulus @racket[n] must be positive, and @racket[a] must be nonnegative. -A number @racket[a] is a quadratic residue modulo @racket[n], if there -exists a number @racket[x] such that @math-style{x^2=a mod n}. - @interaction[(require math) - (quadratic-residue? 0 4) - (quadratic-residue? 1 4) - (quadratic-residue? 2 4) - (quadratic-residue? 3 4)] +Formally, @racket[a] is a quadratic residue modulo @racket[n] if there +exists a number @racket[x] such that @racket[(* x x) = a] (mod @racket[n]). +In other words, @racket[(quadratic-residue? a n)] is @racket[#t] when +@racket[a] is a perfect square modulo @racket[n]. + +@examples[#:eval untyped-eval + (quadratic-residue? 0 4) + (quadratic-residue? 1 4) + (quadratic-residue? 2 4) + (quadratic-residue? 3 4)] } -@defproc[(quadratic-character [a natural?] [p prime?]) (union -1 1)]{ -Returns the values of the quadratic character modulo the prime @racket[p]. +@defproc[(quadratic-character [a Integer] [p Integer]) (U -1 0 1)]{ +Returns the value of the quadratic character modulo the prime @racket[p]. That is, for a non-zero @racket[a] the number @racket[1] is returned when @racket[a] is a quadratic residue, and @racket[-1] is returned when @racket[a] is a non-residue. If @racket[a] is zero, then @racket[0] is returned. - -This function is also known as the @emph{Legendre Symbol}. - @interaction[(require math) - (quadratic-character 0 4) - (quadratic-character 1 4) - (quadratic-character 2 4) - (quadratic-character 3 4)] +If @racket[a] is negative or @racket[p] is not positive, @racket[quadratic-character] raises an error. +If @racket[p] is not prime, @racket[(quadratic-character a p)] is indeterminate. + +This function is also known as the @emph{Legendre symbol}. + + @interaction[#:eval untyped-eval + (quadratic-character 0 5) + (quadratic-character 1 5) + (quadratic-character 2 5) + (quadratic-character 3 5)] } +@margin-note{Wikipedia: @hyperlink["http://en.wikipedia.org/wiki/Modular_multiplicative_inverse"]{Multiplicative Inverse}} +@defproc[(modular-inverse [a Integer] [n Integer]) Natural]{ + Returns the inverse of @racket[a] modulo @racket[n] if @racket[a] and @racket[n] are coprime, + otherwise raises an error. The modulus @racket[n] must be positive, and @racket[a] must be nonzero. + + Formally, if @racket[a] and @racket[n] are coprime, @racket[b = (modular-inverse a n)] is the + unique natural number less than @racket[n] such that @racket[(* a b) = 1] (mod @racket[n]). + + @interaction[#:eval untyped-eval + (modular-inverse 2 5) + (modulo (* 2 3) 5)] +} + +@defproc[(modular-expt [a Integer] [b Integer] [n Integer]) Natural]{ + Computes @racket[(modulo (expt a b) n)], but much more efficiently. The modulus @racket[n] must + be positive, and the exponent @racket[b] must be nonnegative. + + @examples[#:eval untyped-eval + (modulo (expt -6 523) 19) + (modular-expt -6 523 19) + (modular-expt 9 158235208 19) + (eval:alts (code:line (code:comment "don't try this at home!") + (modulo (expt 9 158235208) 19)) + (eval:result @racketresultfont{4})) + ] +} + +@subsection[#:tag "modular"]{Parameterized Modular Arithmetic} + +The @racketmodname[math/number-theory] library supports modular arithmetic parameterized on a current +modulus. For example, the code + +@racketblock[(with-modulus n + ((modexpt a b) . mod= . c))] + +corresponds with the mathematical statement +@italic{a}@superscript{@italic{b}} = @italic{c} (mod @italic{n}). + +The current modulus is stored in a @tech{parameter} that, for performance reasons, can only be +set using @racket[with-modulus]. (The basic modular operators cache parameter reads, and this +restriction guarantees that the cached values are current.) + +@defform[(with-modulus n body ...) + #:contracts ([n Integer])]{ +Alters the current modulus within the dynamic extent of @racket[body]. +The expression @racket[n] must evaluate to a positive integer. + +By default, the current modulus is @racket[1], meaning that every modular arithmetic expression +that does not raise an error returns @racket[0]. +} + +@defproc[(current-modulus) Positive-Integer]{ +Returns the current modulus. +@examples[#:eval untyped-eval + (current-modulus) + (with-modulus 5 (current-modulus))] +} + +@defproc[(mod [x Exact-Rational]) Natural]{ +Converts a rational number @racket[x] to a natural number less than the current modulus. + +If @racket[x] is an integer, this is equivalent to @racket[(modulo x n)]. +If @racket[x] is a fraction, an integer input is generated by multiplying its numerator +by its denominator's modular inverse. + +@examples[#:eval untyped-eval + (with-modulus 7 (mod (* 218 7))) + (with-modulus 7 (mod 3/2)) + (with-modulus 7 (mod/ 3 2)) + (with-modulus 7 (mod 3/7))] +} + +@deftogether[(@defproc[(mod+ [a Integer] ...) Natural] + @defproc[(mod* [a Integer] ...) Natural])]{ +Equivalent to @racket[(modulo (+ a ...) (current-modulus))] and +@racket[(modulo (* a ...) (current-modulus))], respectively, but generate smaller intermediate +values. +} + +@deftogether[(@defproc[(modsqr [a Integer]) Natural] + @defproc[(modexpt [a Integer] [b Integer]) Natural])]{ +Equivalent to @racket[(mod* a a)] and @racket[(modular-expt a b (current-modulus))], respectively. +} + +@defproc[(mod- [a Integer] [b Integer] ...) Natural]{ +Equivalent to @racket[(modulo (- a b ...) (current-modulus))], but generates smaller intermediate +values. Note that @racket[(mod- a) = (mod (- a))]. +} + +@defproc[(mod/ [a Integer] [b Integer] ...) Natural]{ +Divides @racket[a] by @racket[(* b ...)], by multiplying @racket[a] by the multiplicative inverse +of @racket[(* b ...)]. The one-argument variant returns the modular inverse of @racket[a]. + +Note that @racket[(mod/ a b ...)] is @bold{not} equivalent to +@racket[(modulo (/ a b ...) (current-modulus))]; see @racket[mod=] for a demonstration. +} + +@deftogether[(@defproc[(mod= [a Integer] [b Integer] ...) Boolean] + @defproc[(mod< [a Integer] [b Integer] ...) Boolean] + @defproc[(mod<= [a Integer] [b Integer] ...) Boolean] + @defproc[(mod> [a Integer] [b Integer] ...) Boolean] + @defproc[(mod>= [a Integer] [b Integer] ...) Boolean])]{ +Each of these is equivalent to @racket[(op (mod a) (mod b) ...)], where @racket[op] is the +corresponding numeric comparison function. Additionally, when given one argument, the inequality +tests always return @racket[#t]. + +Suppose we wanted to know why 17/4 = 8 (mod 15), but 51/12 (mod 15) is undefined, even though +normally 51/12 = 17/4. In code, +@interaction[#:eval untyped-eval + (with-modulus 15 (mod/ 17 4)) + (/ 51 12) + (with-modulus 15 (mod/ 51 12))] +We could try to divide by brute force: find, modulo 15, all the numbers @racket[a] +for which @racket[(mod* a 4)] is @racket[17], then find all the numbers @racket[b] for which +@racket[(mod* a 12)] is @racket[51]. +@interaction[#:eval untyped-eval + (with-modulus 15 + (for/list ([a (in-range 15)] + #:when (mod= (mod* a 4) 17)) + a)) + (with-modulus 15 + (for/list ([b (in-range 15)] + #:when (mod= (mod* b 12) 51)) + b))] +So the problem isn't that @racket[b] doesn't exist, it's that @racket[b] isn't @italic{unique}. +} @; ---------------------------------------- @section[#:tag "primes"]{Primes} -@defproc[(prime? [z Integer]) boolean?]{ -Returns @racket[#t] if @racket[z] is a prime, -@racket[#f] otherwise. +@defproc[(prime? [z Integer]) Boolean]{ +Returns @racket[#t] if @racket[z] is a prime, @racket[#f] otherwise. -Note: An integer @racket[z] is considered a prime, if the only -positive divisors of @racket[z] are @racket[1] and @racket[|z|]. +Formally, an integer @racket[z] is prime when the only positive divisors of @racket[z] +are @racket[1] and @racket[(abs z)]. The positive primes below 20 are: @interaction[#:eval untyped-eval - (require racket/list) (filter prime? (range 1 21))] The corresponding negative primes are: @interaction[#:eval untyped-eval (filter prime? (range 1 -21 -1))] } -@defproc[(odd-prime? [z Integer]) boolean?]{ +@defproc[(odd-prime? [z Integer]) Boolean]{ Returns @racket[#t] if @racket[z] is a odd prime, @racket[#f] otherwise. @@ -181,15 +296,15 @@ Returns @racket[#t] if @racket[z] is a odd prime, (odd-prime? 3)] } -@defproc[(nth-prime [n Natural]) natural?]{ -Returns the n'th positive prime. +@defproc[(nth-prime [n Integer]) Natural]{ +Returns the @racket[n]th positive prime; @racket[n] must be nonnegative. @interaction[#:eval untyped-eval (nth-prime 0) (nth-prime 1) (nth-prime 2)] } -@defproc[(next-prime [z Integer]) prime?]{ +@defproc[(next-prime [z Integer]) Integer]{ Returns the first prime larger than @racket[z]. @interaction[#:eval untyped-eval @@ -197,7 +312,7 @@ Returns the first prime larger than @racket[z]. (next-prime 5)] } -@defproc[(prev-prime [z Integer]) prime?]{ +@defproc[(prev-prime [z Integer]) Integer]{ Returns the first prime smaller than @racket[z]. @interaction[#:eval untyped-eval @@ -205,21 +320,21 @@ Returns the first prime smaller than @racket[z]. (prev-prime 5)] } -@defproc[(next-primes [z Integer] [n Natural]) (Listof prime?)]{ -Returns list of the next @racket[n] primes larger than @racket[z]. +@defproc[(next-primes [z Integer] [n Integer]) (Listof Integer)]{ +Returns list of the next @racket[n] primes larger than @racket[z]; @racket[n] must be nonnegative. @interaction[#:eval untyped-eval (next-primes 2 4)] } -@defproc[(prev-primes [z Integer] [n Natural]) (Listof prime?)]{ -Returns list of the next @racket[n] primes smaller than @racket[z]. +@defproc[(prev-primes [z Integer] [n Integer]) (Listof Integer)]{ +Returns list of the next @racket[n] primes smaller than @racket[z]; @racket[n] must be nonnegative. @interaction[#:eval untyped-eval (prev-primes 13 4)] } -@defproc[(factorize [n Natural]) (Listof (List prime? natural?))]{ +@defproc[(factorize [n Natural]) (Listof (List Natural Natural))]{ Returns the factorization of a natural number @racket[n]. The factorization consists of a list of corresponding primes and exponents. The primes will be in ascending order. @@ -229,7 +344,7 @@ The prime factorization of 600 = 2^3 * 3^1 * 5^2: (factorize 600)] } -@defproc[(defactorize [f (Listof (List prime? natural?))]) natural?]{ +@defproc[(defactorize [f (Listof (List Natural Natural))]) Natural]{ Returns the natural number, whose factorization is given by @racket[f]. The factorization @racket[f] is represented as described in @racket[factorize]. @@ -247,7 +362,7 @@ The divisors appear in ascending order. (divisors -120)] } -@defproc[(prime-divisors [z Integer]) (Listof Natural)]{ +@defproc[(prime-divisors [z Natural]) (Listof Natural)]{ Returns a list of all positive prime divisors of the integer @racket[z]. The divisors appear in ascending order. @@ -255,10 +370,10 @@ Returns a list of all positive prime divisors of the integer (prime-divisors 120)] } -@defproc[(prime-exponents [z Integer]) (Listof Natural)]{ +@defproc[(prime-exponents [z Natural]) (Listof Natural)]{ Returns a list of the exponents of in a factorization of the integer @racket[z]. - + @interaction[#:eval untyped-eval (define z (* 2 2 2 3 5 5)) (prime-divisors z) @@ -268,20 +383,19 @@ Returns a list of the exponents of in a factorization of the integer @; ---------------------------------------- @section[#:tag "roots"]{Roots} - -@defproc[(integer-root [n Natural] [m Natural]) natural?]{ -Returns the @racket[m]'th integer root of @racket[n]. +@defproc[(integer-root [n Natural] [m Natural]) Natural]{ +Returns the @racket[m]th integer root of @racket[n]. This is the largest number @racket[r] such that -@racket[r^m<=n]. - +@racket[(expt r m) <= n]. + @interaction[#:eval untyped-eval (integer-root (expt 3 4) 4) (integer-root (+ (expt 3 4) 1) 4)] } - + @defproc[(integer-root/remainder [n Natural] [m Natural]) - (values natural? natural?)]{ -Returns two values. The first, @racket[r], is the @racket[m]'th + (values Natural Natural)]{ +Returns two values. The first, @racket[r], is the @racket[m]th integer root of @racket[n]. The second is @racket[n-r^m]. @interaction[#:eval untyped-eval @@ -293,31 +407,31 @@ integer root of @racket[n]. The second is @racket[n-r^m]. @; ---------------------------------------- @section[#:tag "powers"]{Powers} -@defproc[(max-dividing-power [a Integer] [b Integer]) natural?]{ +@defproc[(max-dividing-power [a Integer] [b Integer]) Natural]{ Returns the largest exponent, @racket[n], of a power with base @racket[a] that divides @racket[b]. -That is, @racket[a^n] divides @racket[b] but @racket[a^(n+1)] does not divide +That is, @racket[(expt a n)] divides @racket[b] but @racket[(expt a (+ n 1))] does not divide @racket[b]. - + @interaction[#:eval untyped-eval (max-dividing-power 3 (expt 3 4)) (max-dividing-power 3 5)] } @defproc[(perfect-power [m Integer]) - (Union (List natural? natural?) #f)]{ + (U (List Natural Natural) #f)]{ If @racket[m] is a perfect power, a list with two elements -@racket[b] and @racket[n] such that @racket[b^n = m] +@racket[b] and @racket[n] such that @racket[(expt b n) = m] is returned, otherwise @racket[#f] is returned. - + @interaction[#:eval untyped-eval (perfect-power (expt 3 4)) (perfect-power (+ (expt 3 4) 1))] } + - -@defproc[(perfect-power? [m Integer]) boolean?]{ +@defproc[(perfect-power? [m Integer]) Boolean]{ Returns @racket[#t] if @racket[m] is a perfect power, otherwise @racket[#f]. @@ -326,10 +440,10 @@ otherwise @racket[#f]. (perfect-power? (+ (expt 3 4) 1))] } - + @defproc[(prime-power [m Natural]) - (Union (List prime? natural?) #f)]{ -If @racket[m] is a power of the form @racket[p^n] + (U (List Natural Natural) #f)]{ +If @racket[m] is a power of the form @racket[(expt p n)] where @racket[p] is prime, then a list with the prime and the exponent is returned, otherwise @racket[#f] is returned. @@ -339,7 +453,7 @@ prime and the exponent is returned, otherwise (prime-power (expt 6 4))] } -@defproc[(prime-power? [m Natural]) boolean?]{ +@defproc[(prime-power? [m Natural]) Boolean]{ Returns @racket[#t] if @racket[m] is a prime power, otherwise @racket[#f]. @@ -350,7 +464,7 @@ otherwise @racket[#f]. (prime-power? 0)] } -@defproc[(odd-prime-power? [m Natural]) boolean?]{ +@defproc[(odd-prime-power? [m Natural]) Boolean]{ Returns @racket[#t] if @racket[m] is a power of an odd prime, otherwise @racket[#f]. @@ -361,10 +475,10 @@ otherwise @racket[#f]. } @defproc[(as-power [m Positive-Integer]) - (values natural? natural?)]{ + (values Natural Natural)]{ Returns two values @racket[b] and @racket[n] -such that @racket[m=b^r] and @racket[n] is maximal. - +such that @racket[m = (expt b n)] and @racket[n] is maximal. + @interaction[#:eval untyped-eval (as-power (* (expt 2 4) (expt 3 4))) (expt 6 4) @@ -373,9 +487,9 @@ such that @racket[m=b^r] and @racket[n] is maximal. } @defproc[(perfect-square [m Natural]) - (Union natural? #f)]{ -Returns @racket[sqrt(m)] if @racket[m] is perfect -square, otherwise @racket[#f]. + (U Natural #f)]{ +Returns @racket[(sqrt m)] if @racket[m] is perfect +square, otherwise @racket[#f]. @interaction[#:eval untyped-eval (perfect-square 9) @@ -385,42 +499,28 @@ square, otherwise @racket[#f]. @; ---------------------------------------- @section[#:tag "multiplicative"]{Multiplicative Functions} -In number theory a multiplicative function is a -function @racket[f] such that @racket[f(a b) = f(a) f(b)] -for all coprime natural numbers @racket[a] and @racket[b]. - -The functions @racket[totient], @racket[moebius-mu], and, -@racket[divisor-sum] are multiplicative. +The functions in this section are @deftech{multiplicative}. +In number theory, a multiplicative function is a function @racket[f] such that +@racket[(f a b) = (* (f a) (f b))] for all coprime natural numbers @racket[a] and @racket[b]. @margin-note{Wikipedia: @hyperlink["http://en.wikipedia.org/wiki/Euler%27s_totient_function"]{Euler's Totient}} -@defproc[(totient [n Natural]) natural?]{ +@defproc[(totient [n Natural]) Natural]{ Returns the number of integers from 1 to @racket[n] that are coprime with @racket[n]. This function is known as Eulers totient or phi function. -Note: The function @racket[totient] is multiplicative. - @interaction[#:eval untyped-eval - (require racket/function) ; for curry (totient 9) (length (filter (curry coprime? 9) (range 10)))] } - - - -@defproc[(moebius-mu [n Natural]) (Union -1 0 1)]{ @margin-note{Wikipedia: @hyperlink["http://en.wikipedia.org/wiki/M%C3%B6bius_function"]{Moebius Function}} +@defproc[(moebius-mu [n Natural]) (U -1 0 1)]{ Returns: - -@racket[1] if @racket[n] is a product of an even number of primes - -@racket[-1] if @racket[n] is a product of an odd number of primes - -@racket[0] if @racket[n] has a multiple prime factor - -Note: The function @racket[moebius-mu] is multiplicative. +@itemlist[@item{@racket[1] if @racket[n] is a product of an even number of primes} + @item{@racket[-1] if @racket[n] is a product of an odd number of primes} + @item{@racket[0] if @racket[n] has a multiple prime factor}] @interaction[#:eval untyped-eval (moebius-mu (* 2 3 5)) @@ -430,12 +530,10 @@ Note: The function @racket[moebius-mu] is multiplicative. @margin-note{Wikipedia: @hyperlink["http://en.wikipedia.org/wiki/Divisor_function"]{Divisor Function}} -@defproc[(divisor-sum [n Natural] [k Natural]) natural?]{ +@defproc[(divisor-sum [n Natural] [k Natural]) Natural]{ Returns sum of the @racket[k]th powers of all divisors of @racket[n]. -Note: The function @racket[divisor-sum] is multiplicative. - @interaction[#:eval untyped-eval (divisor-sum 12 2) (apply + (map sqr (divisors 12)))] @@ -446,110 +544,118 @@ Note: The function @racket[divisor-sum] is multiplicative. @section[#:tag "number-sequences"]{Number Sequences} @margin-note{Wikipedia: @hyperlink["http://en.wikipedia.org/wiki/Bernoulli_number"]{Bernoulli Number}} -@defproc[(bernoulli [n Natural]) exact-rational?]{ - Returns the @racket[n]th Bernoulli number. - +@defproc[(bernoulli [n Integer]) Exact-Rational]{ + Returns the @racket[n]th Bernoulli number; @racket[n] must be nonnegative. @interaction[#:eval untyped-eval (map bernoulli (range 9))] + + Note that these are the @italic{first} Bernoulli numbers, since @racket[(bernoulli 1) = -1/2]. } @margin-note{MathWorld: @hyperlink["http://mathworld.wolfram.com/EulerianNumber.html"]{Eulerian Number}} -@defproc[(eulerian-number [n Natural] [k Natural]) natural?]{ - Returns the Eulerian number @math-style{}. +@defproc[(eulerian-number [n Integer] [k Integer]) Natural]{ + Returns the Eulerian number @math-style{}; both arguments must be nonnegative. - @interaction[(require math racket) - (eulerian-number 5 2)] + @interaction[#:eval untyped-eval + (eulerian-number 5 2)] } @margin-note{Wikipedia: @hyperlink["http://en.wikipedia.org/wiki/Fibonacci_number"]{Fibonacci Number}} -@defproc[(fibonacci [n Natural]) natural?]{ - Returns the @racket[n]th Fibonacci number. +@defproc[(fibonacci [n Integer]) Natural]{ + Returns the @racket[n]th Fibonacci number; @racket[n] must be nonnegative. The ten first Fibonacci numbers. - @interaction[(require math racket) - (map fibonacci (range 10))] + @interaction[#:eval untyped-eval + (map fibonacci (range 10))] } -@defproc[(fibonacci/mod [n Natural] [m Natural]) natural?]{ - Returns the @racket[n]th Fibonacci number modulo @racket[m]. +@defproc[(fibonacci/mod [n Integer] [m Integer]) Natural]{ + Returns the @racket[n]th Fibonacci number modulo @racket[m]; @racket[n] must be nonnegative + and @racket[m] must be positive. The ten first Fibonacci numbers modulo 5. - @interaction[(require math racket) - (map (λ (n) (fibonacci/mod n 5)) (range 10))] + @interaction[#:eval untyped-eval + (map (λ (n) (fibonacci/mod n 5)) (range 10))] } -@defproc[(farey [n Natural]) (listof rational?)]{ -Returns a list of the numbers in the @racket[n]th Farey sequence. +@defproc[(farey [n Integer]) (Listof Exact-Rational)]{ +Returns a list of the numbers in the @racket[n]th Farey sequence; @racket[n] must be positive. + The @racket[n]th Farey sequence is the sequence of all completely reduced rational numbers from 0 to 1 which denominators are less than or equal to @racket[n]. - @interaction[(require math) - (farey 1) - (farey 2) - (farey 3)] + @interaction[#:eval untyped-eval + (farey 1) + (farey 2) + (farey 3)] } @margin-note{MathWorld: @hyperlink["http://mathworld.wolfram.com/TangentNumber.html"]{Tangent Number}} -@defproc[(tangent-number [n integer?]) integer?]{ -Returns the @racket[n]th tangent number. +@defproc[(tangent-number [n Integer]) Integer]{ +Returns the @racket[n]th tangent number; @racket[n] must be nonnegative. - @interaction[(require math) - (tangent-number 1) - (tangent-number 2) - (tangent-number 3)] + @interaction[#:eval untyped-eval + (tangent-number 1) + (tangent-number 2) + (tangent-number 3)] } @; ---------------------------------------- @section[#:tag "combinatorics"]{Combinatorics} -@defproc[(factorial [n Natural]) natural?]{ - Returns the factorial of @racket[n]. - The factorial of @racket[n] is the - number @math-style{n!=n*(n-1)*(n-2)*...*1}. - @interaction[(require math racket) - (factorial 3) - (factorial 0)] +@defproc[(factorial [n Integer]) Natural]{ + Returns the factorial of @racket[n], which must be nonnegative. + The factorial of @racket[n] is the number @racket[(* n (- n 1) (- n 2) ... 1)]. + @interaction[#:eval untyped-eval + (factorial 3) + (factorial 0)] } -@defproc[(binomial [n Natural] [k Natural]) natural?]{ - Returns @racket[n] choose @racket[k]. - The binomial coeffecient is given by - @math-style{C(n,k)=n!/(n!(n-k)!)}. - @interaction[(require math racket) - (binomial 5 3)] +@defproc[(binomial [n Integer] [k Integer]) Natural]{ + Returns the number of ways to choose a @italic{set} of @racket[k] items from a set of + @racket[n] items; i.e. the order of the @racket[k] items is not significant. + Both arguments must be nonnegative. + + When @racket[k > n], @racket[(binomial n k) = 0]. Otherwise, @racket[(binomial n k)] is + equivalent to @racket[(/ (factorial n) (factorial k) (factorial (- n k)))], but computed more + quickly. + @interaction[#:eval untyped-eval + (binomial 5 3)] } -@defproc[(permutations [n Natural] [k Natural]) natural?]{ - Returns the number of @racket[k]-permutations of @racket[n]. - That is the number of sequences of length @racket[k] where the - elements are drawn from a set with @racket[n] elements. - @math-style{P(n,k)=n!/(n-k)!}. - @interaction[(require math racket) - (permutations 5 3)] +@defproc[(permutations [n Integer] [k Integer]) Natural]{ + Returns the number of ways to choose a @italic{sequence} of @racket[k] items from a set of + @racket[n] items; i.e. the order of the @racket[k] items is significant. + Both arguments must be nonnegative. + + When @racket[k > n], @racket[(permutations n k) = 0]. Otherwise, @racket[(permutations n k)] is + equivalent to @racket[(/ (factorial n) (factorial (- n k)))]. + @interaction[#:eval untyped-eval + (permutations 5 3)] } -@defproc[(multinomial [n Natural] [ks (Listof Natural)]) natural?]{ - Returns the multinomial coeffecient. - The expression @racket[(multinomial n (list k0 k1 ...))] - returns the number @math-style{n! / (k0! * k1! * ...)}. - - @interaction[(require math racket) - (multinomial 5 3 2)] +@defproc[(multinomial [n Integer] [ks (Listof Integer)]) Natural]{ + A generalization of @racket[binomial] to multiple sets of choices; i.e. + @racket[(multinomial n (list k0 k1))] is the number of ways to choose a set of @racket[k0] items + and a set of @racket[k1] items from a set of @racket[n] items. All arguments must be nonnegative. + + When @racket[(apply + ks) = n], this is equivalent to + @racket[(apply / (factorial n) (map factorial ks))]. Otherwise, it returns @racket[0]. + @interaction[#:eval untyped-eval + (multinomial 5 3 2)] } - - @margin-note{Wikipedia: @hyperlink["http://en.wikipedia.org/wiki/Partition_(number_theory)"]{Partition}} -@defproc[(partition-count [n Natural]) natural?]{ - Returns the number of partitions of @racket[n]. +@defproc[(partition-count [n Integer]) Natural]{ + Returns the number of partitions of @racket[n], which must be nonnegative. A partition of a positive integer @racket[n] is a way of writing @racket[n] as a sum of positive integers. - The number 3 has the partitions @math-style{1+1+1, 1+2, 3}. - @interaction[(require math racket) - (partition-count 3) - (partition-count 4)] + The number 3 has the partitions @racket[(+ 1 1 1)], @racket[(+ 1 2)] and @racket[(+ 3)]. + @interaction[#:eval untyped-eval + (partition-count 3) + (partition-count 4)] } @@ -558,12 +664,12 @@ Returns the @racket[n]th tangent number. @subsection{Polygonal Numbers} -@defproc[(triangle? [n Natural]) boolean?]{} -@defproc[(square? [n Natural]) boolean?]{} -@defproc[(pentagonal? [n Natural]) boolean?]{} -@defproc[(hexagonal? [n Natural]) boolean?]{} -@defproc[(heptagonal? [n Natural]) boolean?]{} -@defproc[(octagonal? [n Natural]) boolean?]{ +@defproc[(triangle? [n Natural]) Boolean]{} +@defproc[(square? [n Natural]) Boolean]{} +@defproc[(pentagonal? [n Natural]) Boolean]{} +@defproc[(hexagonal? [n Natural]) Boolean]{} +@defproc[(heptagonal? [n Natural]) Boolean]{} +@defproc[(octagonal? [n Natural]) Boolean]{ The functions @racket[triangle?], @racket[square?], @racket[pentagonal?], @racket[hexagonal?],@racket[heptagonal?] and @racket[octagonal?] @@ -572,12 +678,12 @@ triangle, square, pentagonal, hexagonal, heptagonal and octogonal respectively. } -@defproc[(triangle [n Natural]) natural?]{} -@defproc[(sqr [n Natural]) natural?]{} -@defproc[(pentagonal [n Natural]) natural?]{} -@defproc[(hexagonal [n Natural]) natural?]{} -@defproc[(heptagonal [n Natural]) natural?]{} -@defproc[(octagonal [n Natural]) natural?]{ +@defproc[(triangle [n Natural]) Natural]{} +@defproc[(sqr [n Natural]) Natural]{} +@defproc[(pentagonal [n Natural]) Natural]{} +@defproc[(hexagonal [n Natural]) Natural]{} +@defproc[(heptagonal [n Natural]) Natural]{} +@defproc[(octagonal [n Natural]) Natural]{ The functions @racket[triangle], @racket[sqr], @racket[pentagonal], @racket[hexagonal],@racket[heptagonal] and @racket[octagonal] return the @racket[n]th polygonal number of the corresponding @@ -588,12 +694,12 @@ type of polygonal number. @; ---------------------------------------- @section[#:tag "fractions"]{Fractions} -@defproc[(mediant [x Rational] [y Rational]) rational?]{ +@defproc[(mediant [x Exact-Rational] [y Exact-Rational]) Exact-Rational]{ Computes the @racket[mediant] of the numbers @racket[x] and @racket[y]. The mediant of two fractions @math-style{p/q} and @math-style{r/s} in their lowest term is the number @math-style{(p+r)/(q+s)}. - @interaction[(require math) - (mediant 1/2 5/6)] + @interaction[#:eval untyped-eval + (mediant 1/2 5/6)] } @@ -601,26 +707,26 @@ lowest term is the number @math-style{(p+r)/(q+s)}. @; ---------------------------------------- @section[#:tag "quadratics"]{The Quadratic Equation} -@defproc[(quadratic-solutions [a Real] [b Real] [c Real]) (listof Real)]{ +@defproc[(quadratic-solutions [a Real] [b Real] [c Real]) (Listof Real)]{ Returns a list of all real solutions to the equation @math-style{a x^2 + b x +c = 0}. - @interaction[(require math) - (quadratic-solutions 1 0 -1) - (quadratic-solutions 1 2 1) - (quadratic-solutions 1 0 1)] + @interaction[#:eval untyped-eval + (quadratic-solutions 1 0 -1) + (quadratic-solutions 1 2 1) + (quadratic-solutions 1 0 1)] } -@defproc[(quadratic-integer-solutions [a Real] [b Real] [c Real]) (listof Integer)]{ +@defproc[(quadratic-integer-solutions [a Real] [b Real] [c Real]) (Listof Integer)]{ Returns a list of all integer solutions to the equation @math-style{a x^2 + b x +c = 0}. - @interaction[(require math) - (quadratic-integer-solutions 1 0 -1) - (quadratic-integer-solutions 1 0 -2)] + @interaction[#:eval untyped-eval + (quadratic-integer-solutions 1 0 -1) + (quadratic-integer-solutions 1 0 -2)] } -@defproc[(quadratic-natural-solutions [a Real] [b Real] [c Real]) (listof Natural)]{ +@defproc[(quadratic-natural-solutions [a Real] [b Real] [c Real]) (Listof Natural)]{ Returns a list of all natural solutions to the equation @math-style{a x^2 + b x +c = 0}. - @interaction[(require math) - (quadratic-natural-solutions 1 0 -1) - (quadratic-natural-solutions 1 0 -2)] + @interaction[#:eval untyped-eval + (quadratic-natural-solutions 1 0 -1) + (quadratic-natural-solutions 1 0 -2)] } @@ -642,64 +748,68 @@ Note that @math-style{g} is a primitive root if and only if @math-style{order(g) where @math-style{phi} is Eulers totient. A group with a generator is called @emph{cyclic}. -@defproc[(unit-group [n Natrual]) (listof Natural)]{ -Returns a list of all elements of @math-style{Un}, the unit group modulo @racket[n]. - @interaction[(require math) - (unit-group 5) - (unit-group 6)] +@defproc[(unit-group [n Integer]) (Listof Positive-Integer)]{ +Returns a list of all elements of @math-style{Un}, the unit group modulo @racket[n]. The +modulus @racket[n] must be positive. + @interaction[#:eval untyped-eval + (unit-group 5) + (unit-group 6)] } -@defproc[(order [x Natural] [n Natural]) natural?]{ -Returns the order of @racket[x] in the group @math-style{Un}. -Note: @racket[x] is in @math-style{Un} if and only if @racket[(gcd x n)] is 1. - @interaction[(require math) - (order 2 5) - (order 2 6)] +@defproc[(order [x Integer] [n Integer]) Positive-Integer]{ +Returns the order of @racket[x] in the group @math-style{Un}; both arguments must be positive. +If @racket[x] and @racket[n] are not coprime, @racket[(order x n)] raises an error. + @interaction[#:eval untyped-eval + (order 2 5) + (order 2 6)] } -@defproc[(orders [n Natural]) (listof natural?)]{ -Returns a list @racket[(list (order x0) (order x1) ...)] where +@defproc[(orders [n Integer]) (Listf Positive-Integer)]{ +Returns a list @racket[(list (order x0 n) (order x1 n) ...)] where @racket[x0], @racket[x1], ... are the elements of @math-style{Un}. - @interaction[(require math racket) - (orders 5) - (map (curryr order 5) (unit-group 5))] +The modulus @racket[n] must be positive. + @interaction[#:eval untyped-eval + (orders 5) + (map (curryr order 5) (unit-group 5))] } -@defproc[(primitive-root? [x Natural] [n Natural]) boolean?]{ +@defproc[(primitive-root? [x Integer] [n Integer]) Boolean]{ Returns @racket[#t] if the element @racket[x] in @math-style{Un} is a primitive root modulo @racket[n], -otherwise @racket[#f] is returned. An error is signaled if @racket[x] is not a member of @math-style{Un}. - @interaction[(require math) - (primitive-root? 1 5) - (primitive-root? 2 5) - (primitive-root? 5 5)] +otherwise @racket[#f] is returned. An error is signaled if @racket[x] is not a member of @math-style{Un}. +Both arguments must be positive. + @interaction[#:eval untyped-eval + (primitive-root? 1 5) + (primitive-root? 2 5) + (primitive-root? 5 5)] } -@defproc[(exists-primitive-root? [n Natural]) boolean?]{ +@defproc[(exists-primitive-root? [n Integer]) Boolean]{ Returns @racket[#t] if the group @math-style{Un} has a primitive root (i.e. it is cyclic), -otherwise @racket[#f] is returned. +otherwise @racket[#f] is returned. In other words, @racket[#t] is returned if @racket[n] is one of @math-style{1, 2, 4, p^e, 2*p^e} where @math-style{p} is an odd prime, and @racket[#f] otherwise. - @interaction[(require math) - (exists-primitive-root? 5) - (exists-primitive-root? 6) - (exists-primitive-root? 12)] +The modulus @racket[n] must be positive. + @interaction[#:eval untyped-eval + (exists-primitive-root? 5) + (exists-primitive-root? 6) + (exists-primitive-root? 12)] } -@defproc[(primitive-root [n Natural]) (Union natural? #f)]{ +@defproc[(primitive-root [n Integer]) (Union Natural #f)]{ Returns a primitive root of @math-style{Un} if one exists, -otherwise @racket[#f] is returned. - @interaction[(require math) - (primitive-root 5) - (primitive-root 6)] +otherwise @racket[#f] is returned. The modulus @racket[n] must be positive. + @interaction[#:eval untyped-eval + (primitive-root 5) + (primitive-root 6)] } -@defproc[(primitive-roots [n Natural]) (Listof natural?)]{ -Returns a list of all primitive roots of @math-style{Un}. - @interaction[(require math) - (primitive-roots 3) - (primitive-roots 5) - (primitive-roots 6)] +@defproc[(primitive-roots [n Integer]) (Listof Natural)]{ +Returns a list of all primitive roots of @math-style{Un}. The modulus @racket[n] must be positive. + @interaction[#:eval untyped-eval + (primitive-roots 3) + (primitive-roots 5) + (primitive-roots 6)] }