2017-04-04 3 views
1

J'essaie d'améliorer un SWRTC en modifiant la définition d'un second (long unsigned n_ticks_per_second) en synchronisant l'heure avec un serveur.Conversion à float dans uint32_t calcul

#include <stdint.h> 
#include <stdio.h> 

int main(int argc, char * argv[]){ 

    int32_t total_drift_SEC; 
    int32_t drift_per_sec_TICK; 
    uint32_t at_update_posix_time = 1491265740; 
    uint32_t posix_time = 1491265680; 
    uint32_t last_update_posix_time = 1491251330; 
    long unsigned n_ticks_per_sec = 1000; 

    total_drift_SEC = (posix_time - at_update_posix_time); 
    drift_per_sec_TICK = ((float) total_drift_SEC)/(at_update_posix_time - last_update_posix_time); 

    n_ticks_per_sec += drift_per_sec_TICK; 

    printf("Total drift sec %d\r\n", total_drift_SEC); 
    printf("Drift per sec in ticks %d\r\n", drift_per_sec_TICK); 
    printf("n_ticks_per_second %lu\r\n", n_ticks_per_sec); 

    return 0; 

} 

Ce que je ne comprends pas est que je dois jeter total_drift_SEC à flotteur afin d'avoir un résultat correct à la fin, -à-dire d'avoir n_ticks_per_sec égal à 1000 à la fin.

La sortie de ce code est:

dérive total sec -60

Drift par seconde dans les tiques 0

n_ticks_per_second 1000

considérant que la sortie du code sans la fonte pour flotter est:

dérive totale sec -60

Drift par seconde dans les tiques 298054

n_ticks_per_second 299054

+1

Alternative: 'rift_per_sec_TICK = (1LL * total_drift_SEC)/(at_update_posix_time - last_update_posix_time);' – chux

+0

@chux: Ou ... '(int64_t) total_drift_SEC ...' simplement quelque chose signé avec un rang plus élevé alors 'uint32_t'. – alk

+0

@alk Je préfère '1LL *' ou similaire par rapport à casting comme '1LL *' ne rétrécit pas 'total_drift_SEC', quel que soit le type, mais le casting peut se rétrécir dans une version ultérieure du code quand' total_drift_SEC' est un type comme 'double' . – chux

Répondre

2

Cette ligne

drift_per_sec_TICK = total_drift_SEC/(at_update_posix_time - last_update_posix_time); 

divise un 32 bits signed int par un 32 bits unsigned int.

Le bit 32 bits unsigned int a un rang supérieur à 32 bits signed int.

En faisant des opérations arithmétiques les « conversions arithmétiques usuelles » sont appliquées:

De l'C11 Standard (draft) 6.3.1.8/1:

si l'opérande qui est de type entier non signé est de rang supérieur ou égal au rang du type de l'autre opérande, l'opérande avec le type entier signé est converti en le type de l'opérande avec le type entier non signé .

Alors -60 est converti en un (32 bits) unsigned int: 4294967236

Ici

drift_per_sec_TICK = (float) total_drift_SEC/(at_update_posix_time - last_update_posix_time); 

Ce qui suit applique (du paragraphe de la norme C comme ci-dessus):

si le type réel correspondant de l'un ou l'autre opérande est flottant, l'autre l'opérande est converti, sans changement de domaine de type, en un type dont le type réel correspondant est est float.


Pour ne pas l'étape aveuglément dans ces pièges toujours spécifier -Wconversion lors de la compilation avec GCC.

0

Comme avec la version "entier" total_drift_SEC deviendra unsigned si -60 ->4294967236

4294967236/14410 = 298054 
En utilisant float la division calculera:
-60/14410 = 0 

Se référant à la c-standard à la page 53

6.3.1.8 conversions arithmétiques habituelles

1 De nombreux opérateurs qui attendent opérandes de type arithmétique provoquent des conversions et des résultats de rendement types dans un manière similaire. Le but est de déterminer un type réel commun pour les opérandes et le résultat. Pour les opérandes spécifiés, chaque opérande est converti, sans changement de type , en un type dont le type réel correspondant est le type réel commun. Sauf si explicitement indiqué autrement, le type réel commun est également le type réel correspondant de le résultat, dont le domaine de type est le domaine de type des opérandes si elles sont les mêmes, et complexe sinon. Ce modèle est appelé les conversions arithmétiques habituelles: [...] Sinon, les promotions entières sont effectuées sur les deux opérandes. Ensuite, les règles suivantes sont appliquées aux opérandes promus:

  • Si les deux opérandes ont le même type, aucune autre conversion est nécessaire.Sinon, si les deux opérandes ont des types entiers signés ou si les deux ont des types entiers non signés, l'opérande ayant le type de rang de conversion entier inférieur est converti en le type de l'opérande avec un rang supérieur .
  • Dans le cas contraire, si l'opérande est de type entier non signé est de rang supérieur ou égal au rang du type de l'autre opérande, puis l'opérande de type entier signé est converti en type de l'opérateur avec non signé type entier.
  • Dans le cas contraire, si le type de l'opérateur avec le type entier signé peut représenter toutes les valeurs du type de l'opérateur avec le type non signé entier, l'opérande de type entier non signé est converti au type de opérande avec un type entier signé.
  • Sinon, les deux opérandes sont convertis en le type entier non signé correspondant au type de l'opérande avec le type entier signé.

Ephasis mes

+0

Merci pour la réponse :) – PaulGWF