0

Weird Floating Point operation

In this code,I try to separate the integer part and fractional part from the floating point number Eg: let consider if I divide 1.000000 by 0.000005,I get result as 200000.000000 From the result,I need to separate the integer part and fractional part and store it in variable separately i.e. result = 200000.000000 integer_part = 200000; fractional part = 0.000000; But instead of getting 200000 as integer part,I got 199999.I don't know why it interpret wrongly. But if you divide the 1.000000 by 0.000006,it correctly separate the fractional part and integer part i.e result = 166666.666667 integer_part = 166666 Fractional_part = 0.666667 what is the reason behind it? https://sololearn.com/compiler-playground/cAFLK3sPRq2J/?ref=app

16th Jun 2024, 2:33 PM
Yogeshwaran P
Yogeshwaran P - avatar
17 Answers
+ 2
Could you describe what you expected from your code detailed?
16th Jun 2024, 5:54 PM
JaScript
JaScript - avatar
+ 2
When "weird" things happen involving calculation of floating point types; it might worth a time to read the wiki page about it. The "Accuracy problems" section was rather difficult for me to digest, but I guess it is more closely relevant to your case. https://en.wikipedia.org/wiki/Floating-point_arithmetic This page also covers the "weirdness" of floating point calculation. Unfortunately, I don't see C/C++ in the cheat sheet menu. I presume a cheat sheet was nothing as easy reminiscing the languages' learning curves (a personal opinion). https://floating-point-gui.de/ You may try separating the integer and fractional part using modf() function from math.h. But considering the issue was related to the accuracy problem of the type, I don't see much a reason why it would do you a favour, if any. http://www.cplusplus.com/reference/cmath/modf P.S. Just reminding you of the `double` type format specifier, use %lf in place of %f ;)
18th Jun 2024, 7:08 AM
Ipang
+ 2
Ipang I was also wondering about %f and %lf. I thought it would allow for more precision in the result. In scanf, there is a distinction, but in printf and sprintf, floats are promoted to double and there is no difference. More decimal places actuslly resulted in rounding in some cases. https://stackoverflow.com/questions/25860850/what-is-the-difference-between-f-and-lf-in-c
18th Jun 2024, 7:18 AM
Bob_Li
Bob_Li - avatar
+ 2
Thank you Bob_Li Ipang X—X for your response, I need precise calculation without rounding off the fractional part For that I try to modify the float format specifier from %f to %0.30f Then I wonder and find that format specifier is the main culprit for rounding off the value(for frontend purpose) and make it visible on display. But actually the variable still it hold the precise floating point value and use that value for backend purposes. Later in internet I found that why compiler print 1.000000/0.000005 = 199999.99999999 instead of 200000.000000, because we know hardware only understood number in 0's and 1's. while converting some fractional number like 0.000005 into binary may lead to significant precision loss,that's why it print 199999.999999 instead of 200000.0000000 Finally I have an one question, How many floating point digit can actually the double datatype can hold and process? https://sololearn.com/compiler-playground/chmwWkXYwBNs/?ref=app
18th Jun 2024, 8:40 AM
Yogeshwaran P
Yogeshwaran P - avatar
+ 2
Great question. So the %0.30f format specifier in C's printf function does not indicate the actual precision of the double datatype itself, but rather controls how many digits are *displayed* after the decimal point when printing a double value. So in very simple terms, the accuracy is up to 15-16 digits but the 30 digits (or more) is generalization. Anything beyond 15-16 digits may suffer rounding errors or loss of precision (aka its complete and total garbage past that point due to the precision of floating-point arithmetic in C). It’s why when I run your new compiler-playground link’s code it states: Divide Result - 199999.999999999970896169543266296387 Integer part - 199999 Fractional part - 0.999999999970896169543266296387 Whereas if %0.30f was actual precision it would state: Divide Result - 199999.999999999999999999999999999999 Integer part - 199999 Fractional part - 0.99999999999999999999999999999 What’s actually quite interesting is Sololearn’s compiler bottlenecks it even more at 10 digits.
18th Jun 2024, 9:47 AM
X—X
X—X - avatar
+ 2
Bob_Li Thanks for that extra info, and that's true. But I still prefer to use the designated format specifier because I have experienced weirdness myself; like in this snippet... * Sorry I didn't use code bit link, linking code bit is rather a hassle while accessing SL from mobile web XD * Assume in main() double d1 = 123.456f; // from float literal double d2 = 123.456; printf("3 decimal points\n%%f\t%.3f\n%%lf\t%.3lf\n", d1, d2); printf("\n6 decimal points (default)\n%%f\t%f\n%%lf\t%lf\n", d1, d2); printf("\n9 decimal points\n%%f\t%.9f\n%%lf\t%.9lf\n", d1, d2); printf("\n12 decimal points\n%%f\t%.12f\n%%lf\t%.12lf\n", d1, d2); printf("\n15 decimal points\n%%f\t%.15f\n%%lf\t%.15lf\n", d1, d2); printf("\n18 decimal points\n%%f\t%.18f\n%%lf\t%.18lf\n", d1, d2); Both <d1> and <d2> are declared double, it's just that <d1> gets a float literal value assigned. I still like the outputs given from the use of %lf better Idk why :)
18th Jun 2024, 10:32 AM
Ipang
+ 2
Bob_Li True. I just wanted to give the best answer possible that I could for Yogeshwaran P. But you’re completely correct.
18th Jun 2024, 2:29 PM
X—X
X—X - avatar
+ 1
It's a little bit unclear what you expected as output, but if you want the integer part as output without decimals, then you can use %.0f
16th Jun 2024, 7:30 PM
Jan
Jan - avatar
+ 1
The results will be rounded. You have to convert the result to string and slice that. Here is my little experiment https://sololearn.com/compiler-playground/cDQRQBbx04j4/?ref=app and a second simpler version https://sololearn.com/compiler-playground/cVToTO2qfp13/?ref=app
17th Jun 2024, 2:16 PM
Bob_Li
Bob_Li - avatar
+ 1
Good question. The issue you're encountering is related to the precision of floating-point arithmetic in C. When I run your program I get: Divide Result - 200000.000000 Integer part - 199999 Fractional part - 1.000000 The issue where you're getting 19999 instead of 20000 (what you want) when trying to convert a double to an int (integer_part) is related to how floating-point numbers are represented and rounded in memory. So when you perform operations like division, the result might not be exactly representable in binary floating-point format, leading to very small rounding errors. Modify Line 9 with either of these fixes: #1) You can round before casting int integer_part = (int)round(result); Also remember to #include <math.h> // for the round() function #2) Adjust the tolerance (no additional header/library needed) int integer_part = (int)(result + 0.5); // Round to the nearest integer This will work as expect from anywhere in between +1.0 to +0.00000001, et cetera. Hope that helped ))
18th Jun 2024, 4:55 AM
X—X
X—X - avatar
+ 1
X—X one problem with using round is that it does exactly that. It rounds the value. 1.5 is a good example where you don't want to round when separating the integer from the fractional part. I think Yogeshwaran P was trying to keep the unrounded value. Converting to numeric types (int, float, double) will introduce rounding. Purely truncating or splitting is easier done with strings. But representing floating point values as a string still introduces compromises. Irrational, repeating, and very small fractional values are some edge cases that are problematic.
18th Jun 2024, 6:20 AM
Bob_Li
Bob_Li - avatar
+ 1
Bob_Li Well said and very true. Also Yogeshwaran P the answer to your question is around 15-16 (depending on the system and compiler) decimal digits of percision according to the IEEE 754 standard for double-precision floating-point numbers. ‘double’ uses 64 bits to store the number (1 bit for sign, 11 bits for exponent, and 52 bits for the significand). Hope that helps )))
18th Jun 2024, 9:12 AM
X—X
X—X - avatar
+ 1
But X—X while using %0.30f format specifier,still I getting the floating value upto 30 digits, even though the the floating digit is limited to 15-16.Where do these remaining number came from?
18th Jun 2024, 9:28 AM
Yogeshwaran P
Yogeshwaran P - avatar
+ 1
Ipang yeah, the double from float seems to show garbage values earlier than the second double. maybe the weirdness comes from the implicit float to double conversion during the declaration of d1, rather than in printf formatting itself. I reversed the positions of d1 and d2 in the printf and it seems that this is the case, the weirdness switched to %lf.
18th Jun 2024, 11:01 AM
Bob_Li
Bob_Li - avatar
+ 1
X—X floating point numbers is really a balancing act of memory space, precision, binary to decimal conversion and practical use case. Numbers that is exact in decimal might be only achieved as an approximation in binary and irrational numbers can never have an exact floating point representation. That is why floating point comparison is never a good idea.
18th Jun 2024, 11:43 AM
Bob_Li
Bob_Li - avatar
0
Hii Jan JaScript sorry for non-clarity in my question , please revisit my updated thread,I hope now you will understand
17th Jun 2024, 2:15 AM
Yogeshwaran P
Yogeshwaran P - avatar
0
possibly OT, but I've been playing with zig, so here is my zig code that does something similar. Zig is really an easy language to learn. https://godbolt.org/z/zs6hnYfhz
18th Jun 2024, 4:06 AM
Bob_Li
Bob_Li - avatar