• Aucun résultat trouvé

Dans cette section, nous présentons comment sont implantés CompHorner et DDHorner, et montrons quels sont les surcoûts introduits en pratique par ces deux algorithmes.

5.2.1 Implantations pratique de CompHorner

On considère l'évaluation de p(x) à l'aide du schéma de Horner compensé (algorithme 4.3). Tel que présentée au chapitre 4, cette évaluation compensée s'eectue en trois étapes :

1. calcul de Horner(p, x) et des deux polynômes pπ et pσde degré n−1 par EFTHorner(p, x), 2. évaluation de (pπ + pσ)(x) avec Horner(pπ⊕ pσ, x),

5.2. Performances en pratique 63 3. nalement, calcul du résultat compensé r.

Il est facile de voir que les deux premières étapes peuvent être regroupées, en évitant ainsi le stockage des polynômes pπ et pσ. Le schéma de Horner compensé sera donc implanté en pratique à l'aide d'une simple boucle, comme indiqué ci-dessous.

function r = CompHorner(P, x) [xh, xl] = Split(x) rn= an; cn = 0 for i = n − 1 : −1 : 0 [pi, πi] = TwoProdxh,xl(ri+1, x) [ri, σi] = TwoSum(pi, ai) ci = ci+1⊗ x ⊕ (πi⊕ σi) end r = r0⊕ c0

Notons bien que le découpage de x en xh + xl n'est eectué qu'une seule fois avant le début de la boucle, de manière à réduire le coût du calcul de TwoProd(ri+1, x). C'est ce qui est fait dans l'implantation en langage C de CompHorner proposée ci-dessous. On peut voir que cette implantation nécessite 22n + 5 opérations ottantes.

double CompHorner(double *P, unsigned int n, double x) { double p, r, c, pi, sig, x_hi, x_lo, hi, lo, t;

int i;

/* Split(x_hi, x_lo, x) */

t = x * _splitter_; x_hi = t - (t - x); x_lo = x - x_hi; r = P[n]; c = 0.0;

for(i=n-1; i>=0; i--) {

/* TwoProd(p, pi, s, x); */ p = r * x;

t = r * _splitter_; hi = t - (t - r); lo = r - hi; pi = (((hi*x_hi - p) + hi*x_lo) + lo*x_hi) + lo*x_lo; /* TwoSum(s, sigma, p, P[i]); */

r = p + P[i]; t = r - p;

sig = (p - (r - t)) + (P[i] - t); /* Computation of the error term */ c = c * x + (pi+sig);

}

return(r+c); }

5.2.2 Algorithme de Horner en arithmétique double-double

Nous rappelons ci-dessous le schéma de Horner eectué en utilisant l'arithmétique double  voir chapitre 3, algorithme 3.27. Rappelons également qu'un

double-64 Chapitre 5. Performances du schéma de Horner compensé double a est un couple de ottants (ah, al) avec a = ah + al et |al| ≤ 1

2ulp(ah). Cette dernière propriété impose une étape de renormalisation à la n de chaque opération arith-métique sur les double-doubles : c'est ici l'algorithme FastTwoSum (algorithme 3.1) qui assure cette renormalisation. Par exemple, la ligne [shi, sli] = FastTwoSum(th, tl) dans l'algorithme 3.27 assure que le couple (shi, sli) satisfait |sli| ≤ 1

2ulp(shi), et constitue donc bien un double-double valide.

Algorithme 5.1. Algorithme de Horner en arithmétique double-double function r = DDHorner(P, x)

[xh, xl] = Split(x) shn= ai; sln = 0 for i = n − 1 : −1 : 0

% double-double = double-double × double : % (phi, pli) = (shi+1, sli+1) ⊗ x

[th, tl] = TwoProdxh,xl(shi+1, x) tl = sli+1⊗ x ⊕ tl

[phi, pli] = FastTwoSum(th, tl)

% double-double = double-double + double : % (shi, sli) = (phi, pli) ⊕ ai [th, tl] = TwoSum(phi, ai) tl = tl ⊕ pli [shi, sli] = FastTwoSum(th, tl) end r = sh0

A nouveau, on constate que x est découpé une fois pour toute avant le début de la boucle. Nous fournissons également ci-dessous une implantation en langage C du schéma de Horner avec l'arithmétique double-doubles. Cette implantation requiert 28n + 4 opérations ottantes.

double DDHorner(double *P, unsigned int n, double x) { double r_h, r_l, t_h, t_l, x_hi, x_lo, hi, lo, t; int i;

/* Split(x_hi, x_lo, x) */

t = x * _splitter_; x_hi = t - (t - x); x_lo = x - x_hi; r_h = P[n]; r_l = 0.0;

for(i=n-1; i>=0; i--) {

/* (r_h, r_l) = (r_h, r_l) * x */

t = r_h * _splitter_; hi = t - (t - r_h); lo = (r_h - hi); t_h = r_h * x;

t_l = (((hi*x_hi-t_h) + hi*x_lo) + lo*x_hi) + lo*x_lo; t_l += r_l * x;

5.2. Performances en pratique 65 r_l = (t_h - r_h) + t_l; /* (r_h, r_l) = (r_h, r_l) + P[i] */ t_h = r_h + P[i]; t = t_h - r_h; t_l = ((r_h - (t_h - t)) + (P[i] - t)); t_l += r_l; r_h = t_h + t_l; r_l = (t_h - r_h) + t_l; } return(r_h); }

5.2.3 Résultats expérimentaux

Pour nos expériences, nous avons codé les fonctions C CompHorner et DDHorner, telles que décrites ci-dessus, en utilisant la double précision IEEE-754 comme précision de travail. Les environnements expérimentaux sont listés dans le tableau 5.1.

Tab. 5.1  Environnements expérimentaux. Environnement Description

(I) Intel Pentium 4, 3.0GHz, GNU Compiler Collection 4.1.2, fpu x87 (II) Intel Pentium 4, 3.0GHz, GNU Compiler Collection 4.1.2, fpu sse (III) Intel Pentium 4, 3.0GHz, Intel C Compiler 9.1, fpu x87

(IV) Intel Pentium 4, 3.0GHz, Intel C Compiler 9.1, fpu sse

(V) AMD Athlon 64, 2 GHz, GNU Compiler Collection 4.1.2, fpu sse (VI) Itanium 2, 1.5 GHz, GNU Compiler Collection 4.1.1

(VII) Itanium 2, 1.5 GHz, Intel C Compiler 9.1

Nos mesures sont eectuées à l'aide d'un jeu de 39 polynômes, dont les coecients sont choisis aléatoirement, et dont le degré varie de 10 à 200 par pas de 5. Pour chaque degré considéré, on mesure le ratio du temps d'exécution de CompHorner sur le temps d'exécution du schéma de Horner classique Horner : cette mesure quantie le surcoût introduit par Com-pHorner en comparaison de Horner. On eectue également cette mesure pour l'algorithme DDHorner.

Le tableau Table 5.2 résume les mesures eectuées : nous y avons reporté, pour chaque algorithme et chaque environnement, la moyenne des ratios mesurés, sur l'ensemble des 39 polynômes considérés. Les résultats détaillés de ces mesures sont fournis en annexe.

Premièrement, on observe que les surcoûts mesurés sont toujours signicativement plus faibles que ceux auxquels on aurait pu s'attendre d'après le décompte des opérations ot-tantes. En eet, si l'on ne considère que ces décomptes,

CompHorner

Horner = 22n + 52n ≈ 11, et DDHorner

Horner = 28n + 42n ≈ 14.

D'autre part, on constate que CompHorner s'exécute au moins deux fois plus rapidement en pratique que DDHorner. Insistons à nouveau sur le fait que les décomptes des opérations

66 Chapitre 5. Performances du schéma de Horner compensé Tab. 5.2  Surcoût moyen introduit par CompHorner et DDHorner.

Environnement CompHorner Horner DDHorner Horner (I) P4, gcc, x87 2.8 8.6 (II) P4, gcc, sse 3.1 8.9 (III) P4, icc, x87 2.7 9.0 (IV) P4, icc, sse 3.3 9.8 (V) Ath64, gcc, sse 3.2 8.7

ottantes ne permettent pas d'expliquer de telles performances. Dans ce cas, on a en eet DDHorner

CompHorner = 28n + 422n + 5 ≈ 1.3.

Les simples décomptes d'opérations ottantes sont donc clairement insusants pour expliquer les diérences de performances entre CompHorner et DDHorner.

5.2.4 Diérence algorithmique entre CompHorner et DDHorner

On compare ci-dessous une version modiée de l'algorithme CompHorner à l'algorithme DDHorner. La modication apportée à CompHorner consiste simplement à changer l'ordre des opérations dans le calcul de ci en fonction de ci+1, x, πi et σi.

function r = CompHorner0(P, x) [xh, xl] = Split(x) rn = ai; cn= 0 for i = n − 1 : −1 : 0 [ai, πi] = TwoProd(ri+1, x) t = ci+1⊗ x ⊕ πi [ri, σi] = TwoSum(pi, ai) ci = ti⊕ σi end r = r0⊕ c0 function r = DDHorner(P, x) [xh, xl] = Split(x) shn = ai; sln= 0 for i = n − 1 : −1 : 0 % (phi, pli) = (shi+1, sli+1) ⊗ x [th, tl] = TwoProdxh,xl(shi+1, x) tl = sli+1⊗ x ⊕ tl [phi, pli] = FastTwoSum(th, tl) % (shi, sli) = (phi, pli) ⊕ ai [th, tl] = TwoSum(phi, ai) tl = tl ⊕ pli [shi, sli] = FastTwoSum(th, tl) end r = sh0

On constate ainsi clairement que les algorithmes CompHorner et DDHorner eectuent essentiellement les mêmes opérations ottantes, à la diérence près que les étapes de re-normalisation sont supprimées dans CompHorner : CompHorner eectue ainsi au total 6n opérations de moins que DDHorner.

La suppression de ces 6n opérations ottantes ne permet clairement pas d'expliquer à elle seule le fait que CompHorner s'exécute en pratique deux fois plus rapidement que DDHorner. Cependant nous verrons à la section suivante que, grâce à la suppression de des étapes de renormalisation, CompHorner présente signicativement plus de parallélisme d'instruction que DDHorner.