IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Problème d'arrondi lors de traitements sur des uint / ulong


Sujet :

C#

  1. #1
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 170
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 170
    Points : 7 422
    Points
    7 422
    Billets dans le blog
    1
    Par défaut Problème d'arrondi lors de traitements sur des uint / ulong
    Bonjour,

    J'ai un problème, je pense, d'arrondi lorsque je fais des traitements sur des uint et ulong.

    Contexte :
    Je suis en train de travailler sur une librairie perso d'encryption de fichiers.
    N'ayant aucune notion de cryptographie, mais fort du diction "diviser pour mieux régner", j'ai mis au point une méthode (certainement pas la meilleure) pour transformer en "bruit" n'importe quel fichier, et être capable de le reconstruire grâce à un dictionnaire.

    En fait, pour faire simple, c'est un Huffman inversé.

    Donc j'ai une chaîne "toto va à la plage".
    => Je compte chaque occurrence de chaque byte.
    => Puis je génère un dictionnaire qui prend cette fois non plus 256 valeurs possibles, mais 2^32 valeurs, en disant "bon le byte qui contient 't' peut être remplacé par n'importe quelle valeur entre X et Y". Le choix de la valeur entre X et Y se faisant de façon aléatoire, ce qui rend pour ainsi dire infini le nombre de version identiques d'un même fichier.

    Et c'est au moment de la génération de ce dictionnaire que je pense, j'ai des soucis.

    Voici un fichier en entrée :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Toto le haricot
    Ceci est un test pour voir si ça marche
     
    Et franchement, j'aimerais bien que ça marche !
    Une version du fichier crypté : (c'est joli tout plein)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Cöná¼Þ‚á§z¢¶w¡%!©ÞË*ށ…sJ+ù5ýœ‹ÁË*QR*Ç”Vñ˜(*7[z§¿4¢¶ï¬Ca
    4£cá>û7ljJ+È[êx—-uÀ%Zë	xJ+UÚ|iÙâ§z\/edó(¬’±iF/-V""â&H5}ìÜñßÈù¹âèôV!ïÖ»š¶Þ‚*òï@¦ÖÜï6®¨qùˆÎÁ[Ÿ’®§²Ð–ºº-®¨6Ú2? š(*&eeþô	ÎS³pﮧƒªdOŠÄ±Ç”VèaS½Ú‰Nôì}§{ÒŠóÈùOr×õfáNBV!ßè§zή¨¥aÑ›„•HŠÄï*&H]ô
    {‡¿g*nøÓƒ¤!cl>5(°&Gòéèû<ށŒV"~ží“9Ù¹6XR$‘ìÜ`§EbÔmøÓL̉FQŠÄkª¡Ú4¢Å"dóZ~Íý“±În›ƒ¥*psf4dÒÆ7Oø½agøÓ51V""ÿí®Iöni®§Ý¦‘ò…Iön³Ñì÷d©ß†/Ú/wìÝV!Á8]
    Et enfin, la version presque décryptée car j'ai un bug :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Toto ÿe haricot
    ÿeci est un test pour vpir si ça marche
     
    Tt franchement, j!aimerais cien que ça marche !
    Ça marche presque pas mal... Mais comme à mon habitude, y'a jamais moyen d'avoir un programme qui marche à 100%...

    Alors voici des parties de code susceptibles d'être responsables. Je n'arrive pas à comprendre où ça merde :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
     
                dictionary = new byte[256 * 8];
                byte[] arr1 = new byte[4];
                byte[] arr2 = new byte[4];
     
                for (int i = 0, cpt = this.Capacity; i < cpt; i++)
                {
                    this[i].Position = (uint)(((ulong)uint.MaxValue * (ulong)this[i].Position) / (ulong)total);
                    this[i].Length = (uint)(((ulong)uint.MaxValue * (ulong)this[i].Length) / (ulong)total);
                    UInt32ToByte(arr1, 0, this[i].Position);
                    UInt32ToByte(arr2, 0, this[i].Length);
                    AddToDictionary(arr1, arr2, i * 8);
                }
     
            private void AddToDictionary(byte[] arr1, byte[] arr2, int index)
            {
                dictionary[index + 0] = arr1[0];
                dictionary[index + 1] = arr1[1];
                dictionary[index + 2] = arr1[2];
                dictionary[index + 3] = arr1[3];
                dictionary[index + 4] = arr2[0];
                dictionary[index + 5] = arr2[1];
                dictionary[index + 6] = arr2[2];
                dictionary[index + 7] = arr2[3];
            }
     
            private static void UInt32ToByte(byte[] arr, int index, ulong value)
            {
                arr[index + 0] = (byte)(value >> 24);
                arr[index + 1] = (byte)((value >> 16) & 0xFF);
                arr[index + 2] = (byte)((value >> 8) & 0xFF);
                arr[index + 3] = (byte)(value & 0xFF);
            }
     
            private static uint BytesToUInt32(byte[] arr, int index)
            {
                return ((uint)arr[index + 0] << 24) | (((uint)arr[index + 1] << 16) & 0xFF) | (((uint)arr[index + 2] << 8) & 0xFF) | ((uint)arr[index + 3] & 0xFF);
            }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
            public void Encrypt(byte[] arr, byte value)
            {
                UInt32ToByte(arr, 0, UInt32Random(this[value].Position, this[value].Length, rnd));
            }
     
            private static uint UInt32Random(uint min, uint length, Random rand)
            {
                byte[] buf = new byte[8];
                rand.NextBytes(buf);
                ulong ulongRand = (ulong)BytesToUInt32(buf, 0);
                return (uint)(ulongRand % (ulong)length + (ulong)min);
            }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
            public byte Decrypt(byte[] arr)
            {
                uint value = BytesToUInt32(arr, 0);
                for (int i = 0; i < 256; i++)
                {
                    if (this[i].Position <= value && this[i].Position + this[i].Length > value)
                    {
                        return (byte)i;
                    }
                }
                return 255;
            }
    Si une âme charitable pouvait jeter un oeil là dessus et me dire où j'ai pu faire une bêtise...

    En pièce jointe, vous trouverez les sources complètes (aucun commentaire, ni documentation pour le moment).
    Fichiers attachés Fichiers attachés

  2. #2
    Membre averti Avatar de pascalCH
    Homme Profil pro
    Formateur en informatique
    Inscrit en
    Juillet 2006
    Messages
    187
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 66
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Formateur en informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Juillet 2006
    Messages : 187
    Points : 369
    Points
    369
    Par défaut
    j'imagine que ce genre de ligne - et surtout les casts en cascades - sont là pour éradiquer les warning du comiplateur

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
                    this[i].Position = (uint)(((ulong)uint.MaxValue * (ulong)this[i].Position) / (ulong)total);
                    this[i].Length = (uint)(((ulong)uint.MaxValue * (ulong)this[i].Length) / (ulong)total);
    ulong * ulong / ulong <==> 64 bits * 64 bits / 64 bits <=> 128 bits / 64 bits ...

    en C++ il existe une fonction MulDiv qui corrige ce problème d'overflow, je n'ai pas trouvé d'équivalent en c#.

    donc, une solution consiste sans doute à passer par des UInt32, le calcul se fera sur des ulong sans débordement

    @+

  3. #3
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 170
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 170
    Points : 7 422
    Points
    7 422
    Billets dans le blog
    1
    Par défaut
    Non, les cast en cascade sont là pour justement, forcer .NET à conserver le niveau de précision voulue.

    En effet, à la base, j'ai :

    (uint32 * uint32) / uint32

    sauf que si les deux premiers paramètres sont trop grands, je vais avoir un dépassement de capacité. Donc je les force en uint64 afin de ne pas prendre ce risque que mes données soient tronquées (ou qu'il y ait un plantage).
    Je divise donc ensuite par un uint64 toujours pour la même raison.
    Donc j'ai pas besoin de passer par un uint128, uint64 est en toute logique suffisant.

    Mais sinon heu... Je viens de me rendre compte d'un truc... Le nombre de valeurs possibles dans un uint, c'est pas uint.MaxValue mais uint.MaxValue + 1

    Je me demande si le souci ne vient pas tout simplement de là...

    En effet, du coup j'ai des trous dans le gruyère, voir même des chevauchements de plage.

    Dès que j'ai 5 minutes, je refait un test avec uint.MaxValue + 1 pour voir...

Discussions similaires

  1. Réponses: 12
    Dernier message: 08/02/2007, 10h17
  2. Réponses: 8
    Dernier message: 14/09/2006, 17h43
  3. [MySQL] problème de caractères lors de la récupération des données
    Par lecail65 dans le forum PHP & Base de données
    Réponses: 8
    Dernier message: 02/08/2006, 17h45
  4. traitement sur des secondes
    Par richou dans le forum VB 6 et antérieur
    Réponses: 2
    Dernier message: 20/03/2006, 12h00
  5. Problème d'attribut de lecture seule sur des dossiers
    Par Redbull dans le forum Sécurité
    Réponses: 2
    Dernier message: 09/08/2005, 10h52

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo