Corriger des erreurs

publicité
Corriger des erreurs
Renaud Rioboo
Projet Groupe 1.1
Contexte
L’informatique manipule d’une manière ou d’une autre des suites de bits qui
doivent être traités exactement. Une erreur inversant un bit change complètement
le sens de la suite et on essaie d’éviter ces erreurs en ajoutant de la redondance
aux données pour pouvoir les détecter voire les corriger.
La technique la plus connue est celle du bit de parité où on code k bits
b1 , . . . bk en ajoutant un bit bk+1 de façon à ce que la somme des k + 1 bits à un
soit paire.
Si une erreur a affecté la suite (bi )i=k+1
lors d’une transmission ou d’une
i=1
écriture sur un support physqique on reçoit une suite (b0i )i=k+1
dont la parité
i=1
est fausse. Si par contre aucune erreur n’a eu lieu la parité est bonne. Dans le
cas de deux erreurs ou plus on ne peut bien sur rien dire.
Un tel codage est dit détecteur d’une erreur sur un bloc de k + 1 bits. Un
code qui corrigerait une erreur serait dit correcteur d’une erreur.
Pour formaliser cette technique on se place dans le corps à deux éléments F2
et on a
Σi=k+!
i=1 bi = 0
En général on interprète la suite (b0i )i=k+1
comme le polynôme P (X) =
i=1
et l’équation devient simplement P (1) = 0 dans F2 [X] l’ensemble
des polynômes à coefficients sur F2 . Ceci revient à dire que le polynôme P est
divible par X − 1 (qui vaut aussi X + 1 dans F2 [X]).
Plus généralement les codes dits cycliques encore appelés CRC (Cyclic Redundancy Check) permettent de détecter et de corriger plus d’une erreur et sont
utilisés dans tous les supports modernes de données. Le code est alors formé
de l’ensemble des multiples d’un polynôme générateur Pc . Ces codes sont dits
cycliques car Pc est un diviseur de X N − 1 pour un certain N .
On se fixe donc un polynôme de test Pc de degré k et, pour coder un
polynôme Pu , on calcule R de degré inférieur à k − 1 pour que Pe = X k Pu + R
soit mulitple de Pc . Ainsi R est le reste de la division Euclidienne de X k Pu par
Pc . Pour tester si un polynôme P est dans le code il nous suffit de calculer le
reste de la division Euclidienne de P par Pc et si ce reste est nul on tronque les
k derniers bits.
Σi=k+1
bi X k+1−i
i=1
1
Le Travail
Notre but est d’implémenter une librairie de polynômes pour effectuer la division
Euclidienne des polynômes.
Vous devrez rendre sur le serveur de dépôts une archive contenant vos sources
et un rapport au format pdf expliquant vos choix d’implémentation ainsi que
les algorithmes utilisés.
Bien que pour ce sujet nous n’utiliserons que des polynômes de F2 [X] les
CRC utilisés en pratique travaillent dans F256 [X] où les coefficients sont dans le
corps à 256 éléments. Nous voulons avoir un code générique où les algorithmes
sur les polynômes peuvent s’exprimer sur n’importe quel corps de coefficients.
Les Nombres
Le corps F2 contient les deux éléments 0 et 1, nous utiliserons des entiers pour
les représenter. Nous devons donc définir un type de données Field ainsi que
des opérations de base pour l’arithmétique, les tests et l’impression.
Les Polynômes
Traditionellement les polynômes sont représentés par des listes de monômes
qui sont des couples formés d’un degré et d’un coefficient. Le degré est en
général un entier non signé et le coefficient un élément non nul d’un anneau K
dont les valeurs peuvent être représentés de différentes façons. Les listes sont
implicitement triées par ordre décroissant des monômes, c’est-à-dire que les plus
hauts degrés sont au début de la liste.
0.0.1
Addition et soustraction
Étant donnés deux polynômes P et Q, il vient de la représentation que si P et
Q sont non nuls ils se décomposent en:
P = cp X dp + P 0
Q = cq X dq + Q0
où cp et cq sont non nuls dans K sans calculs.
La somme S des polynômes P + Q peut donc se calculer par l’une des formules:
S = cp X dp + (P 0 + Q)
S = cq X dq + (P + Q0 )
S = cX d + (P 0 + Q0 )
avec c = cp + cq et d = dp = dq et en fonction de la comparaison entre dp et dq .
Ici la somme cp + cq s’effectue bien sûr dans K.
Dans la formule précédente seule la somme P 0 +Q0 est récursive. On prendra
en outre soin de ne pas construire le monôme cX d lorsque c est nul dans K.
L’algorithme est donc le même que celui qu’on applique à la main et la
soustraction de fait de la même manière.
2
1
Multiplication
Il n’est pas nécessaire de coder la multiplication pour la division Euclidienne
mais il vous est quand même demandé de le faire. On procède comme à la main
et on décompose deux polynômes P et Q en:
P = cp X dp + P 0
Q = cq X dq + Q0
comme plus haut. La multiplication consiste à calculer le produit Mq P où Mq
est le monôme cq X dq lorsque Q est non nul.
Le produit Mq P est nul si P est nul. Sinon on l’exprime récursivement en
fonction du produit Mq P 0 et de c = cp cq :
cX dp +dq + Mq P 0 .
La Division Euclidienne
Pour un polynôme A et un polynôme non nul B, la division Euclidienne de A
par B consiste à calculer un quotient Q et un reste R tels que
A = BQ + R
où R est nul ou de degré strictement inférieur celui de B. On décompose
A = ca X da + A0
B = cb X db + B 0
et le premier monôme du quotient est ca /cb X da −db . Il suffit ensuite de procéder
récursivement.
2
Mise en œuvre
Le fichier crc.c suivant vous propose quelques notations pour vous aider:
/* Cyclic codes */
#include <stdlib.h>
#include <stdio.h>
#define Field int
typedef struct p_data{
Field coef;
int deg;
struct p_data* red;} p_val;
typedef p_val* Poly;
3
// fonctions du corps de base
Field base_add(Field x, Field y) {return((x == y)? 0: 1);};
// On peut remarquer que modulo 2 + et - sont la m^
eme operation
Field base_sub(Field x, Field y) {return((x == y)? 0: 1);};
Field base_mult(Field x, Field y) {return(x? y: x);};
int base_is_zero(Field x) {return(x);};
void base_print(Field x) {printf("%d", x);};
Field base_zero = 0;
Field base_one = 1;
// la valeur polynomiale 0
Poly poly_zero = NULL;
//quelques fonctions a implanter
Poly poly_add(Poly p1, Poly p2) {return(NULL);};
Poly poly_sub(Poly p1, Poly p2) {return(NULL);};
Poly poly_mult(Poly p1, Poly p2) {return(NULL);};
// ring_to_poly(v) suppose que v n’est pas nul dans l’anneau. fixme!
Poly ring_to_poly(Field v) {
p_val* temp = malloc(sizeof(p_val));
temp->coef = v;
temp->deg = 0;
temp->red = poly_zero;
return(temp);
}
int main(){
return((ring_to_poly(base_one))->deg);
}
4
Téléchargement