C get fractional value as int - c

I'm trying to get the value of the fractional part of a number. I need the number as an integer however.
float x = 12.345; // eventually not hard-coded
int whole = (int)x;
int frac = (x - (float)whole); // this gives 0.345 - expected
x may be/have any length of decimal places. I need (in my example) 345 stored in frac
I'm thinking I should store the value as a string/char[] and then manipulate the values...
Q: How can I get the fractional value of a fractional number stored as int?

Q: How can I get the fractional value of a fractional number stored as int?
Use modff() to break a float into whole number and fractional parts. #Michael Burr
The modf functions break ... into integral and fractional parts,
#include <math.h>
float x = 12.345;
float whole;
float frac = modff(x, &whole);
The lrint and llrint functions round their argument to the nearest integer value, rounding according to the current rounding direction.
Scale the fractional part and round.
int i = lrintf(frac * 1000);
Using int whole = (int)x; is undefined behavior when x is much outside the int range.
Other approaches that multiple x by 1000 first may incur rounding inaccuracies or may overflow.

I made a quick routine that has what you are looking for. If you need to change the number of digits past the decimal then change the 3 in the .3f in the first printf to match the digits. otherwise you will either see the result multiplied by a multiple of 10 or stripped.
See: http://www.cplusplus.com/reference/cstdio/printf/ for more formatting options.
I also allocated 10 bytes for the number instead of 6 to lower the chances of error should you decide to use a larger number.
The "return 0" simply means normal exit. This has been tested in GCC 4.3.3. for linux and works with no warning.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
float x = 12.345; // your number
char num[10]; // allocate 10 bytes to store number.
sprintf(num,"%0.3f",x); //Format number to string with 3 digits past decimal max
char* frac=strchr(num,(int)'.'); //Find decimal point
if (frac){ //If decimal found then...
frac++; //advance character pointer so we start at wanted number
printf("%s\n",frac); //as a test, print it as a string
long int result=strtol(frac,NULL,10); //convert string to long integer
printf("%ld\n",result); //and print again
}
return 0;
}

Related

Using floorf to reduce the number of decimals

I would like to use the first five digits of a number for computation.
For example,
A floating point number: 4.23654897E-05
I wish to use 4.2365E-05.I tried the following
#include <math.h>
#include <stdio.h>
float num = 4.23654897E-05;
int main(){
float rounded_down = floorf(num * 10000) / 10000;
printf("%f",rounded_down);
return 0;
}
The output is 0.000000.The desired output is 4.2365E-05.
In short,say 52 bits are allocated for storing the mantissa.Is there a way to reduce the number of bits being allocated?
Any suggestions on how this can be done?
A number x that is positive and within the normal range can be rounded down approximately to five significant digits with:
double l = pow(10, floor(log10(x)) - 4);
double y = l * floor(x / l);
This is useful only for tinkering with floating-point arithmetic as a learning tool. The exact mathematical result is generally not exactly representable, because binary floating-point cannot represent most decimal values exactly. Additionally, rounding errors can occur in the pow, /, and * operations that may cause the result to differ slightly from the true mathematical result of rounding x to five significant digits. Also, poor implementations of log10 or pow can cause the result to differ from the true mathematical result.
I'd go:
printf("%.6f", num);
Or you can try using snprintf() from stdlib.h:
float num = 4.23654897E-05; char output[50];
snprintf(output, 50, "%f", num);
printf("%s", output);
The result is expected. The multiplication by 10000 yield 0.423.. the nearest integer to it is 0. So the result is 0. Rounding can be done using format specifier %f to print the result upto certain decimal places after decimal point.
If you check the return value of floorf you will see it returns If no errors occur, the largest integer value not greater than arg, that is ⌊arg⌋, is returned. where arg is the passed argument.
Without using floatf you can use %e or (%E)format specifier to print it accordingly.
printf("%.4E",num);
which outputs:
4.2365E-05
After David's comment:
Your way of doing things is right but the number you multiplied is wrong. The thing is 4.2365E-05 is 0.00004235.... Now if you multiply it with 10000 then it will 0.42365... Now you said I want the expression to represent in that form. floorf returns float in this case. Store it in a variable and you will be good to go. The rounded value will be in that variable. But you will see that the rounded down value will be 0. That is what you got.
float rounded_down = floorf(num * 10000) / 10000;
This will hold the correct value rounded down to 4 digits after . (not in exponent notation with E or e). Don't confuse the value with the format specifier used to represent it.
What you need to do in order to get the result you want is move the decimal places to the right. To do that multiply with larger number. (1e7 or 1e8 or as you want it to).
I would like to use the first five digits of a number for computation.
In general, floating point numbers are encoded using binary and OP wants to use 5 significant decimal digits. This is problematic as numbers like 4.23654897E-05 and 4.2365E-05 are not exactly representable as a float/double. The best we can do is get close.
The floor*() approach has problems with 1) negative numbers (should have used trunc()) and 2) values near x.99995 that during rounding may change the number of digits. I strongly recommend against it here as such solutions employing it fail many corner cases.
The *10000 * power10, round, /(10000 * power10) approach suffers from 1) power10 calculation (1e5 in this case) 2) rounding errors in the multiple, 3) overflow potential. The needed power10 may not be exact. * errors show up with cases when the product is close to xxxxx.5. Often this intermediate calculation is done using wider double math and so the corner cases are rare. Bad rounding using (some_int_type) which has limited range and is a truncation instead of the better round() or rint().
An approach that gets close to OP's goal: print to 5 significant digits using %e and convert back. Not highly efficient, yet handles all cases well.
int main(void) {
float num = 4.23654897E-05f;
// sign d . dddd e sign expo + \0
#define N (1 + 1 + 1 + 4 + 1 + 1 + 4 + 1)
char buf[N*2]; // Use a generous buffer - I like 2x what I think is needed.
// OP wants 5 significant digits so print 4 digits after the decimal point.
sprintf(buf, "%.4e", num);
float rounded = (float) atof(buf);
printf("%.5e %s\n", rounded, buf);
}
Output
4.23650e-05 4.2365e-05
Why 5 in %.5e: Typical float will print up to 6 significant decimal digits as expected (research FLT_DIG), so 5 digits after the decimal point are printed. The exact value of rounded in this case was about 4.236500171...e-05 as 4.2365e-05 is not exactly representable as a float.

Add zeros in the right hand of a float number

I need to do this (does not round, floor or ceil):
example:
1.58700023 (16bits)
expected 1.58700000
i am doing this operation: (value-32768.0)/32768 to convert to (byte value to real value in float) int his conversion have this error = X.00000023 or others
It's quite possible that you cannot do this with floats; note that not all values are exactly representable as a float: it's limited to 32 (typically) bits after all.
For printing, you should be able to use:
printf("%.3f", 1.58700023);
This will print 1.587 by rounding as the value is converted to string.
I assume you want to implement rounding with primitives.
To round to four decimal places, multiply with 10e4, convert to integer (effectively truncating or removing the decimals), then divide by float value 10e4 which converts the result back to float again. For example:
#include <stdio.h>
int main()
{
double f = 1.58700023;
printf("%10.10f\n", f);
// Round to 4 decimal places
double r = (int)(f*10000.0)/10000.0;
printf("%10.10f\n", r);
return 0;
}
This outputs:
1.5870002300
1.5870000000
There are many edge cases not supported by this routine, though. E.g., you may want to add one half of 1/10e4 to perform rounding to nearest next digit, etc.

create number 0 only using int in the C

#include <stdio.h>
struct real_num
{
int int_num;
int frac_num;
};
void main()
{
struct real_num num1;
printf("input the number : ");
scanf("%d.%d",&num1.int_num,&num1.frac_num):
printf("%d.%d",num1.int_num,num1.frac_num);
}
i input 12.012 but buffer save 12.12 i want a 012 but this buffer save 12
what should i do? i want a save 012 (using only int)
Numbers are a matter of arithmetic. 1, 01, 1.0, 1.000, 0x01, 1e0 all describe the same number: whichever representation you use has the same mathematical properties, and behaves identically in calculation (ignoring the matter of computer storage of numbers as int or float or double... which is again another matter entirely).
The representation of a number is a matter of sequences of characters, or strings. Representations of numbers can be formatted differently, and can be in different bases, but can't be calculated with directly by a computer. To store leading zeroes, you need a string, not an int.
You typically convert from number representation to number at input, and from number to number representation at output. You would achieve your stated desire by not converting from number representation to number at input, but leaving it as a string.
You don't want to store 012, you want to store 0.012.
The value 0.012 in binary is (approximately):
0.00000011000100100110111010010111b
..and the value 12.012 is (approximately):
110.00000011000100100110111010010111b
Note that 0.012 is impossible to store precisely in binary because it would consume an infinite number of bits; in the same way that 1/3 can't be written precisely in decimal (0.333333333.....) because you'd need an infinite number of digits.
Let's look at 12.012. In hex it's this:
0x0000000C.03126E97
This makes it easier to see how the number would be stored in a pair of 32-bit integers. The integer part in one 32-bit integer, and the fractional part in another 32-bit integer.
The first problem is that you're using signed 32-bit integers, which means that one of the bits of the fraction is wasted for a sign bit. Essentially, you're using a "sign + 31 bit integer + wasted bit + 31 bit fraction" fixed point format. It'd be easier and better to use an unsigned integer for the fractional bits.
The second problem is that standard C functions don't support fixed point formats. This means that you either have to write your own "string to fixed point" and "fixed point to string" conversion routines, or you have use C's floating point conversion routines and write your own "floating point to fixed point" and "fixed point to floating point" conversion routines.
Note that the latter is harder (floating point is messy), slower, and less precise (double floating point format only supports 53 bits of precision while you can store 62 bits of precision).
A fraction does not consists of a single integer. A fraction consists of 2 integers: numerator/denominator.
Code needs to keep track of width of the fraction input. Could use "%n" to record offset in scan.
#include <stdio.h>
struct real_number {
int ipart;
int num;
int den_pow10;
};
void main(void) {
struct real_number num1;
printf("input the number : ");
fflush(stdout);
int n1 = 0;
int n2 = 0;
scanf("%d.%n%d%n",&num1.ipart, &n1, &num1.num , &n2):
if (n2 == 0) {
fprintf(stderr, "bad input\n");
return -1;
}
num1.den_pow10 = n2 - n1;
printf("%d.%*0d",num1.ipart,num1.den_pow10, num1.frac_num);
return 0;
}
Input/Output
input the number : 12.00056
Result 12.00056

Count number of digits after `.` in floating point numbers?

This is one interview question.
How do you compute the number of digit after . in floating point number.
e.g. if given 3.554 output=3
for 43.000 output=0.
My code snippet is here
double no =3.44;
int count =0;
while(no!=((int)no))
{
count++;
no=no*10;
}
printf("%d",count);
There are some numbers that can not be indicated by float type. for example, there is no 73.487 in float type, the number indicated by float in c is 73.486999999999995 to approximate it.
Now how to solve it as it is going in some infinite loop.
Note : In the IEEE 754 Specifications, a 32 bit float is divided as 24+7+1 bits. The 7 bits indicate the mantissa.
I doubt this is what you want since the question is asking for something that's not usually meaningful with floating point numbers, but here is the answer:
int digits_after_decimal_point(double x)
{
int i;
for (i=0; x!=rint(x); x+=x, i++);
return i;
}
The problem isn't really solvable as stated, since floating-point is typically represented in binary, not in decimal. As you say, many (in fact most) decimal numbers are not exactly representable in floating-point.
On the other hand, all numbers that are exactly representable in binary floating-point are decimals with a finite number of digits -- but that's not particularly useful if you want a result of 2 for 3.44.
When I run your code snippet, it says that 3.44 has 2 digits after the decimal point -- because 3.44 * 10.0 * 10.0 just happens to yield exactly 344.0. That might not happen for another number like, say, 3.43 (I haven't tried it).
When I try it with 1.0/3.0, it goes into an infinite loop. Adding some printfs shows that no becomes exactly 33333333333333324.0 after 17 iterations -- but that number is too big to be represented as an int (at least on my system), and converting it to int has undefined behavior.
And for large numbers, repeatedly multiplying by 10 will inevitably give you a floating-point overflow. There are ways to avoid that, but they don't solve the other problems.
If you store the value 3.44 in a double object, the actual value stored (at least on my system) is exactly 3.439999999999999946709294817992486059665679931640625, which has 51 decimal digits in its fractional part. Suppose you really want to compute the number of decimal digits after the point in 3.439999999999999946709294817992486059665679931640625. Since 3.44 and 3.439999999999999946709294817992486059665679931640625 are effectively the same number, there's no way for any C function to distinguish between them and know whether it should return 2 or 51 (or 50 if you meant 3.43999999999999994670929481799248605966567993164062, or ...).
You could probably detect that the stored value is "close enough" to 3.44, but that makes it a much more complex problem -- and it loses the ability to determine the number of decimal digits in the fractional part of 3.439999999999999946709294817992486059665679931640625.
The question is meaningful only if the number you're given is stored in some format that can actually represent decimal fractions (such as a string), or if you add some complex requirement for determining which decimal fraction a given binary approximation is meant to represent.
There's probably a reasonable way to do the latter by looking for the unique decimal fraction whose nearest approximation in the given floating-point type is the given binary floating-point number.
The question could be interpreted as such:
Given a floating point number, find the shortest decimal representation that would be re-interpreted as the same floating point value with correct rounding.
Once formulated like this, the answer is Yes we can - see this algorithm:
Printing floating point numbers quickly and accurately. Robert G. Burger and R. Kent Dybvig. ACM SIGPLAN 1996 Conference on Programming Language Design and Implementation, June 1996
http://www.cs.indiana.edu/~dyb/pubs/FP-Printing-PLDI96.pdf
See also references from Compute the double value nearest preferred decimal result for a Smalltalk implementation.
Sounds like you need to either use sprintf to get an actual rounded version, or have the input be a string (and not parsed to a float).
Either way, once you have a string version of the number, counting characters after the decimal should be trivial.
It is my logic to count the number of digits.
number = 245.98
Take input as a string
char str[10] = "245.98";
Convert string to int using to count the number of digits before the decimal point.
int atoi(const char *string)
Use logic n/10 inside the while to count the numbers.
Numbers after decimal logic
Get the length of the string using strlen(n)
inside the while (a[i]! ='.'). then increment i
Later you can add step 3 logic output and step 4 logic output
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char num[100] = "345653.8768";
int count=0;
int i=0;
int len;
int before_decimal = atoi(num);
int after_decimal;
int total_Count;
printf("Converting string to int : %d\n", before_decimal);
//Lets count the numbers of digits before before_decimal
while(before_decimal!=0){
before_decimal = before_decimal/10;
count++;
}
printf("number of digits before decimal are %d\n",count);
//Lets get the number of digits after decimal
// first get the lenght of the string
len = strlen(num);
printf("Total number of digits including '.' are =%d\n",len);
//Now count the number after '.' decimal points
// Hope you know how to compare the strings
while(num[i]!='.'){
i++;
}
// total lenght of number - numberof digits after decimal -1(becuase every string ends with '\0')
after_decimal= len-i-1;
printf("Number of digits after decimal points are %d\n",after_decimal);
//Lets add both count Now
// ie. Number of digits before decmal and after decimal
total_Count = count+ after_decimal;
printf("Total number of digits are :%d\n",total_Count);
return 0;
}
Output:
Converting string to int : 345653
number of digits before decimal are 6
Total number of digits including '.' are =11
Number of digits after decimal points are 4
Total number of digits are :10
There are no general exact solutions. But you can convert the value to string and don't count the part exceeding the type's precision and exclude the trailing 0s or 9s. This will work for more cases but it still won't return the correct answer for all.
For example double's accuracy is about 15 digits if the input is a decimal string from the user (17 digits for binary-decimal-binary round trip), so for 73.486999999999995 there are 15 - 2 = 13 digits after the radix point (minus the 2 digits in the int part). After that there are still many 9s in the fractional part, subtract them from the count too. Here there are ten 9s which means there are 13 - 10 = 3 decimal digits. If you use 17 digits then the last digit which may be just garbage, exclude it before counting the 9s or 0s.
Alternatively just start from the 15 or 16th digit and iterate until you see the first non-0 and non-9 digit. Count the remaining digits and you'll get 3 in this case. Of course while iterating you must also make sure that the trailing is all 0s or all 9s
Request: e.g. if given 3.554 output = 3, for 43.000 output = 0
Problem: that's already a decimal like 0.33345. When this gets converted to a double, it might be something like 0.333459999...125. The goal is merely to determine that 0.33345 is a shorter decimal that will produce the same double. The solution is to convert it to a string with the right number of digits that results in the same original value.
int digits(double v){
int d=0; while(d < 50){
string t=DoubleToString(v,d); double vt = StrToDouble(t);
if(MathAbs(v-vt) < 1e-15) break;
++d;
}
return d;
}
double v=0.33345; PrintFormat("v=%g, d=%i", v,digits(v));// v=0.33345, d=5
v=0.01; PrintFormat("v=%g, d=%i", v,digits(v));// v=0.01, d=2
v=0.00001; PrintFormat("v=%g, d=%i", v,digits(v));// v=1e-05, d=5
v=5*0.00001; PrintFormat("v=%g, d=%i", v,digits(v));// v=5e-05, d=5
v=5*.1*.1*.1; PrintFormat("v=%g, d=%i", v,digits(v));// v=0.005, d=3
v=0.05; PrintFormat("v=%g, d=%i", v,digits(v));// v=0.05, d=2
v=0.25; PrintFormat("v=%g, d=%i", v,digits(v));// v=0.25, d=2
v=1/3.; PrintFormat("v=%g, d=%i", v,digits(v));// v=0.333333, d=15
What you can do is multiply the number by various powers of 10, round that to the nearest integer, and then divide by the same number of powers of 10. When the final result compares different from the original number, you've gone one digit too far.
I haven't read it in a long time, so I don't know how it relates to this idea, but How to Print Floating-Point Numbers Accurately from PLDI 1990 and 2003 Retrospective are probably very relevant to the basic problem.

atof accuracy with double is causing grief

I have an ascii "15605632.68128593" and I wish to convert
it to a double without losing accuracy
double d;
d=(double)atof("15605632.68128593");
printf("%f",d);
printed result is 15605632.681286
Any ideas?
It's likely you're not getting all the trailing decimal places. Try printf("%.8f", d).
You might also try sscanf("15605632.68128593", "%lf", &d) in place of the atof call.
It's also not necessary to cast the result of atof to double. It's already a double. But the cast does no harm.
Note that - at least about 6 years ago when I looked at this in detail - many printf and scanf implementations were buggy in the sense that they didn't function as perfect inverses as you'd assume. Visual C/C++ and gcc both had problems in their native implementations. This paper is a useful reference.
Cygwin with gcc 4.3.4:
#include <stdio.h>
int main(void)
{
double x;
sscanf("15605632.68128593", "%lf", &x);
printf("%.8f\n", x);
return 0;
}
And then:
# gcc foo.c
# ./a
15605632.68128593
Goal: Convert "15605632.68128593" to a double without losing accuracy.
atof() accomplished that to best the program could do. But since "15605632.68128593" (a 16-digit number) is not exactly representable as a double in your C, it was approximated to 1.560563268128593080...e+07. Thus accuracy was lost, albeit a small loss.
Typical double can represent about 264 different numbers. The nearby candidates and OP's string are shown below for reference.
15605632.68128 592893... previous double
"15605632.68128 593" code's string
15605632.68128 593080... closest double
15605632.68128 6 output
The grief comes when attempting to print, thinking that what printed was the exact value of x. Instead the nearby double value was printed. Printout is also rounded. Using the %f specifier defaults to 6 places to the right of the '.' giving the reported 15605632.681286, a 14 digit number.
A better way to see all the significant digits for all double is to use the %e format with DBL_DIG or DBL_DECIMAL_DIG. DBL_DIG is the most number of digits to the right of the '.', in decimal exponential notation %e, to show all the digits needed to "round-trip" a double (string to double to string without a string difference). Since %e always shows 1 digit to the left of '.', the print below shows 1 + DBL_DIG significant digits. DBL_DECIMAL_DIG is 17 on my mine and many C environments, but it vary.
If you wish to show all the significant digits, you need to qualify what is significant. The nextafter() function shows the next representable double. So we might want to show at least enough digits to distinguish x and the next x. I recommend DBL_DECIMAL_DIG. Details
The exact value the program used for your "1.560563268128593e+07" is 15605632.68128593079745769500732421875. There are few situations where you need to see all those digits. Even is you request lots of digits, at some point, printf() just gives you zeros.
#include <stdio.h>
#include <float.h>
#include <tgmath.h>
int main(int argc, char *argv[]) {
double x;
x = atof("15605632.68128593");
printf("%.*le\n",DBL_DIG, x); // All digits "round-trip" string-to-double-string w/o loss
printf("%.*le\n",DBL_DIG + 1, x); // All the significant digit "one-way" double-string
printf("%.*le\n",DBL_DIG + 1, nextafter(x, 2*x)); // The next representable double
printf("%.*le\n",DBL_DIG + 3, x); // What happens with a few more
printf("%.*le\n",DBL_DIG + 30, x); // What happens if you are a bit loony
return 0;
}
1.560563268128593e+07
1.5605632681285931e+07
1.5605632681285933e+07
1.560563268128593080e+07
1.560563268128593079745769500732421875000000000e+07
double does not have that much precision. It can only round-trip 15 (DBL_DIG from float.h) decimal places from decimal string to double back to decimal string.
Edit: While, in general, my claim is true, it doesn't seem to be your problem here. While there exist 16-decimal-place numbers which can't be round-tripped, this particular input can.

Resources