2010-07-16 5 views
0

J'ai un problème avec la coulée du flotteur pour doubler quand fread;problème avec le flotteur de coulée -> double en C quand la frette

fread(doublePointer,sizeofFloat,500,f); 

Si je change le double pointeur en pointeur flottant, cela fonctionne très bien. Cependant, j'ai besoin qu'il soit un double pointeur pour laster, et je pensais que quand j'écris du petit type de données (float) à la mémoire du plus grand type de données (double), ça devrait aller. mais il s'avère que ça ne marche pas comme je m'y attendais. quel est le problème avec, et comment puis-je résoudre ce problème. Je sais que je peux le résoudre en le convertissant un par un. mais j'ai une énorme quantité de données. et je ne veux pas 9000000+ ronde de conversion .. ce serait très cher. et y a-t-il un truc que je peux résoudre?

est-il des C++/c astuces

grâce

+4

Vous lisez la représentation binaire des flottants directement dans la mémoire d'un double, ce qui n'est pas la même chose que de lancer un flotteur en double. – nos

Répondre

6

Si vous écrivez des données Float-formaté en double, vous allez seulement pour obtenir les ordures en conséquence. Bien sûr, vous ne déborderez pas votre tampon, mais ce n'est pas le seul problème - il va toujours trouver deux flotteurs où il attend un double. Vous avez besoin de le lire comme un flotteur, puis le convertir - coulée (même implicitement) de cette manière permet au compilateur de savoir que les données ont été un flotteur et doit être converti:

float temp[500]; 
int i; 

fread(temp, sizeof(temp[0]), 500, f); 
for (i = 0; i < 500; i++) 
    doublePointer[i] = temp[i]; 
+0

Je sais que je peux le résoudre de cette façon. mais j'ai une énorme quantité de données. et je fais 500 par fread. Je ne veux pas faire une autre itération de 500 pour chaque 500 fread ... – Grey

+5

La conversion doit être faite à un certain niveau. float et double juste à plat ne stockent pas leurs bits dans le même format. –

+2

@grey, Cette itération de 500 est-elle un problème réel, ou un problème théorique? Je traiterai d'abord de vrais problèmes (lire les valeurs correctement semble plus important et réel dans ce cas) – nos

3

Supposons par exemple un flotteur 4 octets sur votre ordinateur. Si vous lisez 500 flottants alors vous lisez 2000 octets, un flotteur par flotteur et le résultat est correct. Supposons par exemple qu'un double soit 8 octets sur votre ordinateur. Si vous lisez 500 flottants alors vous lisez 2000 octets, mais vous les lisez en 250 doubles, 2 flottants par double, et le résultat est un non-sens.

Si votre fichier contient 500 flottants, vous devez lire 500 flottants. Convertissez chaque valeur flottante en valeur double. Vous pouvez convertir chaque valeur numérique de cette façon. Quand vous abusez d'un pointeur, prétendant que le pointeur pointe vers un type de données qu'il ne pointe pas vraiment, alors vous ne convertissez pas chaque valeur numérique, vous conservez un non-sens comme un non-sens.

Editer: Vous avez ajouté à votre question "et je ne veux pas 9000000+ tour supplémentaire de conversion .. ce serait très cher et y at-il un truc que je peux le résoudre?" La réponse est oui, vous pouvez utiliser un truc de garder vos flotteurs comme flotteurs. Si vous ne voulez pas convertir en double, ne convertissez pas en double, gardez vos flotteurs comme flotteurs.

+0

+1 pour l'astuce de les stocker dans le bon format en premier lieu :) – Peter

1

9000000 les conversions du flotteur au double ne sont rien. fread dans un tableau float, puis le convertir en un tableau double. Reportez-vous scientifiquement à ce code, ne devinez pas où les ralentissements pourraient être.

Si vous êtes gêné lors de la conversion, écrivez une boucle de conversion vectorisée déroulée ou utilisez-en une provenant d'une bibliothèque de vecteurs commerciale. Si c'est encore trop lent, collez vos lectures de façon à lire dans vos données flottantes par lots de quelques pages qui tiennent dans le cache L1, puis convertissez les en double, puis lisez les pages suivantes et convertissez les en double, etc.

Si c'est encore encore trop lent, étudiez le chargement paresseux de vos données afin que seules les parties nécessaires soient chargées, et seulement lorsqu'elles sont utilisées.

Un noyau x86 moderne est capable de faire deux conversions float->double par cycle dans une boucle vectorisée à réglage manuel; à 2 GHz, cela représente 4 milliards de conversions par seconde par cœur. 9 millions de conversions est un petit changement - mon ordinateur portable le fait en moins de 1 milliseconde.


Alternativement, il suffit de convertir l'ensemble de données en double une fois, et de le lire à partir de maintenant. Problème résolu.

0

Je regarderais cela sous un angle différent. Si les données sont stockées en tant que float, alors c'est toute la précision qu'il aura jamais. Il est inutile de convertir double jusqu'à ce que les règles de l'arithmétique à virgule flottante l'exigent.

donc j'allouer un tampon pour 500 (ou autre) float s, et de les lire à partir du fichier de données avec un appel approprié à fread():

float *databuffer; 
//... 
databuffer = malloc(500 * sizeof(float)); 
fread(databuffer, sizeof(Float), 500, f); 

Plus tard, utiliser les données quelles que soient les mathématiques qu'il doit participer. Il sera promu au double si nécessaire. N'oubliez pas de libérer éventuellement le tampon après qu'il n'est plus nécessaire.

Si vos résultats ont vraiment toute la précision d'un double, utilisez un nouveau tampon de double s pour les maintenir. Cependant, si elles doivent être réécrites dans le fichier float, vous devrez éventuellement les placer dans un tampon de float s. Notez que la lecture et l'écriture de fichiers à échanger doivent souvent être considérées comme un problème distinct du stockage et de l'utilisation efficaces des données en mémoire. Il est souvent nécessaire de lire un fichier et de traiter chaque valeur individuellement d'une manière ou d'une autre. Par exemple, un programme portable peut être nécessaire pour gérer les données écrites par un système utilisant un ordre d'octets différent. Moins fréquemment aujourd'hui, vous pourriez constater que même la disposition des bits dans un float diffère entre les systèmes. En général, ce problème est souvent mieux résolu en se reportant à une bibliothèque implémentant un standard tel que XDR (défini par RFC 4506) conçu pour gérer la portabilité binaire.