-->

How to get the integer and fractional part of a de

2020-03-26 14:22发布

问题:

How do I convert 30.8365146 into two integers, 30 and 8365146, for example, in Arduino or C?

This problem faces me when I try to send GPS data via XBee series 1 which don't allow to transmit fraction numbers, so I decided to split the data into two parts. How can I do this?

I have tried something like this:

double num=30.233;
int a,b;

a = floor(num); 
b = (num-a) * pow(10,3);

The output is 30 and 232! The output is not 30 and 233. Why and how can I fix it?

回答1:

double value = 30.8365146;
int left_part, right_part;
char buffer[50];
sprintf(buffer, "%lf", value);
sscanf(buffer, "%d.%d", &left_part, &right_part);

and you will get left/right parts separately stored in integers.

P.S. the other solution is to just multiply your number by some power of 10 and send as an integer.



回答2:

You can output the integer to a char array using sprintf, then replace the '.' with a space and read back two integers using sscanf.



回答3:

I did it for float, using double as temporary:

int fract(float raw) {

    static int digits = std::numeric_limits<double>::digits10 - std::numeric_limits<float>::digits10 - 1;
    float intpart;
    double fract = static_cast<double>(modf(raw, &intpart));
    fract = fract*pow(10, digits - 1);
    return floor(fract);
}

I imagine that you could use quadruple-precision floating-point format to achieve the same for double: libquadmath.



回答4:

The 30 can just be extracted by rounding down (floor(x) in math.h).

The numbers behind the decimal point are a bit more tricky, since the number is most likely stored as a binary number internally, this might not translate nicely into the number you're looking for, especially if floating point-math is involved. You're best bet would probably be to convert the number to a string, and then extract the data from that string.



回答5:

As in the comments, you need to keep track of the decimal places. You can't do a direct conversion to integer. A bit of code that would do something like this:

#include <stdio.h>
#include <math.h>

#define PLACES 3

void extract(double x)
{
        char buf[PLACES+10];
        int a, b;

        sprintf(buf, "%.*f", PLACES, x);
        sscanf(buf, "%d.%d", &a, &b);

        int n = (int) pow(10, PLACES);

        printf("Number           : %.*f\n", PLACES, x);
        printf("  Integer        : %d\n", a);
        printf("  Fractional part: %d over %d\n", b, n);
}

int main()
{
        extract(1.1128);
        extract(20.0);
        extract(300.000512);
}

Produces:

Number           : 1.113
  Integer        : 1
  Fractional part: 113 over 1000
Number           : 20.000
  Integer        : 20
  Fractional part: 0 over 1000
Number           : 300.001
  Integer        : 300
  Fractional part: 1 over 1000


回答6:

What about using floor() to get the integer value and num % 1 (modulo arithmetic) to get the decimal component?

Then you could multiply the decimal component by a multiple of 10 and round. This would also give you control over how many decimal places you send, if that is limited in your comm. standard.

Would that work?

#include <math.h>

integer_part = floor(num); 
decimal_part = fmod(num,1)*10^whatever;