floatToStr function

General discussion on mikroC.
Post Reply
Author
Message
brunai
Posts: 71
Joined: 07 Nov 2006 06:53
Location: brunai,bandar seri

floatToStr function

#1 Post by brunai » 24 Feb 2007 08:13

hello
my project is Astronomical Applications on that imagine what floatToStr
has wrote on lcd

Code: Select all

float G_day ;
char txt[13];
void main()
{
 trisb = 0;
 portb =0;
 lcd_init(&portb);
 lcd_cmd(LCD_CLEAR);
 //G_day = Golian_day(year,month,day);  // get golian day
 G_day = 2610.5; //  match  24/2/2007
 floatToStr(G_day,txt); // print 2610.499
 lcd_out_cp(txt);

}
help me please
"when you keep your face to the sun shadows fall behind"
[img]http://www.expertrating.com/logos/C%20Programming.gif[/img][img]http://www.expertrating.com/logos/ComputerSkills.gif[/img]

picdog
Posts: 390
Joined: 28 Feb 2006 09:32

#2 Post by picdog » 24 Feb 2007 22:54

Hello Brunai,
the result you obtain is due to floating point representation because it is not a perfect representation of real numbers - and this is not related to mikroC itself.

So seems appear that at this level of precision (float 32-bit) for 2610.5 you get 2610.499 that is the real number closest to your, in this representation.

If your question is related about to get from a float number a timestamp representation (like in Golian_day), you should have a specific function that does this conversion, because itself FloatToStr converts only the float in a string.

hope that helps,
have a good evening :-)
picdog
... a proud user of MikroElektronica EasyPic3, EasyPic4, BigPic4, MikroC for PIC, EasydsPIC2, dsPIC-Pro2, LV24-33 and MikroC for dsPIC :)

brunai
Posts: 71
Joined: 07 Nov 2006 06:53
Location: brunai,bandar seri

so so satisfied

#3 Post by brunai » 26 Feb 2007 01:39

hello picdog
thanks alot
i am not agree with you that floatToStr function satisfied
here other code

Code: Select all

floatToStr(2610 ,txt);its print 2609.999 
also

Code: Select all

Const_n = 57.2958; 
PI = π  = 180° =180/Const_n =3.141591;
floatToStr(PI ,txt);// ok 3.141591
floatToStr(Const_n ,txt);// no its printing 57.29579
I note that if( numbers <=10) the function floatToStr satisfied
what can i do i would rather write my own function floatToStr instead of built in
help me please
"when you keep your face to the sun shadows fall behind"
[img]http://www.expertrating.com/logos/C%20Programming.gif[/img][img]http://www.expertrating.com/logos/ComputerSkills.gif[/img]

picdog
Posts: 390
Joined: 28 Feb 2006 09:32

#4 Post by picdog » 26 Feb 2007 03:13

Hello Brunai,
it depends on the number.
Floats are implemented via IEEE-754 format but 32 bits are not many, so you obtain those effects.
It is not true that n<10 is ok; try e.g. 0.26105.
This doesn't depend on how the FloatToStr is implemented, or sprintf; but on the number itself as it is memorized in 32 bits of precision.
It is the number itself that is memorized as 2610.499; it is not the function that "render" the number in this way.
For example try this:
define a float variable = 2610.5
FloatToStr it
you obtain 2610.499
then: define a float variable = 0.5
FloatToStr it
this is good: 0.5
now, FloatToStr(var1-var2, txt)
and you obtain 2609.999

This is evidence that the FloatToStr function from MikroElektronika is ok, it is the number that is "rounded" to the nearest possible in that floating point precision.

Hope that helps you.

Best regards, and good work,

picdog
[/list]
... a proud user of MikroElektronica EasyPic3, EasyPic4, BigPic4, MikroC for PIC, EasydsPIC2, dsPIC-Pro2, LV24-33 and MikroC for dsPIC :)

janni
Posts: 5373
Joined: 18 Feb 2006 13:17
Contact:

#5 Post by janni » 26 Feb 2007 23:50

It is the number itself that is memorized as 2610.499; it is not the function that "render" the number in this way.
Actually, both 0.5 and 2610.5 are accurately represented in IEEE-754 32-bit format (not 0.26105, though).

brunai
Posts: 71
Joined: 07 Nov 2006 06:53
Location: brunai,bandar seri

hi to all

#6 Post by brunai » 27 Feb 2007 02:18

thanks all for helps
i will give you some examples that mikroC's IEEE-754 Floating-Point Conversion Single precision (32 bits) working fine but floatToString not so
first of all here is expression

Code: Select all

(-1)sign bit *   (1+fraction)  * 2 exponent - bias 

Code: Select all

bias = 127 // Single precision (32 bits) mikroc supported
bias = 1023 // Double precision (64 bits) not supported yet

Image
Image
first of all
Converting to IEEE 754 Form
second will do
Convert the following single-precision IEEE 754 number into a floating-point decimal value.
wait me please
"when you keep your face to the sun shadows fall behind"
[img]http://www.expertrating.com/logos/C%20Programming.gif[/img][img]http://www.expertrating.com/logos/ComputerSkills.gif[/img]

brunai
Posts: 71
Joined: 07 Nov 2006 06:53
Location: brunai,bandar seri

go on here

#7 Post by brunai » 27 Feb 2007 06:14

here is source code

Code: Select all

float TNUM ;
char TXT[13];

void main()
{
  Lcd_Init(&PORTB);
  Lcd_Cmd(LCD_CLEAR);
  TNUM = 11.0;
  FloatToStr(TNUM,TXT);
  LCD_Out_CP(TXT);
}
Now after compile the source code
On menu View Assembly

Code: Select all

TNUM = 11.0;
$0383	$3000			MOVLW	0
$0384	$00A3			MOVWF	_TNUM
$0385	$3000			MOVLW	0
$0386	$00A4			MOVWF	_TNUM+1
$0387	$3030			MOVLW	48
$0388	$00A5			MOVWF	_TNUM+2
$0389	$3082			MOVLW	130
$038A	$00A6			MOVWF	_TNUM+3

Code: Select all

Bit 31 Sign Bit  0:+ ! 1:- = 0 = _TNUM+2.f7
Bits 30 - 23 Exponent Field = _TNUM+3 = 130
Bits 22 – 0 fraction  Significand = 1 .01100000000000000000000 
Decimal value of the significand = 1.3750000
Let see Example: Converting to IEEE 754 Form:
1. Put 11.0 in single-precision format
2. The first step is to look at the sign of the number.
Because 11.0 is positive, the sign bit =0.

POW(-1, signbit) = 1
3. Write 11.0 in base-2 scientific notation.
This means that we must factor it into a number in the range [1 <= n < 2] and a power of 2.

Code: Select all

11.0 = POW(-1, 0) *  (1+fraction)   * POW(2,power)  
or:

Code: Select all

11.0 / POW(2,power)  = (1+fraction). 
power = exponent – bias = exponent – 127

So we can divide 11.0 by some power of 2 to get the (1 + fraction).

Code: Select all

11.0 / pow(2,1) = 5.5
11.0 / pow(2,2)  = 2.75
11.0 / pow(2,3)  = 1.375   range  1<= n <2 ok
11.0 / pow(2,4)  = 0.6875
Therefore, 11.0 = 1.375 * 23
4.
Find the exponent.
The power of 2 is 3, and the bias for the single-precision format is 127.
This means that the

Code: Select all

exponent = 3 + 127 = 130ten.

In binary, it's 1000 0010 bin
5. Write the fraction in binary form
We know that the number we calculated in step 2 is in the range [1 <= n < 2]. Therefore, we don't have to store the leading 1.

The fraction = 0.375 . Unfortunately, this is not a "pretty" number, like those shown in the book. The best we can do is to approximate this value. Single-precision format allows 23 bits for the fraction.

Binary fractions look like this:

Code: Select all

0.1 = (1/2) =pow(2,-1)
0.01 = (1/4) = pow(2,-2)
0.001 = (1/8) = pow(2,-3)
To 0.375, we can say:


0.375 = pow(2,-2) + pow(2,-3)
0.375 = 0.25 + 0.125

0.375ten = 0.01100000000000000000000bin

The binary string we need is:

Code: Select all

01100000000000000000000.
floating-point numbers in IEEE 754 format.
6. Now put the binary strings in the correct order -

1 bit for the sign, followed by 8 for the exponent, and 23 for the fraction. The answer is:

Code: Select all

	Sign	Exponent	Fraction
Decimal	0	130	0.375
Binary	0	1000 0010	011 0000   00000000  00000000
			011 0000	00000000	00000000
	_TNUM+2.F7	_TNUM+3	_TNUM+2	_TNUM+1	_TNUM
		130	48	0	0
Now we can say mikroC's IEEE-754 Floating-Point Conversion Single precision (32 bits) working fine
Example: Converting to Float
Convert the following single-precision IEEE 754 number into a floating-point decimal value

Code: Select all

 _TNUM+3    _TNUM+2 _TNUM+1 _TNUM
0    130         48      0       0
0 10000010 011 0000   00000000 00000000
1. First, put the bits in three groups.

Code: Select all

Bit 31 (the leftmost bit) shows the sign of the number.
Bits 23-30 (the next 8 bits) are the exponent.
Bits 0-22 (on the right) give the fraction 
2. Now, look at the sign bit.
If this bit is a 1, the number is negative.
If it is 0, the number is positive.

This bit is 1, so the number is negative.
3. Get the exponent and the correct bias.
The exponent is simply a positive binary number.

Code: Select all

10000010bin = 130ten 
Remember that we will have to subtract a bias from this exponent to find the power of 2. Since this is a single-precision number, the bias is 127.
4. Convert the fraction string into base ten.
This is the trickiest step. The binary string represents a fraction, so conversion is a little different.

Binary fractions look like this:

Code: Select all

0.1 = (1/2) =pow(2,-1) 
0.01 = (1/4) = pow(2,-2)
0.001 = (1/8) = pow(2,-3)
So, for this example, we multiply each digit by the corresponding power of 2:

Code: Select all

0. 011 0000   00000000 00000000bin 
=

Code: Select all

0*pow(2,-1)+ 1*pow(2,-2) + 1*pow(2,-3) + 0*pow(2,-4)  = 1/4 + 1/8
=

Code: Select all

0.375
5. This is all the information we need. We can put these numbers in the expression:

Code: Select all

pow(-1, sign bit ) *   (1+fraction)  * pow(2 ,exponent – bias)
=

Code: Select all

pow(-1,0) *   (1.375) * pow(2 ,130-127)

Code: Select all

= 11
The answer is 11.0 not approximately 10.99999
What we can say why floatToStr don’t obtain 11 instead of 10.99999
Help me please
"when you keep your face to the sun shadows fall behind"
[img]http://www.expertrating.com/logos/C%20Programming.gif[/img][img]http://www.expertrating.com/logos/ComputerSkills.gif[/img]

Skyline
Posts: 267
Joined: 10 Jan 2006 09:35

Re: go on here

#8 Post by Skyline » 27 Feb 2007 09:30

Hi,

You are using decimal arithmetic logic below to support your premise that the conversion of binary fraction string into base 10 is wrong.

You should actually carry out the entire binary fraction conversion below using only binary arithmetic logic, that is, pretending that you are a binary computing unit, then you would understand the imprecision of representing decimal fractions in binary coding. We cannot use decimal arithmetic ( eg 1/4 + 1/8 = 0.375) to explain binary arithmetic ... :)

Your solution is to use integer or longint type data, and handle the decimal point yourself, or roll your own binary coded decimal code and number representation.

brunai wrote:
4. Convert the fraction string into base ten.
This is the trickiest step. The binary string represents a fraction, so conversion is a little different.

Binary fractions look like this:

Code: Select all

0.1 = (1/2) =pow(2,-1) 
0.01 = (1/4) = pow(2,-2)
0.001 = (1/8) = pow(2,-3)
So, for this example, we multiply each digit by the corresponding power of 2:

Code: Select all

0. 011 0000   00000000 00000000bin 
=

Code: Select all

0*pow(2,-1)+ 1*pow(2,-2) + 1*pow(2,-3) + 0*pow(2,-4)  = 1/4 + 1/8
=

Code: Select all

0.375
5. This is all the information we need. We can put these numbers in the expression:

Code: Select all

pow(-1, sign bit ) *   (1+fraction)  * pow(2 ,exponent – bias)
=

Code: Select all

pow(-1,0) *   (1.375) * pow(2 ,130-127)

Code: Select all

= 11
The answer is 11.0 not approximately 10.99999

User avatar
srdjan
mikroElektronika team
Posts: 1552
Joined: 28 Dec 2005 12:47
Location: Serbia

Re: go on here

#9 Post by srdjan » 27 Feb 2007 10:06

Hi,
First of all, not that it meters for this issue, but is important to be noticed, mikroC is using Microchip AN575 32-bit format for floating point numbers representation as stated in mikroC help file.
The issue you are experiencing happens because of the math calculations used in FloatToStr function. That is, there is error in rounding manifested on 6th number after decimal point which can not be avoided.
You can use Sprintf function, which has bigger footprint, but is more accurate, instead.

brunai
Posts: 71
Joined: 07 Nov 2006 06:53
Location: brunai,bandar seri

ok

#10 Post by brunai » 27 Feb 2007 22:37

thank you srdjan
i am sure that mikroC is using Microchip AN575 32-bit format
and i hope that mikroC support Double precision (64 bits)soon
sprintf working fine but its working for 18pic not for 12,16
i will do own one for my project
thanks
"when you keep your face to the sun shadows fall behind"
[img]http://www.expertrating.com/logos/C%20Programming.gif[/img][img]http://www.expertrating.com/logos/ComputerSkills.gif[/img]

pic-o
Posts: 34
Joined: 21 Oct 2008 09:25
Location: London
Contact:

#11 Post by pic-o » 25 Aug 2009 23:44

Hello,

sorry to resume this old post.
I still think the function FloatToStr is not working as it should.
1) The help file reports as an example

Mikro C 8.2.0.0
float ff = -374.2;
char txt[13];
//...
FloatToStr(ff, txt);
// txt is "-0.37420e3"

Mikro C Pro 2.50
float ff1 = -374.2;
float ff2 = 123.456789;
float ff3 = 0.000001234;
char txt[15];
...
FloatToStr(ff1, txt); // txt is "-374.2"
FloatToStr(ff2, txt); // txt is "123.4567"
FloatToStr(ff3, txt); // txt is "1.234e-6"


I have tested the example and it returns -374.1999

2) Using other compilers e.g. MS Visual Studio C++, where the float type is stored on 4 bytes, the result of a similar operation is as expected not a decimal calculation of the IEEE754 binary represantion of the number.

Could somebody please clarify further.
Thanks

janni
Posts: 5373
Joined: 18 Feb 2006 13:17
Contact:

#12 Post by janni » 27 Aug 2009 12:24

The FloatToStr function is not the culprit here (it could perform some forced rounding, but it's not a real solution). The source of the problem lies in Microchip floating point library (AN575), used, with some modifications, by mC. Due to errors in original code, the so-called unbiased rounding cannot be used and is blocked in the library. This also means that when converting from float to integral type, there's no rounding, as well - only truncation. These are the real reasons that lead to results with 9's at the end.

Maybe, in a free moment, I'll prepare a version of corrected f-p math lib for mC PRO (I have one working with mP - all it requires for mC is a header file for one of it's modules).

pic-o
Posts: 34
Joined: 21 Oct 2008 09:25
Location: London
Contact:

#13 Post by pic-o » 28 Aug 2009 00:24

Many thanks janni. I am looking forward to see your libraries :)

I am still wondering though how come a bug like this has not yet been addressed. I was under the impression the the "PRO" line of products would have been such.

janni
Posts: 5373
Joined: 18 Feb 2006 13:17
Contact:

#14 Post by janni » 28 Aug 2009 01:16

Well, this is not something that significantly reduces compiler usefulnees. There are not so many applications that require floating point calculations, and less still that realy need the unbiased rounding which matters only in complicated calculations. The 9's may be unnerving, but it's comparatively easy to fix the displayed string. I guess that mE had more important things to do than polishing the f-p math lib.

Post Reply

Return to “mikroC General”