0
votes

Comment écrire de manière générale un double type de données dans le fichier C

Je dois stocker des valeurs double dans un fichier d'une manière qui sera portable. Je sais que je peux simplement les écrire sous forme lisible humaine comme 1.23456789 , mais j'espère économiser de l'espace en les écrivant comme binaire.

Je sais comment écrire binaire dans un fichier, mais existe-t-il un moyen de le faire d'une manière dans laquelle le fichier résultant sera le même quelle que soit la machine sur laquelle le code a été compilé et exécuté? J'espère pouvoir lire / écrire de tels fichiers sur des machines de cette manière.


13 commentaires

La voie normale facile est d'utiliser une bibliothèque de sérialisation croisée comme msgpack ou Google Protocol Tampers


Intéressant, je vais vérifier.


Il est excessivé si la chose seulement vous devez sérialiser est double, mais cela est extrêmement improbable.


Ouais, j'avais effectivement besoin d'écrire des entiers aussi, sauf que je pensais que j'avais que cela figurait depuis qu'il existe des types de données entier de taille fixe fournis (int16_t, int32_t), mais j'ai oublié que l'endansité peut passer de la machine à la machine. Je vais donc probablement utiliser msgpack. Merci1


Vous essayez de gagner de l'espace car le stockage est si cher? En écrivez-vous plus d'un million de doubles? Utilisez simplement une bibliothèque JSON.


Oui, j'écris beaucoup de doubles. Pourquoi Json et pourquoi pas msgpack?


@ NC404 - L'usage typique de JSON fera vos données 1) un peu auto-documentant, 2) lisible par l'homme, 3) facilement modifiable, 4) Lisible par de nombreuses langues, et 5) Lisible par de nombreuses langues Nativement et 6) sans changement de compilation automatiquement requis pour les modifications de données. C'est aussi (généralement) 7) plus grand et plus lent. L'utilisation typique des tampons de protocole Google vous donnera 1, 3 et 4.


Il n'est pas possible d'écrire des valeurs double dans un format de manière universelle portable dans les implémentations C. Preuve: C Définit une valeur à virgule flottante pour être un chiffre dans une base multipliée par la base à une puissance (C 2018 5.2.4.2.2 3). La longueur du chiffre et la base sont définies par la mise en oeuvre. Certains chiffres représentables dans une implémentation C, telle que 1/10 dans une mise en œuvre de base-dix, ne sont pas représentables dans d'autres. Par conséquent, quelle que soit la chaîne est écrite dans un fichier, il n'est pas possible de reconstruire la valeur dans une implémentation C utilisant un point flottant binaire.


Si vous pouvez supposer que les systèmes impliqués, utilisez le même format de base binaire pour double (ou au moins utilisez un format de base binaire et chaque système est capable de représenter toutes les valeurs requises), puis utilisez le % A format d'entrée et de sortie. Cela utilise une notation hexadécimale qui représente des valeurs facilement et exactement (c'est-à-dire sans aucun arrondi nécessaire).


Si vous avez besoin de compresser plus loin que cela, puis pouvez assumer une base binaire, puis écrivez un peu pour le signe, les bits de signification et l'exposant en binaire. Vous pouvez obtenir les bits pour signification et l'exposant en utilisant frexp . Vous devrez décider comment encoder des nans et des infinies.


@ERICPOSTPISCHIL - J'ai réfléchi à vos commentaires. Si nous supposons une double utilisation typique où la gamme et la précision d'un flotteur de 4 octets sont insuffisantes, mais la gamme et la précision d'un flotteur de 8 octets sont une surkillasse massive, un tel cas échéant de traduire 124.56054 de texte à IEEE double à base-dix double Retour à IEEE Double et retour à Texte < / Code> Sans le changement de texte, pourrions-nous alors envisager une mise en œuvre "suffisamment portable" pour une utilisation / mise en œuvre spécifiques? Je suppose que votre définition de portable est très stricte et voudrait s'assurer que c'est correct.


@ZZXYZ: Il est probable qu'une certaine représentation portable peut être définie, mais la déclaration de problème a besoin de clarification. Je ne suis pas sûr de savoir ce que l'on entend de texte à l'IEEE Double pour baser-dix double à IEEE Double au texte. C'est plus de conversions que nécessaire pour "J'ai une valeur de point flottante dans mon programme, et j'écris certaines données à un fichier et je l'ai lu dans un autre programme et je prends la fin avec la valeur initiale (ou quelque chose dans un fichier défini distance) dans le nouveau programme. "


@ERICPOSTPISCHIL (J'imaginais un voyage à l'interface utilisateur d'un ordinateur pour peut-être un serveur étrange de retour à l'interface utilisateur d'un autre ordinateur). Je pense que votre première phrase répond à ma question assez bien à mes fins, qui est essentiellement une curiosité inactive :)


3 Réponses :


0
votes

Vous pouvez toujours extérioriser le nombre en fonction de l'IEEE 754. Il s'agit également du format le plus utilisé dans les processeurs actuels, mais si vous souhaitez être portable, vous devez calculer les champs correspondants (signe / exponent / fraction) dans le besoin requis. précision programmatiquement au lieu d'utiliser directement la représentation en mémoire de la plate-forme actuelle.

Une autre alternative utilise des nombres à virgule fixe. Si la plage de nombres et la précision que vous souhaitez représenter lui permettent, cela pourrait être la variante plus facile.


0 commentaires

0
votes

Si la machine que vous utilisez pour sérialiser la valeur double code> utilise une double précision IEEE 754 pour Valeurs double code>, vous pouvez stocker le signe, l'exposant et la mantissie séparément, afin que vous puissiez utiliser ces informations pour reconstruire la double valeur dans tout autre système que vous souhaitez le charger sur:

typedef union _DI
{
    double d;
    uint64_t bits;
} DI;


DI foo;
uint64_t mask = 0x8000000000000000, sign, exp, mantissa, base;
int i;

foo.d = 3.141;
sign = !!(foo.bits & mask);

mask = 0x7FF0000000000000;
exp = ((foo.bits & mask) >> 52) - 1023;

mask = 0x000FFFFFFFFFFFFF;
mantissa = (foo.bits & mask);


1 commentaires

C a frexp pour fournir le signaland et l'exposant; Il n'y a pas besoin de syndicats ou en supposant un format IEEE-754.



0
votes

La réponse facile est non. Il n'y a pas de moyen portable binaire d'écrire des nombres de points flottants sous forme binaire. Même si vous suivez le document IEEE-752, vous constaterez que vous pouvez stocker les octets conformes à un point flottant dans des commandes différentes (comme Big / Petites formes pour les entiers)

Il existe plusieurs protocoles IETF (protocole IPFIX le plus notable) qui définissent un format de transmission des nombres de points flottants IEEE-752 dans ce qu'on appelle le format de réseau (là). Cela oblige le nombre à écrire dans une base de poids majeure à mineure, mais cela oblige, par exemple, cela force des machines à faible endian (comme Intel's) pour échanger les octets en lecture / écriture sur le fil.

Alors, qu'est-ce que les gens font? Eh bien, si vous souhaitez conserver vos données, vous feriez mieux de définir votre propre format et de le suivre toujours dans vos projets. D'une manière indépendante de l'architecture. Si vous avez la chance d'être le premier, lorsque d'autres doivent accéder à vos données, vous pouvez leur indiquer la manière dont ces données sont stockées et toutes peuvent suivre votre spécification, au lieu d'être vous qui doit vous adapter à la leur.


0 commentaires