I have a sine equation which return a float value like:
0.0034,.000006,6.1684332059801899768737349875082e-4.
I want to convert the corresponding float value to integer variables and pass it to a register to generate the particular sine wave graph.
Please help me out.
If you're getting values like 0.0034, you can't simply cast that to an int since it will come out as zero. In fact, the majority of floating point values between zero and one will come out as zero.
You need to first scale up the value, then cast it to an integer.
For example, to turn the output of a sine function into a value between -100 and 100, you could use something like:
int val = (int)(fpVal * 100);
That will turn the range (-1,1) (but mostly 0) into something more usable, (-100,100) (with slightly better distribution across the range).
You may also want to round the value rather than truncate it, to ensure the values generated more accurate represent the inputs.
You could try to save the float value into 3 unsigned integers, one for the values left of the decimal point and two for the values on the right of the decimal point.
For example, we get the float number "359.042042" and save it as variable flt.
int main(void)
{
unsigned int int1, int2, int0;
float flt = 359.042042;
int1 = floor(flt);
int2 = (flt - int1) * pow(10.0, 8.0);
int0 = 8 - log10(int2);
printf("%d.", int1);
while (int0 != 0)
{
printf("0");
int0--;
}
printf("%d", int2);
return 0;
}
int1 are the digits on the left side of the decimal points, int2 are the digits on the right and int0 are the "0" before int2.
This would print "359.042042". Good luck.
Related
How to round result to third digit after the third digit.
float result = cos(number);
Note that I want to save the result up to the third digit, no rounding. And no, I don't want to print it with .3f, I need to save it as new value;
Example:
0.00367 -> 0.003
N.B. No extra zeroes after 3 are wanted.
Also, I need to be able to get the 3rd digit. For example if it is 0.0037212, I want to get the 3 and use it as an int in some calculation.
0.00367 -> 0.003
A float can typically represent about 232 different values exactly. 0.00367 and 0.003 are not in that set.
The closest float to 0.00367 is 0.0036700000055134296417236328125
The closest float to 0.003__ is 0.0030000000260770320892333984375
I want to save the result up to the third digit
This goal needs a compromise. Save the result to a float near a multiple of 0.001.
Scaling by 1000.0, truncating and dividing by 1000.0 will work for most values.
float y1 = truncf(x * 1000.0f) / 1000.0f;
The above gives a slightly wrong answer with some values near x.xxx000... and x.xxx999.... Using higher precision can solve that.
float y2 = (float) (trunc(x * 1000.0) / 1000.0);
I want to get the 3 and use it as an int in some calculation.
Skip the un-scaling part and only keep 1 digit with fmod().
int digit = (int) fmod((trunc(x * 1000.0), 10);
digit = abs(digit);
In the end, I suspect this approach will not completely satisfy OP's unstated "use it as an int in some calculation.". There are many subtitles to FP math, especially when trying to use a binary FP, as are most double, in some sort of decimal way.
Perhaps the following will meet OP's goal, even though it does some rounding.:
int third_digit = (int) lround(cos(number)*1000.0) % 10;
third_digit = abs(third_digit);
You can scale the value up, use trunc to truncate toward zero, then scale down:
float result = trunc(cos(number) * 1000) / 1000;
Note that due to the inexact nature of floating point numbers, the result won't be the exact value.
If you're looking to specifically extract the third decimal digit, you can do that as follows:
int digit = (int)(result * 1000) % 10;
This will scale the number up so that the digit in question is to the left of the decimal point, then extract that digit.
You can subtract from the number it's remainder from division by 0.001:
result -= fmod(result, 0.001);
Demo
Update:
The question is updated with very conflicting requirements. If you have an exact 0.003 number, there will be infinite numbers of zeroes after it, and it is a mathematical property of numbers. OTOH, float representation cannot guarantee that every exact number of 3 decimal digits will be represented exactly. To solve this problem you will need to give up on using the float type and switch to a some sort of fixed point representation.
Overkill, using sprintf()
double /* or float */ val = 0.00385475337;
if (val < 0) exit(EXIT_FAILURE);
if (val >= 1) exit(EXIT_FAILURE);
char tmp[55];
sprintf(tmp, "%.50f", val);
int third_digit = tmp[4] - '0';
I stumbled on one issue while I was implementing in C the given algorithm:
int getNumberOfAllFactors(int number) {
int counter = 0;
double sqrt_num = sqrt(number);
for (int i = 1; i <= sqrt_num; i++) {
if ( number % i == 0) {
counter = counter + 2;
}
}
if (number == sqrt_num * sqrt_num)
counter--;
return counter;
}
– the reason for second condition – is to make a correction for perfect squares (i.e. 36 = 6 * 6), however it does not avoid situations (false positives) like this one:
sqrt(91) = 18.027756377319946
18.027756377319946 * 18.027756377319946 = 91.0
So my questions are: how to avoid it and what is the best way in C language to figure out whether a double number has any digits after decimal point? Should I cast square root values from double to integers?
In your case, you could test it like this:
if (sqrt_num == (int)sqrt_num)
You should probably use the modf() family of functions:
#include <math.h>
double modf(double value, double *iptr);
The modf functions break the argument value into integral and fractional parts, each of
which has the same type and sign as the argument. They store the integral part (in
floating-point format) in the object pointed to by iptr.
This is more reliable than trying to use direct conversions to int because an int is typically a 32-bit number and a double can usually store far larger integer values (up to 53 bits worth) so you can run into errors unnecessarily. If you decide you must use a conversion to int and are working with double values, at least use long long for the conversion rather than int.
(The other members of the family are modff() which handles float and modfl() which handles long double.)
I am working on a small electronics project at home using a PIC microcontroller 18F which I am programming with HiTech C18 that is going to be used for digital control of a bench power supply.
I have run into a problem which is that I have a floating point number in a variable lets say for example 12.34 and need to split it out into 4 variables holding each individual number so i get Char1 = 1, Char2=2 etc etc for display on a 4-way seven segment LED display. The number will always be rounded to 2 decimal places so there shouldnt be a need to track the location of the decimal point.
I am trying to avoid any rounding where possible above 2 decimal places as the displays are giving measurements of voltage/current and this would affect the accuracy of the readouts.
Any advice on how to get this split would be greatly appreciated.
Thanks
Use sprintf to put the value into a character array. And then pick out the digits from there.
You could convert the floating point value directly to text. Or you could multiply by 100, truncate or round to int, and then convert that to text.
Convert to int and then to a string.
float x;
int i = x*100;
// or i = x*100.0f + 0.5f is round to nearest desired.
if ((i < 0) || (i > 9999)) Handle_RangeProblem();
char buf[5];
sprintf(buf, "%04d", i);
In embedded applications, many compilers use the fixed format string to determine which parts of the large printf() code will be needed. If code is all ready using "%f" else where, then a direct sprintf("%f") here is not an issue. Otherwise using %04d" could result in significant space savings.
Floating point numbers are stored in binary format comprised of a sign bit, mantissa, and exponent. A floating point number may not exactly match a given decimal representation (because of the different base-10 for decimal from the base-2 storage of floating point). Conversion of a floating point number to a decimal representation is a problem often assigned in beginning programming courses.
Since are only interested in two decimal places, and a limited range of values, you could use a fixed point representation of your value. This would reduce the problem from conversion of a floating point to decimal into conversion of integer to decimal.
long
longround( float f )
{
long x;
x = (long)((f*100)+.5); //round least significant digit
return(x);
}
char*
long2char( char ca[], long x )
{
int pos=0;
char sign = '+';
ca[pos] = '0';
long v = x;
if( v<0 ) {
sign = '-';
v = -v;
}
for( pos=0; v>0; ++pos )
{
ca[pos] = (v%10)+'0';
v = v/10;
}
ca[pos++] = sign;
ca[pos] = '\0'; //null-terminate char array
//reverse string - left as exercise for OP
return(ca);
}
If you have a problem where the largest value could exceed the range of values supported by long integer on your system, then you would need to modify the above solution.
Given the stated stability of your decimal point: simply sprintf() float into a buffer with appropriate format specifier, then you have your 4 values in a string easily extracted into what ever type you need them to be in...
Example
float num = 12.1234456;
char buf[6];
int main(void)
{
char a[2], b[2], c[2], d[2];
int x, y, z, w;
sprintf(buf, "%0.2f", num);//capture numeric into string
//split string into individual values (null terminate)
a[0] = buf[0]; a[1]=0;
b[0] = buf[1]; b[1]=0;
//skip decimal point
c[0] = buf[3]; c[1]=0;
d[0] = buf[4]; d[1]=0;
//convert back into numeric discretes if necessary
x = atoi(a);
y = atoi(b);
z = atoi(c);
w = atoi(d);
}
There are certainly more elegant ways, but this will work...
I'm trying to convert the decimal portion of a double 247.32
into an int 32. I only need two decimal places.
I can cast the double as int and subtract from the double to get .32000
I can then multiply by 100 to get 32.000
But then when I try to cast that 32.000 as an int, it turns into 31.
Can I fix this?
Should I use a different datatype than a double to store that number?
Thanks
The problem (which skjaidev's answer doesn't solve) is that 247.32 cannot be represented exactly in binary floating-point. The actual stored value is likely to be:
247.31999999999999317878973670303821563720703125
So you can't just discard the integer part, multiply by 100, and convert to int, because the conversion truncates.
The round() function, declared in <math.h>, rounds a double value to the nearest integer -- though the result is still of type double.
double a = 247.32;
a -= trunc(a); /* a == 0.32 -- approximately */
a *= 100.0; /* a == 32.0 -- approximately */
a = round(a); /* a == 32.0 -- exactly */
printf ("%d\n", (int)a);
Or, putting the computation into a single line:
double a = 247.32;
printf("%d\n", (int)round(100.0 * (a - trunc(a))));
Actually, this is probably a cleaner way to do it:
double a = 247.32;
printf("%d\n", (int)round(100.0 * fmod(a, 1.0)));
Given input value x and output y:
char buf[5];
snprintf(buf, sizeof buf, "%.2f", fmod(x, 1.0));
y = strtol(buf+2, 0, 10);
Or just y = 10*(buf[2]-'0')+buf[3]-'0'; to avoid the strtol cost.
This is about the only way to do what you want without writing a ton of code yourself, since the printf family of functions are the only standard functions capable of performing decimal rounding.
If you have some additional constraints like that x is very close to a multiple of 1/100, you could perhaps cheat and just do something like:
int y = ((x+0.001)*100;
By the way, if your problem involves money, do not use floating point for money! Use integers in units of cents or whatever the natural smallest unit for your currency is.
Since you're only looking for 2 decimal places, this works for me:
double a = 247.32;
int b = (int) (a * 100)%100;
printf ("%d\n", b);
Update: See my comment below.
I need to find maximum and minimum of 8 float values I get. I did as follows. But float comparisons are going awry as warned by any good C book!
How do I compute the max and min in a accurate way.
main()
{
float mx,mx1,mx2,mx3,mx4,mn,mn1,mn2,mn3,mn4,tm1,tm2;
mx1 = mymax(2.1,2.01); //this returns 2.09999 instead of 2.1 because a is passed as 2.09999.
mx2 = mymax(-3.5,7.000001);
mx3 = mymax(7,5);
mx4 = mymax(7.0000011,0); //this returns incorrectly- 7.000001
tm1 = mymax(mx1,mx2);
tm2 = mymax(mx3,mx4);
mx = mymax(tm1,tm2);
mn1 = mymin(2.1,2.01);
mn2 = mymin(-3.5,7.000001);
mn3 = mymin(7,5);
mn4 = mymin(7.0000011,0);
tm1 = mymin(mx1,mx2);
tm2 = mymin(mx3,mx4);
mn = mymin(tm1,tm2);
printf("Max is %f, Min is %f \n",mx,mn);
getch();
}
float mymax(float a,float b)
{
if(a >= b)
{
return a;
}
else
{
return b;
}
}
float mymin(float a,float b)
{
if(a <= b)
{
return a;
}
else
{
return b;
}
}
How can I do exact comparisons of these floats? This is all C code.
thank you.
-AD.
You are doing exact comparison of these floats. The problem (with your example code at least) is that float simply does not have enough digits of precision to represent the values of your literals sufficiently. 7.000001 and 7.0000011 simply are so close together that the mantissa of a 32 bit float cannot represent them differently.
But the example seems artificial. What is the real problem you're trying to solve? What values will you actually be working with? Or is this just an academic exercise?
The best solution depends on the answer to that. If your actual values just require somewhat more more precision than float can provide, use double. If you need exact representation of decimal digits, use a decimal type library. If you want to improve your understanding of how floating point values work, read The Floating-Point Guide.
You can do exact comparison of floats. Either directly as floats, or by casting them to int with the same bit representation.
float a = 1.0f;
float b = 2.0f;
int &ia = *(int *)(&a);
int &ib = *(int *)(&b);
/* you can compare a and b, or ia and ib, the results will be the same,
whatever the values of the floats are.
Floats are ordered the correct way when its bits are considered as int
and thus can be compared (provided that float and int both are 32 bits).
*/
But you will never be able to represent exactly 2.1 as a float.
Your problem is not a problem of comparison, it is a problem of representation of a value.
I'd claim that these comparisons are actually exact, since no value is altered.
The problem is that many float literals can't be represented exactly by IEEE-754 floating point numbers. So for example 2.1.
If you need an exact representation of base 10 pointed numbers you could - for example - write your own fixed point BCD arithmetic.
Concerning finding min and max at the same time:
A way that needs less comparisons is for each index pair (2*i, 2*i+1) first finding the minimum (n/2 comparisons)
Then find the minimum of the minima ((n-1)/2 comparisons) and the maximum of the maxima ((n-1)/2 comparisons).
So we get (3*n-2)/2 comparisons instead of (2*n-2)/2 when finding the minimum and maximum separated.
The < and > comparison always works correct with floats or doubles. Only the == comparison has problems, therefore you are advised to use epsilon.
So your method of calculating min, max has no issue. Note that if you use float, you should use the notation 2.1f instead of 2.1. Just a note.