C (Embedded) - Divide uint16 and convert to double

1.5k Views Asked by At

I'm having some problems and getting confused about the proper way of doing some operations with uint16_t and double for C embedded software (Using GCC).

Ex1:

uint16_t PD_input =723;// Input will always be greater than output
uint16_t PD_output =246;
uint16_t FQ_u16 = PD_input/PD_output;

This will result in: FQ_u16=2, no?

Ex2:

uint16_t PD_input =723;
uint16_t PD_output =246;
double FQ_dbl = PD_input/PD_output;  

In this case FQ_dbl =2.9390, but I get 0.... or should I do:

double FQ_dbl = (double)(PD_input/PD_output);  

In this case I don't know if doinng the casting will cause some problems. I get 0 anyway.

If I do the casting on the other side the next example will be correct, or how should I do it? Ex3:

double FQ_dbl = PD_input/PD_output; 
uint16_t var= (uint16_t)FQ_dbl; //Is this correct?

What is the proper way of dividing two uint16_t? What is the proper way of casting/convert a double to an uint16_t?

Ex4:

uint16_t var=7342;
double target = var/1000; 

target=7.342?-->I get 0

EDIT: I try this example using UNITY (It uses GCC)

uint16_t Operations(void)
{
    uint16_t PD_input=723;
    uint16_t PD_output=246;
    uint16_t FQ_u16_raw=PD_input/PD_output;
    uint16_t FQ_u16 = (PD_input + (PD_output >> 1)) / PD_output;
    printf("FQ_u16: %d, FQ_u16_raw: %d",FQ_u16,FQ_u16_raw);

    double FQ_dbl=(PD_input/PD_output);
    printf("\nFQ_dbl: %d, FQ_dbl:%f",FQ_dbl,FQ_dbl);

    FQ_dbl=(double)(PD_input/PD_output);
    printf("\nFQ_dbl: %d, FQ_dbl:%f",FQ_dbl,FQ_dbl);

    FQ_dbl=((double)PD_input)/PD_output;
    printf("\nFQ_dbl: %d, FQ_dbl:%f",FQ_dbl,FQ_dbl);
    printf("\n********************");
    uint16_t target=7341;
    double target_dbl=target/1000;
    printf("\ntarget_dbl: %d,target_dbl:%f",target_dbl,target_dbl);
    return FQ_u16;
}

I get this as output:

  • "FQ_u16: 3, FQ_u16_raw: 2"
  • "FQ_dbl: 0, FQ_dbl:0.000000"
  • "FQ_dbl: 0, FQ_dbl:0.000000"
  • "FQ_dbl: 942797699, FQ_dbl:0.000000"
  • "********************"
  • "target_dbl: 0,target_dbl:0.000000"
1

There are 1 best solutions below

2
Clifford On

For a divide operation to be promoted to double at least one of teh operatnds must be double. To that end you need to cast one or both operands, not the expression after the divide operation. So in:

double FQ_dbl = (double)(PD_input/PD_output);  

PD_input/PD_output is an integer divide which you then explicitly cast to double (though it would implicitly converted in any case).

What you need in this case is:

double FQ_dbl = (double)PD_input / PD_output ;  

Casting PD_input to double implicitly promotes PD_output to double and provided a floating point divide.

You could equally be explicit throughout:

double FQ_dbl = (double)PD_input / (double)PD_output ;  

but it is equivalent.

For expressions involving literal constants such as:

double target_dbl = target / 1000 ;

it is sufficient to use a double literal as follows:

double target_dbl = target / 1000.0 ;

but again:

double target_dbl = (double)target / 1000.0 ;

is the explicit equivalent.

As an aside, you are consistently using the wrong formatter (%d) for outputting a double. You need %f. Include -Wformat (GCC) in your compile options to catch such errors (I think -Wformat is implicit in Wall that you should use in any case together with -Werror - do not ignore the warnings, they are often indicative of semantic errors as opposed to syntactic errors).