1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
|
// file kernel/n/c/zimmermann.c: Zimmermann square root
/*-----------------------------------------------------------------------+
| Copyright 2005-2006, Michel Quercia (michel.quercia@prepas.org) |
| |
| This file is part of Numerix. Numerix is free software; you can |
| redistribute it and/or modify it under the terms of the GNU Lesser |
| General Public License as published by the Free Software Foundation; |
| either version 2.1 of the License, or (at your option) any later |
| version. |
| |
| The Numerix Library is distributed in the hope that it will be |
| useful, but WITHOUT ANY WARRANTY; without even the implied warranty |
| of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| Lesser General Public License for more details. |
| |
| You should have received a copy of the GNU Lesser General Public |
| License along with the GNU MP Library; see the file COPYING. If not, |
| write to the Free Software Foundation, Inc., 59 Temple Place - |
| Suite 330, Boston, MA 02111-1307, USA. |
+-----------------------------------------------------------------------+
| |
| Racine carre de Zimmermann |
| |
+-----------------------------------------------------------------------*/
/* +-----------------+
| Racine carre |
+-----------------+ */
/*
entre :
a = naturel de longueur la
b = naturel de longueur la/2
contraintes :
la > 0, la pair, BASE/16 <= a[la-1] < BASE/4
a,b non confondus
sortie :
b <- 2*floor(sqrt(a))
a <- a - b^2/4
*/
#ifndef assembly_sn_zimsqrt
#ifdef debug_zimsqrt
void xn(zimsqrt_buggy)
#else
void xn(zimsqrt)
#endif
(chiffre *a, long la, chiffre *b) {
long p,q;
chiffre *x;
/* petite racine -> sqrt_n2 */
if (la <= zimsqrt_lim) {xn(sqrt_n2)(a,la,b); return;}
/* cas rcursif : divise a en 2 et calcule la racine du haut */
p = la/4; q = la/2-p;
xn(zimsqrt)(a+2*p,2*q,b+p);
/* divise le reste par 2b[p..p+q-1] */
if (xn(cmp)(a+2*p,q,b+p,q)) xn(burnidiv)(a+p,p,b+p,q,b);
else {
xn(fill)(b,p);
xn(clear)(a+2*p,q);
xn(inc)(a+p,p+q,b+p,q);
}
/* retranche le carr du quotient et dcale le quotient */
x = xn(alloc_tmp)(2*p);
xn(toomsqr)(b,p,x);
xn(dec)(a,p+q+1,x,2*p);
xn(free_tmp)(x);
if (xn(shift_up)(b,p,b,1)) b[p]++;
/* si < 0, corrige */
while(a[p+q]) {
xn(dec1)(b,p+1);
xn(inc)(a,p+q+1,b,p+q);
b[0]--;
}
}
#endif /* assembly_sn_zimsqrt */
/* +------------+
| Contrle |
+------------+ */
#ifdef debug_zimsqrt
void xn(zimsqrt_buggy)(chiffre *a, long la, chiffre *b);
void xn(zimsqrt)(chiffre *a, long la, chiffre *b) {
long lb = la/2;
chiffre *x,*y, r;
/* vrifie que la est pair > 0 et BASE/16 <= a[la-1] < BASE/4 */
if ((la%2) || (la < 2))
xn(internal_error)("error, zimsqrt is called with la odd or la < 2",0);
r = a[la-1] >> (HW-4);
if ((r == 0) || (r > 3))
xn(internal_error)("error, zimsqrt is called without BASE/16 <= msb(la) < BASE/4",1,a,la);
/* calcule la racine carre douteuse */
x = xn(alloc_tmp)(2*la); y = x + la;
xn(move)(a,la,x);
xn(zimsqrt_buggy)(a,la,b);
/* vrifie que a_entre = a_sortie + (b/2)^2 et a_sortie <= b */
xn(toomsqr)(b,lb,y);
r = xn(shift_down)(y,la,y,2);
if (r == 0) r = xn(inc)(y,la,a,lb);
if (r == 0) r = xn(cmp)(x,la,y,la);
if (r == 0) r = (xn(cmp)(a,lb,b,lb) > 0);
if (r) xn(internal_error)("error in zimsqrt", 3,x,la,b,lb,a,lb);
xn(free_tmp)(x);
}
#endif /* debug_zimsqrt */
|