Reputation: 1501
This is a basic question but I am confused.
I have a register which has the format 1.4.12. Meaning it takes a float and takes the range -15.9999 - 15.9999, is that correct, or how many nines? I am confused by the range.
I need to convert a c++ float to fixed point and put it in the register? Are there any std:: libraries to do that in C? If not is there any standard code that someone could point me to?
Also, how to convert fixed to float would be good?
Upvotes: 0
Views: 3674
Reputation: 2747
If you need to use fixed-point, then you must implement addition and multiplication operations. In that case, you need to worry about how many bits you have allocated for the fractional part and how many bits allocated for the integer part. And then you can do "shift" operation as your preference.
In the following code-snippet, I've implemented fixed-point by allocating 22 bits for the fractional part and 9 bits for the integer part. (additional bit will be for the sign)
In multiplication, I've first expanded the bit-length of each value to avoid overflow. After multiplication, left shift will happen to keep the same fractional part for the output of multiplication.
In addition, I've added saturation for the output, in order to avoid any overflow (if overflow happens, then output will keep the maximum absolute value that it can keep irrespective of the sign)
#include <stdio.h>
#include <math.h>
#include <stdint.h>
#define fractional_bits 22
#define fixed_type_bits 32
typedef int32_t fixed_type;
typedef int64_t expand_type;
fixed_type float_to_fixed(float inp)
{
return (fixed_type)(inp * (1 << fractional_bits));
}
float fixed_to_float(fixed_type inp)
{
return ((float)inp) / (1 << fractional_bits);
}
fixed_type fixed_mult(fixed_type inp_1, fixed_type inp_2)
{
return (fixed_type)(((expand_type)inp_1 * (expand_type)inp_2) >> fractional_bits);
}
fixed_type fixed_add(fixed_type inp_1, fixed_type inp_2)
{
fixed_type inp_1_sign = inp_1 >> (fixed_type_bits - 1);
fixed_type inp_2_sign = inp_2 >> (fixed_type_bits - 1);
fixed_type add = inp_1 + inp_2;
fixed_type add_sign = add >> (fixed_type_bits - 1);
if (inp_1_sign != inp_2_sign)
{
return add;
}
else if (add_sign == inp_1_sign)
{
return add;
}
else if (add_sign == -1)
{
return ((1 << (fixed_type_bits - 2)) - 1 + (1 << (fixed_type_bits - 2)));
}
else if (add_sign == 1)
{
return (1 << (fixed_type_bits - 1));
}
}
Upvotes: 1
Reputation: 213200
It's fairly simple to do this yourself:
typedef int32_t fixed;
fixed float_to_fixed(float x)
{
return (fixed)(x * 65536.0f / 16.0f);
}
Note that this has no range checking so if x
can possibly be outside the valid range for your fixed point type then you might want to add some checks and either saturate or throw an error as appropriate.
Similarly for conversion in the other direction:
float fixed_to_float(fixed x)
{
return (float)x * 16.0f / 65536.0f;
}
(This one does not need any range checking of course.)
Upvotes: 3