Float or Char. Types confusion - c

I have a struct like this:
typedef struct tic {
char * close_ts;
float * close;
float * open;
}
open and close are float values (like 11.4, 33.5 etc), will be copied from stream but i don't really need to make any computation on them. I just need to extract them and write somewhere else.
Would be better in this case to use char instead of float?

I will disagree with the answers before me.
If you do not need to perform any computation on those number, and want to remain as you read them, you should use strings.
Why:
Floating point values are imprecise. If you read 1.0f and store it as a float, it might get stored as 0.99999998 (not those exact values mind you). It gets more imprecise as the magnitude of the number increases. If you want to store big numbers, it will only get worse.
There is a good article on wikipedia about why this is the case - http://en.wikipedia.org/wiki/Floating_point
If those values are something like money (they look like that from the naming), even if you need to do computations on them, I would advise against float, and would recommend you use some library that can do fixed point math.

I see no reason why to use char*.
The reasons to use float:
sizeof(float) = 4 bytes is less than sizeof("1.234567f") = 9 bytes.
It is natural to use float, so the program will be more readable.

If you want to store float as float it cannot be:
float *open;
//or
float *close;
but
float open;
//or
float close;
If you do not need to perform any operations on these floats - you may also store them as literal character string in an array but its length will depend on your float literal length etc so array may sometimes occupy more space than regular float so float should be ok here.

First of all, char *close_ts, float *close, and float *open are pointers. You should not assign anything to them but the address of a like variable type. For example:
float num = 5;
float *pNum = #
In this case, pNum holds the address of num (&num). If you dereference pNum (*pNum), you get the value of num (5).
You should decide which variable type you use depending on what it'll be used for. Will you be storing a character in it, such as 'A'? If so, use a char. Will you be storing a number with a fractional part, such as 3.14? If so, use a float.

Related

Seamless conversion between numerical types in c

Ok so for the program I'm working on, I have a section where I have 8 bytes put aside as a sort of accumulator.
Throughout various points in the program I intend to use these as both a double float and a long int. At other points I intend to only use the first 4 bytes as a single int or float, and completely ignore the rest.
Similarly I also have a large array of integers where I will at some points want to read out individual 4 byte blocks, as either an integer or float. Or seamlessly smush 2 together as an 8 byte long or double.
I'm working in an environment where although my operations are incredibly simple, time and memory are incredibly scarce so I can't use up extra assignment operations copying into a separate stack variable.
I'm currently working in c but am near enough into the project I can easily start over in a new language if this isn't the best for it.
How might I go about doing this. If I have a double variable, or an array of integers, how can I arbitrarily read variables as other data types without doing any conversion, any computational overhead, even when the type sizes don't match.
Thankyou
Use unions. Unions are designed for memory to be used as different types at different times.
Ok so for the program I'm working on, I have a section where I have 8 bytes put aside as a sort of accumulator. Throughout various points in the program I intend to use these as both a double float and a long int. At other points I intend to only use the first 4 bytes as a single int or float, and completely ignore the rest.
Definition:
union { double d; long int l; int i; float f; } Accumulator;
Uses:
Accumulator.d = 3.4;
Accumulator.l = -3;
Accumulator.i = 7;
Accumulator.f = 3.4f;
Similarly I also have a large array of integers where I will at some points want to read out individual 4 byte blocks, as either an integer or float. Or seamlessly smush 2 together as an 8 byte long or double.
Definition:
#define N 1024
union { int i[N]; float f[N]; long l[N/2]; double d[N/2]; } LargeArray;
Uses:
LargeArray.i[j] = 7;
LargeArray.f[j] = 3.4f;
LargeArray.l[j] = 7l;
LargeArray.d[j] = 3.4;
Note that storing into different elements of the several arrays in the union has some language-lawyer issues with regard to the C standard, but I would expect it to work in current common C implementations. These could be avoided by making an array of unions instead, but then you would have to do some additional arithmetic. For example, LargeArray.i[j] would become LargeArray[j/2].i[j%2]. The union definition would become:
union { int i[2]; float f[2]; long l; double d; } LargeArray[N/2];
Additionally, it would be good to use some _Static_assert declarations to ensure the size relationships between the types are as expected.

How to force compiler to promote variable to float when doing maths

I got question about math in C, quick example below:
uint32_t desired_val;
uint16_t target_us=1500
uint32_t period_us=20000;
uint32_t tempmod=37500;
desired_val = (((target_us)/period_us) * tempmod);
At the moment (target_us/period_us) results in 0 which gives desired_value also 0. I don't want to make these variables float unless i really have to. I dont need anything after comma as it will be saved into 32bit register.
Is it possible to get correct results from this equation without declaring target_us or period_us as float? I want to make fixed point calculations when it's possible and floating point when it's needed.
Working on cortex-M4 if that helps.
Do the multiplication first.
You should split it into two statements with a temporary variable, to ensure the desired order of operations (parentheses ensure proper grouping, but not order).
uint64_t tempprod = (uint64_t)target_us * tempmod;
desired_val = tempprod / period_us;
I've also used uint64_t for the temporary, in case the product overflows. There's still a problem if the desired value doesn't fit into 32 bits; hopefully the data precludes that.
You'll probably have to do some casting in any case, but there's two different methods. First, stick with integers and do the multiplication first:
desired_val = ((uint64_t)target_us * tempmod) / period_us;
or do the calculations in floating point:
desired_val = (uint32_t)(((double)target_us / period_us) * tempmod);
You can do the computation with double quite easily:
desired_val = (double)target_us * tempmod / period_us;
float would be a mistake, since it has far too little precision to be reliable.
You might want to round that off to the nearest integer rather than letting it be truncated:
#include <math.h>
desired_val = round((double)target_us * tempmod / period_us);
See man round
You could, of course, do the computation using a wider integer type (for example, replacing the double with int64_t or long long). That will make rounding slightly trickier.

Calculating log2, with unions

I found the following code which calculates log2 of float x:
union { float f; unsigned int i; } vx = { x };
float y = vx.i;
y *= 1.0 / (1 << 23);
y = y - 126.94269504f;
return y;
The f parameter of union is initialized to input x and then it uses i? I can not understand how it uses something that is not initialized. And what vx.i value is actually? Thank you.
I can not understand how it uses something that is not initialized.
Actually vx.i is initialized. A union will occupy the same memory location. Therefore vx.i is initialized at the same time that vx.f is initialized.
And what vx.i value is actually?
To get the actual value of vx.i you need to understand how a float is stored in memory. Refer the excellent answer here How are floating point numbers are stored in memory?
From the answer linked,
If vx.f is 1.0 then vx.i will be 3f800000 (in hex)
Unions is something that comes from the time when memory was expensive. They are used to save memory.
When you declare a union, it will be large enough to hold the biggest member. So in this case, the size of vx will be max(sizeof(f), sizeof(i)).
So when you use vx = {x}, the value of x will be put in the memory that has been reserved for vx. When you are using vx.f, then whatever is in that memory will be interpreted as a float, but when you are using vx.i will instead be interpreted as an unsigned integer, but the raw binary data is the same.
union keyword basically means that float f and unsigned int i share the same memory.
initializing the union member f and then reading i is basically implementation defined.
What happens is that you get the binary representation of the float variable. The clever coder then uses that binary representation and scales the value so that you get log2 of the input value.
Your float and int share the same memory location. So the bytes occupied by the float are the same as the bytes of the int. But they mean something completelly different as the binary format of float is different than the int. So of you assign the float value it will change the int but the meaning of it will be completely different.

How to convert int array (holding float value in Hex) back into float value in C

I'm trying to write a automated test program that requires me to generate an int array datastream (which actually holds float data)
To generate that int array, i try to
write a floating number into char byte array, and then
convert the char byte array into an int array, which later
convert back the number from the int array to floating point ( without losing the decimal points).
I was able to do step 1 & 2 without issue, but I can't convert the int array back to floating point using ( float)(*int_ptr).
My code:
int ibuff[10];
int *int_ptr;
float f=0.1;
char c [sizeof(float)];
memcpy(c, &f, sizeof(float)); //now c is 0x3f800000;
ibuff[0]=(c[3]<<24 | c[2]<<16 | c[1]<<8 | c[0]); //ibuff[0] is now also 0x3f800000
int_ptr=&ibuff[0];
printf("%f\n", (float)(*int_ptr)); //this will print out 1065353216.0000, and not 1.0 as I expected
Your direct problem comes from casting the dereferenced integer pointer int_ptr to a float and then attempting to print that value as a float. You are currently attempting:
printf("%f\n", (float)(*int_ptr));
which as you have found will not work. What you want to do is interpret the value at the address held by int_ptr as a float. To accomplish that, you will need:
printf("%f\n", *(float*)(int_ptr));
While you can view the address as anything your like, you must make sure you do not run afoul of the strict-aliasing rules set forth in the C-standard at rules 6.5 (6) and 6.5 (7). There are limited exceptions specified, but as stated: "The intent ... is to specify those circumstances in which an object may or may not be aliased." Technically your cast from int to float is a violation which is masked by the use of a pointer (arrived at through the intervening use of a character array, which muddies the water a bit further).
In your print statement:
(float)(*int_ptr)
You are casting an int to a float, ie (float)(int)(x) will be the value of x as a float instead of an int. What you want is the memory of the location to be interperated as a float, so you need:
*(float *)(int_ptr)

Correct datatype for a variable

I have a question like this:
Which of the following is the correct datatype for the variable like this:
a = 23.5
a) float
b) double
c) long double
d) None
According to me, it should be double. Because, if we
float a = 23.5
Then, actually, we are initializing a float variable by a double constant. Am I right saying that it is option b?
It depends on what type you need for a to be in your program logic, not what type of value it's initialized.
Yes, float a = 23.5;, there is a conversion from the double literal 23.5 to the float variable a, but it's fine. For instance, to initialize a double variable to 42.0, people usually use
double a = 42;
in which 42 is of type int, instead of the longer
double a = 42.0;
So in my opinion, float, double, or long double can all be considered correct here.
You can declare this variable as double, float, or long double.
The difference is in the range of the type.
For example (one possible way):
float- 4 bytes
double - 8 bytes
long double - 12 bytes
You can see more details here: http://www.lix.polytechnique.fr/~liberti/public/computing/prog/c/C/CONCEPT/data_types.html
"It depends on" is the right answer.
There are more options then the three you mention.
If yo can safely assume that your numbers are either an integer, or
an integer +1/2 then storing 2 * i in an integral type may be the
right choice.
Another option is a rational number. There are
libraries out there for this.

Resources