A more efficient way to work with my data (ints vs floats)

My brain fades when it comes to the hex. Some people are abidextrous and others are just right ... well, sort of like, I'm VERY base10 I guess.

Anyway ... I am trying to make some firmwares more efficient. We have a function that calculates the speed of a vehicle based on some hex data that it receives via CANBUS. Right now I'm converting it to a float so I can wrap my head around it, but I'm wondering if we don't use less disk space if we keep it in integer format? Can this be done without losing precision? Right now, my floats are accurate to 1 / 16kph. I know this function seems simple, but works hundreds of times per second, it fades a little.

First, here are some sample data:

[06] [3c] ... [06] [3a] ... [06] [3b] ... [06] [46] ... [06] [3b] ...

I left the remaining 6 bytes as they are not related to speed. The byte on the left will be called speed_a, and the byte on the right will be called speed_b. Here is the function to convert:

float calculateSpeed()
    float speed;
    speed = ( ( float )speed_a * 256.0 + speed_b ) / 16.0;
    return speed;


Thus, the above data will translate to:

99.7500 99.6250 99.6875 100.3750 99.6875

and this accurately reflects the vehicle's true speed in km / h. However, for our application, we don't care what the true speed is, because everything is relative. As long as we do not lose the permission, we are happy. I was thinking about just storing everything in INT form, but then when you divide by 16 it just truncates.

I'm not an idiot about most things ... but I'm an idiot with base2.

Lil 'help? Thank.


source to share

8 answers

Just don't divide by 16.0. You can still compare, sort, add or subtract speeds.



Integers are always faster than floats. Instead of using float to represent kph, use integers to represent 1 / 16th of kph.

Then your code will look like this:

int calculateSpeed() {
    return speed_a * 256 + speed_b


Just the moment you need to display the value to the user, I would convert back to float:

int s = calculateSpeed();
printf ("Speed = %f\n", ((float)(s))/16.0);


Depending on how smart your compiler is and how good your processor is (I could be wrong, but it sounds like an embedded system), the line:

    return (speed_a << 8) + speed_b


could be faster.



You can use the 0.01 scale. Then the integer 9969 is 99.69 km / h. This will avoid complications with base 2.

0.01 is six times better than 0.0666. Twice as good would be enough. Then you can use 2 bytes per measurement and display up to 327 km / h.

If division by 100 is required (for example, for output), there are ways to approximate, but fast division by a constant (100 in the case).



You will save space for a given precision if you use fixed-point math with the requirements you describe, because you can only use the bit number you need to keep the fractional part.

However, most compilers store float as a 32-bit value, and most of the fixed-point math libraries I've seen use 32 bits as storage as well. If you cannot represent the ranges of numbers you want (integer and fractional parts) using a 16-bit fixed-point number, there will be no memory difference between float and (32-bit) int.

Bottom Line If you don't want to deal with 16-bit fixed-point numbers, int and float probably use the same amount of memory on your system.



You can go with:

int calculateSpeed () {
    int speed;
    speed = ( (speed_a * 256 ) + speed_b );    
    return speed;


I just just denied the div part since you don't need that: int is at least 32 bits - while you have 2 bytes that are concatenated into 16 bits.




Integer division just gives an integer result. Real (floating point) division gives a floating point result.

In your case, you can store this as meters, or centimeters, or even microns per second. Then, when you do an integer division of the appropriate scale, you won't care about the truncation and you can defer the conversion to Kph until it's time to print / display the results (or export to whatever expects those units, etc.) ...

By the way, another old approach is to do pairs of (integer) division and modulus operations ... storing the results as pairs of factor / remainder pairs until it's time to print / display / export. Entire libraries of math routines have been implemented with such "scaled integer arithmetic" that can offer significant performance and precision advantages over floating point calculations.



Is it possible to lose data? If it is not, there is not much you can do about those decimal places ... Otherwise:

int speed = ((float_a << 8) | float_b) >> 4;

Do two char

a's short

and keep the last 4 bits (this is the same as dividing by 16 and getting the integer part).

You also have a performance gain in that sinse using bitwise operations is slightly faster than using multiplication / division (despite the fact that this factor is almost negligible for real computers).



If you want to convert to decimal numbers for display without using floating point arithmetic, you can do something like this if speed

measured in sixteen kilometers per hour:

printf("%d.%04d", speed / 16, 10000 * (speed % 16) / 16);


In an embedded environment, you can save a lot of disk space if you don't need to link any floating point arithmetic libraries. It sounds like it might be a good idea for you to get rid of the floating point usage in your application. (Not to mention avoiding use printf()

, but that's a different story.)

If your measurement equipment is not more accurate than sixteenth, there is no point in showing more than two decimal places. Modifying the above example to accommodate this format is left as an exercise for the reader.



All Articles