Floating point conversion
-
I am in the process of trying to code the transmission of floating point data over an ethernet cable. I decided to send two bytes, the first with the "whole" part and the second with the "fractional" part (but as an unsigned char). The first byte works fine, but the second (trivial) part is giving me a strange (to me) problem which is driving me nuts - I can't see WHAT I'm getting wrong. Here is the test code:- float flTest = 0.04; float flResult; flResult = flTest * 100; unsigned char ucResult; ucResult = (unsigned char)flResult; flResult ends up as 4.00000 which is correct, but ucResult gives 3 !! If I change flTest to 0.05, ucResult is 4 !! There is clearly a decrementation involved here, but I can't understand why ! I'm sure that when some kind soul explains it, I shall be kicking myself - HARD !!
Doug
-
I am in the process of trying to code the transmission of floating point data over an ethernet cable. I decided to send two bytes, the first with the "whole" part and the second with the "fractional" part (but as an unsigned char). The first byte works fine, but the second (trivial) part is giving me a strange (to me) problem which is driving me nuts - I can't see WHAT I'm getting wrong. Here is the test code:- float flTest = 0.04; float flResult; flResult = flTest * 100; unsigned char ucResult; ucResult = (unsigned char)flResult; flResult ends up as 4.00000 which is correct, but ucResult gives 3 !! If I change flTest to 0.05, ucResult is 4 !! There is clearly a decrementation involved here, but I can't understand why ! I'm sure that when some kind soul explains it, I shall be kicking myself - HARD !!
Doug
Hate float, try decimal. every time I have used float, the results are unpredictable for what seems like straight forward math, decimal behaves itself.
-
I am in the process of trying to code the transmission of floating point data over an ethernet cable. I decided to send two bytes, the first with the "whole" part and the second with the "fractional" part (but as an unsigned char). The first byte works fine, but the second (trivial) part is giving me a strange (to me) problem which is driving me nuts - I can't see WHAT I'm getting wrong. Here is the test code:- float flTest = 0.04; float flResult; flResult = flTest * 100; unsigned char ucResult; ucResult = (unsigned char)flResult; flResult ends up as 4.00000 which is correct, but ucResult gives 3 !! If I change flTest to 0.05, ucResult is 4 !! There is clearly a decrementation involved here, but I can't understand why ! I'm sure that when some kind soul explains it, I shall be kicking myself - HARD !!
Doug
There is no decrementation, you just need to understand What Every Computer Scientist Should Know About Floating-Point Arithmetic[^]. What you should do to transfer the data (via serial or internet) is to transfer the exact bytes of the data, rather than trying to convert them to something else. So take the address of the number, cast that to an
unsigned char*
and send the four bytes thus pointed at. This will ensure that your receiver will get the exact data that you send. -
Hate float, try decimal. every time I have used float, the results are unpredictable for what seems like straight forward math, decimal behaves itself.
-
I am in the process of trying to code the transmission of floating point data over an ethernet cable. I decided to send two bytes, the first with the "whole" part and the second with the "fractional" part (but as an unsigned char). The first byte works fine, but the second (trivial) part is giving me a strange (to me) problem which is driving me nuts - I can't see WHAT I'm getting wrong. Here is the test code:- float flTest = 0.04; float flResult; flResult = flTest * 100; unsigned char ucResult; ucResult = (unsigned char)flResult; flResult ends up as 4.00000 which is correct, but ucResult gives 3 !! If I change flTest to 0.05, ucResult is 4 !! There is clearly a decrementation involved here, but I can't understand why ! I'm sure that when some kind soul explains it, I shall be kicking myself - HARD !!
Doug
Still learning how to code wrote:
flResult ends up as 4.00000 which is correct
That is not correct. The problem occurs when assigning 0.04 because the binary representation of floating point values can be slightly inexact. In your case
flTest
will be set to the value 0.0399999991. The following multiplication by 100 will not add another error so thatflResult
becomes 3.99999991. Because there is no rounding when casting floating point values to integers, the result is 3. To avoid this, you can add 0.5 before casting:ucResult = (unsigned char)(flResult + 0.5f);
Note that the above is for positive numbers only. With negative numbers, 0.5 must be subtracted.
-
I am in the process of trying to code the transmission of floating point data over an ethernet cable. I decided to send two bytes, the first with the "whole" part and the second with the "fractional" part (but as an unsigned char). The first byte works fine, but the second (trivial) part is giving me a strange (to me) problem which is driving me nuts - I can't see WHAT I'm getting wrong. Here is the test code:- float flTest = 0.04; float flResult; flResult = flTest * 100; unsigned char ucResult; ucResult = (unsigned char)flResult; flResult ends up as 4.00000 which is correct, but ucResult gives 3 !! If I change flTest to 0.05, ucResult is 4 !! There is clearly a decrementation involved here, but I can't understand why ! I'm sure that when some kind soul explains it, I shall be kicking myself - HARD !!
Doug
-
If you need to transmit a float value on the net then do transmit it, that is send its binary representation (e.g 4 bytes for a float, 8 for a double).
That's assuming that you have similar processors at both ends of the connection. While big-endian systems are rare these days, they're not non existent. Furthermore, be careful when going between 32-bit and 64-bit systems. On my x86 linux boxes, a long is 4 bytes, whereas on a x86_64 they're 8 bytes, x86 long-double is 12 bytes and x86_64 its 16.
-
That's assuming that you have similar processors at both ends of the connection. While big-endian systems are rare these days, they're not non existent. Furthermore, be careful when going between 32-bit and 64-bit systems. On my x86 linux boxes, a long is 4 bytes, whereas on a x86_64 they're 8 bytes, x86 long-double is 12 bytes and x86_64 its 16.
-
Float (and double) do exactly what they are supposed to do. The problem is that too many users do not understand how to use it.
Granted. In this case he is not getting the results he is seeking float may be the problem...
-
Granted. In this case he is not getting the results he is seeking float may be the problem...
-
Still learning how to code wrote:
flResult ends up as 4.00000 which is correct
That is not correct. The problem occurs when assigning 0.04 because the binary representation of floating point values can be slightly inexact. In your case
flTest
will be set to the value 0.0399999991. The following multiplication by 100 will not add another error so thatflResult
becomes 3.99999991. Because there is no rounding when casting floating point values to integers, the result is 3. To avoid this, you can add 0.5 before casting:ucResult = (unsigned char)(flResult + 0.5f);
Note that the above is for positive numbers only. With negative numbers, 0.5 must be subtracted.
First of all, apologies for not replying earlier ! WOW, I didn't think that a few lines of code could provoke so much discussion !!! The technique that I am trying to employ is between a PC and an Arduino (via Com port - actually USB). I used it a few years ago to transfer floating point numbers, but in the OPPOSITE direction and it worked perfectly. Anyway, thank you all for your comments - I am amazed that the "error" is actually in the assignment as pointed out by Jochen. In this particular application, the floating point numbers will be quite small, so I think that I'll have to go for the 4 byte transfer method to maintain accuracy - but I'll be doing a lot of testing !! Thank you all once again !
Doug
-
I am in the process of trying to code the transmission of floating point data over an ethernet cable. I decided to send two bytes, the first with the "whole" part and the second with the "fractional" part (but as an unsigned char). The first byte works fine, but the second (trivial) part is giving me a strange (to me) problem which is driving me nuts - I can't see WHAT I'm getting wrong. Here is the test code:- float flTest = 0.04; float flResult; flResult = flTest * 100; unsigned char ucResult; ucResult = (unsigned char)flResult; flResult ends up as 4.00000 which is correct, but ucResult gives 3 !! If I change flTest to 0.05, ucResult is 4 !! There is clearly a decrementation involved here, but I can't understand why ! I'm sure that when some kind soul explains it, I shall be kicking myself - HARD !!
Doug
I am not seeing this issue. I get 4 for unResult. Do you have your floating point options set correctly in the compiler? In visual studio, select properties on your C project. Expand the projects setting out for "c/C++->Code Generation" and set the option for "Floating Point Model" to Precise(/fp:precise).