简体   繁体   中英

Conversion to float in uint32_t calculation

I am trying to improve a SWRTC by modifying the definition of a second ( long unsigned n_ticks_per_second ) by synchronizing time with a server.

#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;

}

What I don't understand is that I need to cast total_drift_SEC to float in order to have a correct result in the end, ie to have n_ticks_per_sec equal to 1000 in the end .

The output of this code is:

Total drift sec -60

Drift per sec in ticks 0

n_ticks_per_second 1000

Whereas the output of the code without the cast to float is:

Total drift sec -60

Drift per sec in ticks 298054

n_ticks_per_second 299054

This line

drift_per_sec_TICK = total_drift_SEC / (at_update_posix_time - last_update_posix_time);

divides a 32 bit signed int by a 32 bit unsigned int .

32 bit unsigned int has a higher rank then 32 bit signed int .

When doing arithmetic operations the " Usual Arithmetic Conversions " are applied:

From the C11 Standard (draft) 6.3.1.8/1 :

if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type.

So -60 gets converted to a (32 bit) unsigned int : 4294967236

Here

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

The following applies (from the paragraph of the C Standard as above):

if the corresponding real type of either operand is float, the other operand is converted, without change of type domain, to a type whose corresponding real type is float .


To not blindly step into those traps always specify -Wconversion when compiling with GCC.

Because with "integer" version total_drift_SEC will become unsigned so -60 --> 4294967236

4294967236 / 14410 = 298054

Using float the division will calculate:

-60/14410 = 0

Referring to the c-standard at page 53

6.3.1.8 Usual arithmetic conversions

1 Many operators that expect operands of arithmetic type cause conversions and yield result types in a similar way. The purpose is to determine a common real type for the operands and result. For the specified operands, each operand is converted, without change of type domain, to a type whose corresponding real type is the common real type. Unless explicitly stated otherwise, the common real type is also the corresponding real type of the result, whose type domain is the type domain of the operands if they are the same, and complex otherwise. This pattern is called the usual arithmetic conversions: [...] Otherwise, the integer promotions are performed on both operands. Then the following rules are applied to the promoted operands:

  • If both operands have the same type, then no further conversion is needed. Otherwise, if both operands have signed integer types or both have unsigned integer types, the operand with the type of lesser integer conversion rank is converted to the type of the operand with greater rank.
  • Otherwise, if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type.
  • Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, then the operand with unsigned integer type is converted to the type of the operand with signed integer type.
  • Otherwise, both operands are converted to the unsigned integer type corresponding to the type of the operand with signed integer type.

Ephasis mine

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM