;========================================================================== ; ; Le←Lisp v15.2 : les rationnels en pre'cision arbitraire Z ; ;=========================================================================== ; (c) Francois Morain, Bernard Serpette, Jean Vuillemin, Paul Zimmermann 1988 ; Institut National de Recherche en Informatique et Automatique ; B.P. 105, 78153 Le Chesnay Cedex, France. morain@inria, ; serpette@inria, vuillemin@inria, zimmerma@inria ;=========================================================================== #| .Chapitre II "L'arithme'tique Ge'ne'rique Le←Lisp" Par convention, tous les types utilisant les ope'rations arithme'tiques ge'ne'riques Le←Lisp sont des sous-types de R. Ceci nous permet d'utiliser pour tous ces objets le comportement par de'faut de'fini dans gen.ll |# (unless (>= (version) 15.2) (syserror 'load "fichier non compatible" 'z)) (add-feature 'z) (unless (featurep 'gen) (libload #u"bngen")) (unless (featurep 'n) (libload #u"bnn")) (setq #:backup:majuscules #:system:read-case-flag #:system:read-case-flag ()) (dmd package (l) `(setq #:sys-package:colon ,l)) (package 'R) ; .Chapitre III "Les entiers relatifs Z." (package ':Q) #| .Section "Structure Interne de Z" L'ensemble Z des entiers relatif, comprend: .br Les fix LeLisp pour les entiers -2↑15<z<2↑15. .br Le type :Q:N, pour les entiers positifs z>2↑15. .br Le type :Q:Z, pour les entiers ne'gatifs z<-2↑15. .Section "Tests de type" L'ensemble de ces trois types characte`rise les objets Lisp pour lesquels (integerp z) = z, leur comple'mentaire par (integerp r) = (). Cette remarque ne sera plus vraie quand on aura fait une extention pour laquelle la fonction ge'ne'rique integerp est e'tendue par (integerp e) = e. Nous ne nous priverons pas de l'utiliser pour les entiers de Gauss, par exemple. |# (de BzCreate (l) (BnCreate l '#:R:Q:Z)) (de BzFree (z) (BnFree z)) (de :integerp (n) n) ; .Section "Recopie" (de Zcopy (n typ) (lets ((nl (BnNumDigits n 0 (BnGetSize n))) (nc (BnCreate typ nl))) (BnAssign nc 0 n 0 nl) nc)) (de BzCopy (z) (Zcopy z (BnGetType z))) ; .Section "Changements de Signe" ; La me`me, e'tendue aux fixp: (de 0-N (n) (selectq (type-of n) (fix (0- n)) (:N (BnSetType n ':Z) n) (:Z (BnSetType n ':N) n) (T (send '0- n)))) (de BzNegate (z) (0-N (BzCopy z))) #| Le fait qu'on ne puisse partager le contenu de deux vecteurs type's entre deux objets diffe'rents oblige a` des copies bien douloureuses pour la ne'gation des nombres. .Section "Valeur absolue abs" |# (de :N:abs (n) n) (de :Z:abs (z) (Zcopy z ':N)) (de BzAbs (z) (Zcopy z ':N)) ; .Section "Oppose' 0-" ; (0- x) vaut -x: (de :Z:0- (z) (Zcopy z ':N)) (de :N:0- (n) (Zcopy n ':Z))) ; Signe (defun BzSign (z) (cond ((neq (BnIsZero z 0 (BnGetSize z)) 0) 0) ((eq (BnGetType z) '#:R:Q:N) 1) (t -1) )) ; .Section "Partie entie`re truncate" ; Pour Z et N: (de :truncate (z) z) ; .Section "Convertion flottante float" (de Zfloat (bn) (let ((s (catenate (string (explode bn)) "."))) (stratom (slen s) s ()))) (de :N:float (r) (Zfloat r)) (de :Z:float (r) (Zfloat r)) ; .Section "La Comparaison <?>" ; (Z?Z n m nl ml) retourne -1,0,1 suivant le signe de N-M = Val<n>-Val<m>. (de Z?Z (n m nl ml) (setq ml (<?> nl ml)) (while (and (eq ml 0) (ge (decr1 nl) 0)) (setq ml (BnCompareDigits n nl m nl))) ml) ; (<?> x y) renvoie 1 ssi x>y, 0 ssi x=y et -1 ssi x<y: (de :N:<?> (n y) (selectq (type-of y) (fix (if (and (eq 1 (BnNumDigits n 0 (BnGetSize n))) (neq (BnDoesDigitFitInWord n 0) 0)) (progn (setq n (BnGetDigit n 0)) (<?> n y)) 1)) (:N (Z?Z n y (BnNumDigits n 0 (BnGetSize n)) (BnNumDigits y 0 (BnGetSize y)))) (:Z 1) (T (0- (<?> y n))))) (de :Z:<?> (z y) (selectq (type-of y) (fix (if (and (eq 1 (BnNumDigits z 0 (BnGetSize z))) (neq (BnDoesDigitFitInWord z 0) 0)) (progn (setq z (BnGetDigit z 0)) (<?> (sub 0 z) y)) -1)) (:N -1) (:Z (Z?Z y z (BnNumDigits y 0 (BnGetSize y)) (BnNumDigits z 0 (BnGetSize z)))) (T (0- (<?> y z))))) (de BzCompare (y z) (<?> y z)) ; .Section "Addition sur Z" (de Z+Z (n nl m ml s typ) (cond ((gt nl ml) (setq s (BnCreate typ nl)) (BnAssign s 0 n 0 nl) (if (eq 0 (BnAdd s 0 nl m 0 ml 0)) s ; overflow (setq n (BnCreate typ (add1 nl))) (BnAssign n 0 s 0 nl) (BnSetDigit n nl 1) n)) ((eqn nl ml) (setq s (BnCreate typ (setq nl (add1 nl)))) (BnAssign s 0 n 0 ml) (BnAdd s 0 nl m 0 ml 0) s) (T (Z+Z m ml n nl s typ)))) (de Z-Z (n nl m ml s typ) (cond ((gt nl ml) (setq s (BnCreate typ nl)) (BnAssign s 0 n 0 nl) (BnSubtract s 0 nl m 0 ml 1) ; pas d'underflow, car nl > ml >= 1 s) ((eqn nl ml) (setq s (BnCreate typ nl)) (BnAssign s 0 n 0 nl) (if (eq 1 (BnSubtract s 0 nl m 0 ml 1)) ; n-m > 0 : on regarde une coertion e'ventuelle (BnConvert s 0 nl) ; underflow (if (and (eq 1 (BnNumDigits s 0 nl)) (neq (BnIsDigitZero s 0) 0)) ; n=m 0 ; n<m (BnComplement s 0 nl) (BnAddCarry s 0 nl 1) (BnSetType s (if (eq typ ':N) ':Z ':N)) (BnConvert s 0 nl)))) (T (Z-Z m ml n nl s (if (eq typ ':N) ':Z ':N))))) (defvar :fix (BnCreate 'N 2)) (de :N:+ (n y) (selectq (type-of y) (fix (cond ((ge y 0) (BnSetDigit :fix 0 y) (Z+Z n (BnNumDigits n 0 (BnGetSize n)) :fix 1 0 ':N)) (T (BnSetDigit :fix 0 (sub 0 y)) (Z-Z n (BnNumDigits n 0 (BnGetSize n)) :fix 1 0 ':N)))) (:N (Z+Z n (BnNumDigits n 0 (BnGetSize n)) y (BnNumDigits y 0 (BnGetSize y)) 0 ':N)) (:Z (Z-Z n (BnNumDigits n 0 (BnGetSize n)) y (BnNumDigits y 0 (BnGetSize y)) 0 ':N)) (t (+ y n)))) (de :N:- (n y) (selectq (type-of y) (fix (cond ((ge y 0) (BnSetDigit :fix 0 y) (Z-Z n (BnNumDigits n 0 (BnGetSize n)) :fix 1 0 ':N)) (T (BnSetDigit :fix 0 (sub 0 y)) (Z+Z n (BnNumDigits n 0 (BnGetSize n)) :fix 1 0 ':N)))) (:N (Z-Z n (BnNumDigits n 0 (BnGetSize n)) y (BnNumDigits y 0 (BnGetSize y)) 0 ':N)) (:Z (Z+Z n (BnNumDigits n 0 (BnGetSize n)) y (BnNumDigits y 0 (BnGetSize y)) 0 ':N)) (t (+ (0- y) n)))) (de :Z:+ (z y) (selectq (type-of y) (fix (cond ((ge y 0) (BnSetDigit :fix 0 y) (Z-Z z (BnNumDigits z 0 (BnGetSize z)) :fix 1 0 ':Z)) (T (BnSetDigit :fix 0 (sub 0 y)) (Z+Z z (BnNumDigits z 0 (BnGetSize z)) :fix 1 0 ':Z)))) (:N (Z-Z z (BnNumDigits z 0 (BnGetSize z)) y (BnNumDigits y 0 (BnGetSize y)) 0 ':Z)) (:Z (Z+Z z (BnNumDigits z 0 (BnGetSize z)) y (BnNumDigits y 0 (BnGetSize y)) 0 ':Z)) (T (+ y z)))) (de BzAdd (y z) (+ y z)) (de :Z:- (z y) (selectq (type-of y) (fix (cond ((ge y 0) (BnSetDigit :fix 0 y) (Z+Z z (BnNumDigits z 0 (BnGetSize z)) :fix 1 0 ':Z)) (T (BnSetDigit :fix 0 (sub 0 y)) (Z-Z z (BnNumDigits z 0 (BnGetSize z)) :fix 1 0 ':Z)))) (:N (Z+Z z (BnNumDigits z 0 (BnGetSize z)) y (BnNumDigits y 0 (BnGetSize y)) 0 ':Z)) (:Z (Z-Z z (BnNumDigits z 0 (BnGetSize z)) y (BnNumDigits y 0 (BnGetSize y)) 0 ':Z)) (T (+ (0- y) z)))) (de BzSubtract (y z) (- y z)) ; La longueur de la somme est 2 en 16 bits et 1 en 32 bits: (defvar :longueur-sommes (if (eq BN←DIGIT←SIZE 16) 2 1)) (de #:fix:+ (x y) (cond ((ge x 0) (BnSetDigit :fix 0 x) (selectq (type-of y) (fix (setq x (BnCreate ':N :longueur-sommes)) (BnSetDigit x 0 y) ; y>0 (BnAdd x 0 :longueur-sommes :fix 0 1 0) x) (:N (Z+Z y (BnNumDigits y 0 (BnGetSize y)) :fix 1 0 ':N)) (:Z (Z-Z y (BnNumDigits y 0 (BnGetSize y)) :fix 1 0 ':Z)) (t (+ y x)))) (T ; x < 0 (BnSetDigit :fix 0 (sub 0 x)) (selectq (type-of y) (fix (setq x (BnCreate ':Z :longueur-sommes)) (BnSetDigit x 0 (sub 0 y)) ; y<0 (BnAdd x 0 :longueur-sommes :fix 0 1 0) x) (:N (Z-Z y (BnNumDigits y 0 (BnGetSize y)) :fix 1 0 ':N)) (:Z (Z+Z y (BnNumDigits y 0 (BnGetSize y)) :fix 1 0 ':Z)) (t (+ y x)))))) (de #:fix:- (x y) (cond ((ge x 0) (BnSetDigit :fix 0 x) (selectq (type-of y) (fix (setq x (BnCreate ':N :longueur-sommes)) (BnSetDigit x 0 (sub 0 y)) ; y<0 (BnAdd x 0 :longueur-sommes :fix 0 1 0) x) (:N (Z-Z y (BnNumDigits y 0 (BnGetSize y)) :fix 1 0 ':Z)) (:Z (Z+Z y (BnNumDigits y 0 (BnGetSize y)) :fix 1 0 ':N)) (t (+ (0- y) x)))) (T ; x < 0 (BnSetDigit :fix 0 (sub 0 x)) (selectq (type-of y) (fix (setq x (BnCreate ':Z :longueur-sommes)) (BnSetDigit x 0 y) ; y>0 (BnAdd x 0 :longueur-sommes :fix 0 1 0) x) (:N (Z+Z y (BnNumDigits y 0 (BnGetSize y)) :fix 1 0 ':Z)) (:Z (Z-Z y (BnNumDigits y 0 (BnGetSize y)) :fix 1 0 ':N)) (t (+ y x)))))) ; .Section "La multiplication" (de Z*Z (n nl m ml p pl typ) (setq pl (add nl ml) ; Longueur de p=n*m. p (BnCreate typ pl)) ; Le produit p=n*m ; On peut supposer n plus long que m, soit nl>=ml: (when (gt ml nl) (psetq n m m n nl ml ml nl)) ; On fait le produit (BnMultiply p 0 pl n 0 nl m 0 ml) ; On renvoie le resultat: p)) ; (* x y) vaut le produit x*y: (de :N:* (n y) (selectq (type-of y) (fix (cond ((gt y 1) (BnSetDigit :fix 0 y) (Z*Z n (BnNumDigits n 0 (BnGetSize n)) :fix 1 0 0 ':N)) ((gt 0 y) (BnSetDigit :fix 0 (sub 0 y)) (Z*Z n (BnNumDigits n 0 (BnGetSize n)) :fix 1 0 0 ':Z)) (t (if (eq 0 y) 0 n)))) (:N (Z*Z n (BnNumDigits n 0 (BnGetSize n)) y (BnNumDigits y 0 (BnGetSize y)) 0 0 ':N)) (:Z (Z*Z n (BnNumDigits n 0 (BnGetSize n)) y (BnNumDigits y 0 (BnGetSize y)) 0 0 ':Z)) (T (* y n)))) (de :Z:* (n y) (selectq (type-of y) (fix (cond ((gt y 1) (BnSetDigit :fix 0 y) (Z*Z n (BnNumDigits n 0 (BnGetSize n)) :fix 1 0 0 ':Z)) ((gt 0 y) (BnSetDigit :fix 0 (sub 0 y)) (Z*Z n (BnNumDigits n 0 (BnGetSize n)) :fix 1 0 0 ':N)) (t (if (eq 0 y) 0 n)))) (:N (Z*Z n (BnNumDigits n 0 (BnGetSize n)) y (BnNumDigits y 0 (BnGetSize y)) 0 0 ':Z)) (:Z (Z*Z n (BnNumDigits n 0 (BnGetSize n)) y (BnNumDigits y 0 (BnGetSize y)) 0 0 ':N)) (T (* y n)))) (de BzMultiply (y z) (* y z)) (de #:fix:* (x y) (cond ((gt x 1) (BnSetDigit :fix 0 x) (selectq (type-of y) (fix (cond ((ge y 0) (setq x (BnCreate ':N 2)) (BnSetDigit :fix 1 y)) (T (setq x (BnCreate ':Z 2)) (BnSetDigit :fix 1 (sub 0 y)))) (BnMultiplyDigit x 0 2 :fix 0 1 :fix 1) x) (:N (Z*Z y (BnNumDigits y 0 (BnGetSize y)) :fix 1 0 0 ':N)) (:Z (Z*Z y (BnNumDigits y 0 (BnGetSize y)) :fix 1 0 0 ':Z)) (t (* y x)))) ((gt 0 x) (BnSetDigit :fix 0 (sub 0 x)) (selectq (type-of y) (fix (cond ((ge y 0) (setq x (BnCreate ':Z 2)) (BnSetDigit :fix 1 y)) (T (setq x (BnCreate ':N 2)) (BnSetDigit :fix 1 (sub 0 y)))) (BnMultiplyDigit x 0 2 :fix 0 1 :fix 1) x) (:N (Z*Z y (BnNumDigits y 0 (BnGetSize y)) :fix 1 0 0 ':Z)) (:Z (Z*Z y (BnNumDigits y 0 (BnGetSize y)) :fix 1 0 0 ':N)) (t (* y x)))) (t (if (eq 0 x) 0 y)))) ;;;;;;;;;;;;;;;;;;;;;;;;;MODIF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; .Section "Les tampons" ; Le tampon qui sert dans les soustractions, divisions et ; pour le prin: (defvar Ntampon (BnCreate '#:R:Q:N 4)) ; Entre les nl chiffres de n dans le tampon, suivis de nz zeros: (de EntreTampon (n nl nz) ; Verifie que la longueur du tampon est superieure a nl+nz, (unless (ge (BnGetSize Ntampon) (add nl nz)) ; sinon, augmente la longueur du tampon: (setq Ntampon (BnCreate '#:R:Q:N (add nl nz)))) (BnAssign Ntampon 0 n 0 nl) ; Recopie n dans le tampon, et ; remet a` 0 les chiffres de poids forts. (setq nz (sub (BnGetSize Ntampon) nl)) (when (gt nz 0) (BnSetToZero Ntampon nl nz))) ; Forme un entier avec les chiffres de n[nd..nd+nl-1] et coerce si possible. (de BnConvert (n nd nl) ; mise a` jour du nombre de chiffres de n (setq nl (BnNumDigits n nd nl)) (if (and (eqn nl 1) (neq (BnDoesDigitFitInWord n nd) 0)) ; n est un fix cache' (progn (if (equal (type-of n) ':N) (BnGetDigit n nd) (sub 0 (BnGetDigit n nd)))) ; n est un bignum (let ((nn (BnCreate (BnGetType n) nl))) (BnAssign nn 0 n nd nl) nn))) ; .Section "Division entiere" (defvar :fdiv (BnCreate ':N 1)) ; Retourne le quotient de n par d avec transit par Ntampon et mise a` ; jour de #:ex:mod. La philosophie est la suivante : on recopie n dans ; Ntampon et on le padde avec un nombre suffisant nz de 0. On divise Ntampon ; par d et on re'cupe`re le reste dans Ntampon[0..dl-1] et le quotient ; dans Ntampon[dl..nl+nz-1]. Ceci est valable dans tous les cas. (de :N:NquomodN (n d) (slet ((nl (BnNumDigits n 0 (BnGetSize n))) (dl (BnNumDigits d 0 (BnGetSize d))) (nz (add1 (sub dl nl)))); nz est le nombre de ze'ros dans Ntampon (selectq (BnCompare n 0 nl d 0 dl) (-1; n < d (setq #:ex:mod (BnConvert n 0 nl)) 0) ( 0; n = d (setq #:ex:mod 0) 1) ( 1; n > d (if (eqn (BnCompareDigits n (sub1 nl) d (sub1 dl)) -1) (progn (setq nz (max 0 nz)) (EntreTampon n nl nz) (BnDivide Ntampon 0 nl d 0 dl)) (setq nz (max 1 nz)) (EntreTampon n nl nz) (BnDivide Ntampon 0 (add1 nl) d 0 dl)) ; Le tampon contient le modulo sur 0...dl-1 (setq #:ex:mod (BnConvert Ntampon 0 dl)) ; et le quotient sur dl...nl+nz-1 (BnConvert Ntampon dl (sub (add nl nz) dl)))))) ; (quomod x y) renvoie le quotient entier q de x par y, et affecte ; le reste r dans #:ex:mod. Mathe'matiquement, q et r sont de'finis ; par x=q*y+r avec q entier relatif et r re'el, 0<=r<abs(y). (de :N:quomod (n y) (selectq (type-of y) (fix (selectq (<?> y 0) (1 (BnSetDigit :fdiv 0 y) (:N:NquomodN n :fdiv)) (0 (#:R:error 'quomod 'RDIV0 (list 'quomod n y))) (-1 (BnSetDigit :fdiv 0 (sub 0 y)) (0-N (:N:NquomodN n :fdiv))))) (:N (:N:NquomodN n y)) (:Z (0-N (:N:NquomodN n y))) (T (#:R:quomod n y)))) (de :Z:quomod (z y) (selectq (type-of y) (fix (selectq (<?> y 0) (1 (BnSetDigit :fdiv 0 y) (-CquoC z :fdiv)) (0 (#:R:error 'quomod 'RDIV0 (list 'quomod z y))) (-1 (BnSetDigit :fdiv 0 (sub 0 y)) (-Cquo-C z :fdiv)))) (:N (-CquoC z y)) (:Z (-Cquo-C z y)) (t (#:R:quomod z y)))) ; Revoir et changer : patch du 25/09/87 ; n=dq+r => -n=d*(-q-1)+d-r pour r>0 (de -CquoC (-n d); au de'part -n est ne'gatif (setq -n (:N:NquomodN (0- -n) d)); 0- -n > 0 (if (= 0 #:ex:mod) (0-N -n) (setq #:ex:mod (- d #:ex:mod)) (0-N (+ -n 1)))) ; n=dq+r => -n=-d*(q+1)+d-r (de -Cquo-C (-n -d); au de'part -n et -d sont ne'gatifs (setq -n (:N:NquomodN (0- -n) -d)) (if (= 0 #:ex:mod) -n (setq #:ex:mod (- (abs -d) #:ex:mod)) (+ -n 1))) (de BzDiv (y z) (quotient y z)) (de BzDivide (y z) (quotient y z)) (de BzMod (y z) (quotient y z) #:ex:mod)) ; .Section "Ecriture des grands entiers" ; .SSection "Manipulation de la base de sortie obase" ; La plus grande puissance de obase inferieure a` Base: (defvar :okmax 1) ; La plus grande puissance de la base qui est un fix: (defvar :okmaxp 1) ; Contient la table des puissances de obase jusqu'a k=:okmax (defvar :obase**k (BnCreate '#:R:Q:N (+ BN←DIGIT←SIZE 1))) ; Construit la table des puissances de obase, affecte :okmax et :okmaxp (de makeObase**k (ob) (let ( (k 0) (kp 0) ) (BnSetToZero :obase**k 0 (+ BN←DIGIT←SIZE 1)) (BnSetDigit :obase**k 0 ob) (while (neq (BnIsDigitZero :obase**k (incr k)) 0) (BnMultiplyDigit :obase**k k 2 :obase**k (sub1 k) 1 :obase**k 0)) (while (and (le kp k) (neq (BnDoesDigitFitInWord :obase**k kp) 0)) (setq kp (add1 kp))) (setq :okmaxp (sub1 kp)) (setq :okmax (sub k 2)))) ; Tampons (defvar :PrinTampon (BnCreate 'N 4)) (defvar :StrgSize 4005); un multiple de :okmax+1 (defvar :StrgTampon (makestring :StrgSize #/0)) (defun Nprin (n) ; (if (debug) ; (#:N:prin n) (slet ((nl (BnNumDigits n 0 (BnGetSize n))) (base (newobase)) (lBuf) (sf 0) (s :StrgTampon) (si 0) nq nr nrp sip (kmax+1 (add1 :okmax)) (kmaxp+1 (add1 :okmaxp)) ; taille maximale du buffer d'impression (SizeBuf (mul (div :StrgSize kmax+1) kmax+1))) (setq nq (add1 nl)) ; mise a` jour du tampon (when (gt (add nq 3) (BnGetSize :PrinTampon)) (setq :PrinTampon (BnCreate 'N (add nq 3)))) ; recopie de n (BnAssign :PrinTampon 0 n 0 nl) (BnSetToZero :PrinTampon nl 3) (setq nrp (add 2 (setq nr nq))) (while (gt nq 1) ; on re'cupe`re un chiffre<:obase**k[:okmax] dans :PrinTampon[nr] (BnDivideDigit :PrinTampon 0 :PrinTampon nr :PrinTampon 0 nq :obase**k :okmax) (setq sip si) (while (eq (BnIsDigitZero :PrinTampon nr) 0) ; on re'cupe`re un fix dans :PrinTampon[nrp] (BnDivideDigit :PrinTampon nr :PrinTampon nrp :PrinTampon nr 2 :obase**k :okmaxp ) ; on l'imprime (C2string (BnGetDigit :PrinTampon nrp) s sip base) ; on met a` jour l'adresse dans la chaine (setq sip (add sip kmaxp+1)) ) ; et voici pour Paul... (when (ge (setq si (add si kmax+1)) SizeBuf) (newl lBuf s) (setq s (makestring SizeBuf #/0) si 0)) (when (neq (BnIsDigitZero :PrinTampon (sub nq 2)) 0) (setq nq (sub1 nq)) )) ; s a au plus si caracte`res, on n'imprime pas les ze'ros de te↑te (while (and (gt si 0) (eq (sref s (setq si (sub1 si))) #/0))) (when (and (eq si 0) (eq (sref s si) #/0) lBuf) (setq s (nextl lBuf) si SizeBuf) (while (and (gt si 0) (eq (sref s (setq si (sub1 si))) #/0)))) ; on imprime tous les chiffres (while s (setq sf si) (while (ge si 0) (princn (sref s si)) (setq si (sub1 si))) (setq s (nextl lBuf)) (setq si (sub1 SizeBuf))) ; remise a` ze'ro de :StrgTampon ; sf contient l'adresse du chiffre de te↑te de :StrgTampon (fillstring :StrgTampon 0 #/0 (add1 sf)) ()))) ; table de transcodage des caracte`res (defvar :fixtocn "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") ; met dans la chaine s, a` partir de la place si, les caracte`res ; repre'sentant le fix 'fix dans la base 'base (defun C2string (fix s si base) (while (neq fix 0) (sset s si (sref :fixtocn (rem fix base))) (setq si (add1 si) fix (div fix base)) ) si ) (de :N:prin (n) (when #:system:print-for-read (let ((#:system:print-for-read ())) (prin "#{"))) (Nprin n) (when #:system:print-for-read (princn #/}))) (de :Z:prin (n) (when #:system:print-for-read (let ((#:system:print-for-read ())) (prin "#{"))) (unless (and (eq 1 (BnNumDigits n 0 (BnGetSize n))) (neq (BnIsDigitZero n 0) 0)) (princn #/-)) (Nprin n) (when #:system:print-for-read (princn #/}))) ; .SSection "Manipulation de la base d'entre'e obase" ; La plus grande puissance de ibase inferieure a` Base: (defvar :ikmax 1) ; La plus grande puissance de la base qui est un fix: (defvar :ikmaxp 1) ; Contient la table des puissances de ibase jusqu'a k=:kmax (defvar :ibase**k (BnCreate '#:R:Q:N (+ BN←DIGIT←SIZE 1))) ; La table de transcodage pour la semantique de lecture. (defvar :rtt (makestring 256 255)) ; Construit la table des puissances de obase, affecte :kmax et :kmaxp (de makeIbase**k (ib) (let ( (k 0) (kp 0) (i 255) ) (while (le i 0) (sset :rtt i 255) (setq i (sub1 i))) (setq i 0) (while (and (lt i 10) (lt i ib)) (sset :rtt (add #/0 i) i) (setq i (add1 i)) ) (while (lt i ib) (sset :rtt (add #/a (sub i 10)) i) (sset :rtt (add #/A (sub i 10)) i) (setq i (add1 i)) ) (BnSetToZero :ibase**k 0 (+ BN←DIGIT←SIZE 1)) (BnSetDigit :ibase**k 0 ib) (while (neq (BnIsDigitZero :ibase**k (incr k)) 0) (BnMultiplyDigit :ibase**k k 2 :ibase**k (sub1 k) 1 :ibase**k 0)) (while (and (le kp k) (neq (BnDoesDigitFitInWord :ibase**k kp) 0)) (setq kp (add1 kp))) (setq :ikmaxp (sub1 kp)) (setq :ikmax (sub k 2)))) (defun #:sharp:|{| () (let ( (b (newibase)) (i 0) c n m j (size 1) hight (s :StrgTampon) (lbuf ()) (inpos 0) strgsize (kmax+1 (add1 :ikmax)) (kmaxp+1 (add1 :ikmaxp)) (sgn ()) ) (setq strgsize (sub :StrgSize (rem :StrgSize kmax+1))) (while (eq (typecn (peekcn)) 'ecom) (readcn)) (when (eq (peekcn) #/-) (setq sgn t) (readcn)) (while (neq (setq c (readcn)) #/}) (unless (eq (sref :rtt c) 255) (sset s inpos c) (setq i (add1 i) inpos (add1 inpos)) (when (eq inpos strgsize) (newl lbuf s) (setq s (makestring strgsize #/0)) (setq inpos 0) ))) (setq n (BnCreate 'n (add 2 (div i kmax+1)))) (setq m (BnCreate 'n (add 2 (div i kmax+1)))) (setq s (:ReverseBuf s lbuf inpos strgsize)) (setq inpos (sub strgsize inpos)) (:StringToDigit s inpos (setq j (rem i kmax+1)) n b) (BnSetDigit n 1 0) (setq inpos (add inpos j)) (while (lt j i) (when (ge inpos strgsize) (when lbuf (setq s (nextl lbuf))) (setq inpos 0) ) (:StringToDigit s inpos kmax+1 m b) (BnSetToZero m 1 size) (BnMultiplyDigit m 0 (add1 size) n 0 size :ibase**k :ikmax) (when (eq (BnIsDigitZero m size) 0) (setq size (add1 size))) (psetq m n n m) (setq j (add j kmax+1) inpos (add inpos kmax+1)) ) (fillstring :StrgTampon 0 #/0 strgsize) (BnSetType n (if sgn '#:R:Q:Z '#:R:Q:N)) (ncons n) )) (defun :ReverseBuf (s l i n) (let ( (n-i (sub n i)) (ret ()) (sl l) ) (bltstring s n-i s 0 i) (while l (bltstring s 0 (car l) i n-i) (newl ret s) (setq s (nextl l)) (bltstring s n-i s 0 i) ) (when sl (displace sl ret)) s )) (defun :StringToDigit (s sd sl n ibase) (let ( (accu 0) i (kmaxp+1 (add1 :ikmaxp)) ) (repeat (setq i (rem sl kmaxp+1)) (setq accu (add (mul accu ibase) (sref :rtt (sref s sd))) sd (add1 sd) )) (BnSetDigit n 0 accu) (while (lt i sl) (setq accu 0) (repeat kmaxp+1 (setq accu (add (mul accu ibase) (sref :rtt (sref s sd))) sd (add1 sd) )) (setq i (add i kmaxp+1)) (BnAssign n 1 n 0 1) (BnSetDigit n 0 accu) (BnMultiplyDigit n 0 2 n 1 1 :ibase**k :ikmaxp) ) n )) ; .Section "Ope'rations avec les fixp Lisp" (package 'fix) ; x est un fix. (de :quomod (x y) (ifn (integerp y) (#:R:quomod x y) (if (and (eq 1 (BnNumDigits y 0 (BnGetSize y))) (neq (BnDoesDigitFitInWord y 0) 0)) (quomod x (BnGetDigit y 0)) (selectq (<?> x 0) (1 (selectq (type-of y) (#:R:Q:N (setq #:ex:mod x) 0) (#:R:Q:Z (setq #:ex:mod x) 0) (fix (if (eq y 0) (#:R:error 'quomod 'RDIV0 (list 'quomod x y)) (quomod x y))) (T (#:R:quomod x y)))) (0 (if (eq y 0) (#:R:error 'quomod 'RDIV0 (list 'quomod x y)) (setq #:ex:mod 0) 0)) (-1 (let ((q (:quomod (sub 0 x) y))) (cond ((eq #:ex:mod 0) (- q)) ((> y 0) (setq #:ex:mod (- y #:ex:mod)) (- -1 q)) (T (setq #:ex:mod (- #:ex:mod y)) (- 1 q))))))))) ; .Section "L'algorithme d'Euclide" ; Calcule le pgcd des nombres composant la liste l: (de gcd l (let ((pgcd 0) (n)) (while l (setq n (nextl l)) (ifn (integerp n) (#:R:error 'gcd 'RNOTZ (list 'gcd n l)) (setq pgcd (pgcd pgcd n)))) pgcd)) (package 'R) (package ':Q) (de pgcd (n m) (selectq (type-of n) (fix (#:fix:pgcd n m)) (':N (:Z:pgcd n m)) (':Z (:Z:pgcd n m)) (T (error 'pgcd 'errnna n)))) ; Pgcd avec au moins un bignum. (de :Z:pgcd (n m) (selectq (type-of m) (fix (fixpgcd (abs m) n)) (':N (:N:pgcd n m)) (':Z (:N:pgcd n m)) (T (error 'pgcd 'errnna m)))) ; Pgcd avec un fix. (de #:fix:pgcd (fix m) (selectq (type-of m) (fix (fixpgcdfix (abs fix) (abs m))) (':N (fixpgcd (abs fix) m)) (':Z (fixpgcd (abs fix) m)) (T (error 'pgcd 'errnna fix)))) ; Pgcd de deux fix. (de fixpgcdfix (n m) (if (eqn m 0) n (fixpgcdfix m (rem n m)))) ; Pgcd d'un fix et d'un bignum. (de fixpgcd (n m) (if (eqn n 0) m (fixpgcdfix (modulo m n) n))) ; Pgcd de deux bignums. (de :N:pgcd (n m) (let ((gl 0) (nl 0) (ml 0)) ; calcul des longueurs (setq nl (BnNumDigits n 0 (BnGetSize n)) ml (BnNumDigits m 0 (BnGetSize m))) ; mise a` jour du tampon (setq gl (add 2 (add nl ml))) (when (lt (BnGetSize Ntampon) gl) (setq Ntampon (BnCreate '#:R:Q:N gl))) ; on s'arrange pour que n >= m (if (eqn (BnCompare n 0 nl m 0 ml) -1) (setq gl (BnGcd Ntampon 0 m 0 ml n 0 nl)) (setq gl (BnGcd Ntampon 0 n 0 nl m 0 ml))) (BnConvert Ntampon 0 gl))) (de :N:pgcd (n m) (let ((ndl 0) (nl 0) (ml 0)) ; calcul des longueurs (setq nl (BnNumDigits n 0 (BnGetSize n)) ml (BnNumDigits m 0 (BnGetSize m))) ; mise a` jour du tampon (setq ndl (add 2 (add nl ml))) (when (lt (BnGetSize Ntampon) ndl) (setq Ntampon (BnCreate '#:R:Q:N ndl))) ; on s'arrange pour que n >= m (if (eqn (BnCompare n 0 nl m 0 ml) -1) (setq ndl (BnGcd m 0 ml n 0 nl)) (setq ndl (BnGcd n 0 nl m 0 ml))) (BnConvert Ntampon (car ndl) (cdr ndl)))) ; Calcul de pgcd(n, m) dans Ntampon. On suppose size(Ntampon) > nl + ml + 1 ; et n >= m. ; Au d'epart : Ntampon[0..ml-1] = m[0..ml-1] ; Ntampon[ml] = 0 ; Ntampon[ml+1..ml+nl] = n[0..nl-1] ; Ntampon[ml+nl+1] = 0 ; Retourne un cons forme' de l'index du premier chiffre de g et du nombre ; de chiffres du pgcd (de BnGcd (n nd nl m md ml) (let ((gmd 0) (gml ml) (gmf (sub1 ml)) (gnd (add1 ml)) (gnl nl) (gnf (add nl ml)) (tmp 0)) ; initialisation de Ntampon (BnAssign Ntampon gmd m md ml) (BnSetToZero Ntampon (add1 gmf) 1) (BnAssign Ntampon gnd n nd nl) (BnSetToZero Ntampon (add1 gnf) 1) ; on boucle tant que gm>0 (until (and (eqn gml 1) (neq (BnIsDigitZero Ntampon gmd) 0)) ; on divise Ntampon[gnd..gnd+gnl-1][0] ; par Ntampon[gmd..gmd+gml-1] (if (eqn (BnCompare Ntampon gnd gnl Ntampon gmd gml) 0) (progn (BnSetToZero Ntampon gnd gml); on met gn a` ze'ro (setq gnl 1)); on met a` jour la longueur (BnSetDigit Ntampon (add1 gnf) 0) (BnDivide Ntampon gnd (add1 gnl) Ntampon gmd gml) ; le reste se trouve sur Ntampon[gnd..gnd+gml-1] ; on met a` jour les longueurs (setq gnl (BnNumDigits Ntampon gnd gml)) (setq gnf (sub1 (add gnd gnl)))) ; on permute les adresses (setq tmp gnd gnd gmd gmd tmp) (setq tmp gnl gnl gml gml tmp) (setq tmp gnf gnf gmf gmf tmp)) ; le reste se trouve dans Ntampon[gnd..gnd+gnl-1] (cons gnd gnl))) ; .Section "Test de parite'" (package '#:R:Q) (de even? (n) (selectq (type-of n) (fix (evenp n)) (:N (if (neq (BnIsDigitOdd n 0) 0) () 0)) (:Z (if (neq (BnIsDigitOdd n 0) 0) () 0)) (T (if (numberp n) (send 'even? n) (#:R:error 'even? 'RNOTZ (list 'even? n)))))) ; .SSection "Exponentielle a` deux arguments" (de ** (x y) (cond ((< y 0) (/ (** x (- y)))) ((eq y 0) 1) ((integerp y) (:**N x y 1)) ((eq x 0) (if (eq 0 y) (/ 0 0) 0)) ((eq 1 x) 1) (T (power x y)))) ; Calcule p*(x**n) (de :**N (x n p) (if (eq 1 n) (* x p) (:**N (* x x) (quomod n 2) (if (= 0 #:ex:mod) p (* x p))))) ; .Chapitre IV "Les rationnels Q." ; (libload #u"/udd/lelisp/vuillemin/lib/q") ;;;;;;;;;;;;;;;;;;;;;;;;;MODIF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; .Section "Fibonacci et Factorielle" ; .SSection "Fibonnacci" ; F0 = 0, F1 = 1, Fn+2 = Fn+1 + Fn: (defvar TableFib '#[0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711 28657]) ; Pour calculer Fib(n) en O(logn) appels re'cursifs, on part de l'identite': ;.br ; F(n+m) = F(m)*F(n+1) + F(m-1)*F(n), dont on utilise les cas particulier: ;.br ; F(2p) = F(p)*(2F(p+1) - F(p)), F(2p+1) = F(p+1)**2 + F(p)**2. ; F(2p) = F(p)**2 + 2F(p)F(p-1), F(2p+1) = F(p+1)**2 + F(p)**2. (de fib (n) (unless (and (integerp n) (>= n 0)) (#:R:error 'fib 'RNOTZ (list 'fib n))) (Nfib n)) (de Nfib (n) (if (le n 23) (vref TableFib n) (lets ((taille (add1 (div n BN←DIGIT←SIZE))) (fn (BnCreate 'fn taille)) (fn+1 (BnCreate 'fn+1 taille)) (f2n (BnCreate 'f2n taille)) (f2n+1 (BnCreate 'f2n+1 taille)) (fl 0) (f2l 0) (sv)) (fibexp n) (EntreTampon fn taille 0) (BnConvert NTampon 0 taille)))) (de fibexp (n) (cond ((ge 23 n) (BnSetDigit fn 0 (vref TableFib n)) (BnSetDigit fn+1 0 (vref TableFib (add1 n))) (setq fl 1)) ((oddp n) (fibexp (sub1 n)) (when (eq 1 (BnAdd fn 0 fl fn+1 0 fl 0)) (BnSetDigit fn fl 1) (incr1 fl)) (psetq fn fn+1 fn+1 fn)) (T ; n=2p (fibexp (div n 2)) (setq f2l (add fl fl)) (BnMultiply f2n 0 f2l fn 0 fl fn 0 fl); fn*fn -> f2n (BnMultiply f2n+1 0 f2l fn+1 0 fl fn+1 0 fl) ; fn+1*fn+1 -> f2n+1 (BnAdd f2n+1 0 f2l f2n 0 f2l 0) ; fn**2+fn+1**2 -> f2n+1 (BnComplement fn+1 0 fl) ; B-1-fn+1 -> fn+1 (BnAdd fn+1 0 fl fn 0 fl 0) ; B-1-fn-1 -> fn+1 (BnComplement fn+1 0 fl) ; fn-1 -> fn+1 (BnAdd fn+1 0 fl fn+1 0 fl 0) ; 2*fn-1 -> fn+1 (BnMultiply f2n 0 f2l fn 0 fl fn+1 0 fl); fn*fn+2*fn-1*fn -> f2n (while (eq 0 (BnCompareDigits #:N:C0 0 f2n+1 (sub1 f2l))) (decr1 f2l)) (BnSetToZero fn 0 fl) (BnSetToZero fn+1 0 fl) (setq sv fn fn f2n f2n sv sv fn+1 fn+1 f2n+1 f2n+1 sv fl f2l f2l 0)))) ; .SSection "Factorielle" ; 0!=1 , n! = n*n-1! ; (fact 0) = 1 , (fact n) = (* n (fact (- n 1))) (de fact (n) (unless (and (integerp n) (>= n 0)) (#:R:error 'fact 'RNOTZ (list 'fact n))) (Nfact n)) ; On multiplie les produits i*(n-i) (de Nfact (n) (let ((fact 1)) (cond ((gt 8 n) (while (ge n 1) (setq fact (mul fact n) n (sub1 n)))) ((or (gt 350 n) (and (eq 32 BN←DIGIT←SIZE) (gt 501 n))) (EntreTampon #:N:C0 0 (sub (div n 2) 1)) (BnSetDigit Ntampon 1 5040) (let ((i 8) (fl 0)) (while (ge n i) (BnSetDigit Ntampon 0 (sub1 (if (eq n i) n (mul n i)))) (incr1 i) (decr1 n) (unless (neq (BnIsDigitZero Ntampon fl) 0) (incr1 fl)) (BnMultiplyDigit Ntampon 1 (add1 fl) Ntampon 1 fl Ntampon 0)) (setq fact (BnConvert Ntampon 1 (add1 fl))))) (T (print "Error Fact trop grande"))) fact)) ; .Section "Bootstrap" ; Change obase en construisant la table des puissances de obase: ; La fonction qui remplacera la fonction 'obase'. (de newobase l (ifn l (oldobase) (setq l (car l)) (oldobase l) (makeObase**k l) l)) ; Le bootstrap a` ne faire qu'UNE SEULE FOIS. (unless (equal (valfn (concat "obase")) (valfn 'newobase)) ; Une copie de la fonction 'obase' d'origine (pour 'newobase'). (synonym 'oldobase (concat "obase")) ; On cache PHYSIQUEMENT 'obase' pour les fonctions de'ja' compile'es (packagecell (concat "obase") 'old) ; On prend la nouvelle de'finition. (synonym (concat "obase") 'newobase)) ; Pour initialiser la table des puissances de obase: (obase (obase)) ; Change ibase en construisant la table des puissances de ibase: ; La fonction qui remplacera la fonction 'ibase'. (de newibase l (ifn l (oldibase) (setq l (car l)) (oldibase l) (makeIbase**k l) l)) ; Le bootstrap a` ne faire qu'UNE SEULE FOIS. (unless (equal (valfn (concat "ibase")) (valfn 'newibase)) ; Une copie de la fonction 'ibase' d'origine (pour 'newibase'). (synonym 'oldibase (concat "ibase")) ; On cache PHYSIQUEMENT 'ibase' pour les fonctions de'ja' compile'es (packagecell (concat "ibase") 'old) ; On prend la nouvelle de'finition. (synonym (concat "ibase") 'newibase)) ; Pour initialiser la table des puissances de ibase: (ibase (ibase)) ; Fin du fichier (setq #:system:read-case-flag #:backup:majuscules)