{"id":57,"date":"2008-03-16T16:01:44","date_gmt":"2008-03-16T18:01:44","guid":{"rendered":"http:\/\/www.ragestorm.net\/blogs\/?p=57"},"modified":"2008-03-16T16:01:44","modified_gmt":"2008-03-16T18:01:44","slug":"converting-a-floating-point-number-to-a-string-explained","status":"publish","type":"post","link":"https:\/\/www.ragestorm.net\/blogs\/?p=57","title":{"rendered":"Converting A Floating Point Number To A String &#8211; Explained"},"content":{"rendered":"<p>I was always curios about how to convert a floating point number into a decimal ASCII string. The equation is trivial after you get to implement it. But the idea behind took me a long while to come up with. For the sake of example I will deal with a single precision floating point of IEEE 754. However, it doesn&#8217;t really matter to me how many bits I have to convert into a string, the algorithm stays the same.\u00a0Floating Point numbers have all this crap about NaNs and QaNs and other weird stuff that I didn&#8217;t care about. They are just technical stuff that you have to implement, nothing really hard about it. I am just gonna focus on the way to\u00a0convert the mantissa (that&#8217;s the part of the fraction of the real number) into decimal. I think it&#8217;s rather easy to take a look at the implementation of printf in libc of Linux. That way you don&#8217;t have a challenge with coming with this, eventually, simple algo on your own.<\/p>\n<p>To simplify matters, I don&#8217;t handle big exponents, again it was not my focus. If you wish to change this code to something really usable, it&#8217;s possible with some work. Here I am not going to cover the format of the IEEE 754 floating point. I presume you know it, and if not, give it a look <a href=\"http:\/\/en.wikipedia.org\/wiki\/IEEE_floating-point_standard\">here<\/a>.<\/p>\n<pre>\r\nvoid pf(unsigned long x)\r\n{\r\n unsigned int sign = x &gt;&gt; 31;\r\n unsigned int exp = ((x &gt;&gt; 23) &amp; 0xff) - 127;\r\n\u00a0unsigned int man = x &amp; ((1 &lt;&lt; 23) - 1);\r\n\u00a0man |= 1 &lt;&lt; 23;\r\n\u00a0if (sign) printf(\"-\");\r\n\u00a0printf(\"%d\", man &gt;&gt; (23 - exp));\r\n\u00a0printf(\".\");\r\n\u00a0unsigned int frac = man &amp; ((1 &lt;&lt; (23-exp)) - 1);\r\n\u00a0unsigned int base = 1 &lt;&lt; (23 - exp);\r\n\u00a0int c = 0;\r\n\u00a0while (frac != 0 &amp;&amp; c++ &lt; 6)\r\n\u00a0{\r\n\u00a0 frac *= 10;\r\n\u00a0 printf(\"%d\", (frac \/ base));\r\n\u00a0 frac %= base;\r\n\u00a0}\r\n printf(\"\\n\");}\r\n}<\/pre>\n<p>You can see in the beginning that we extract the sign bit, exponent and mantissa from the <em>raw<\/em> number we got as a parameter. Then we fix the exponent since it is biased, though it&#8217;s a really nice trick, I won&#8217;t cover it today. And we set bit 24 in the mantissa, because we assume we got a <em>normalized<\/em> floating point number where bit 24th in the data is implied and not saved to spare this extra bit&#8230; Printing the sign is self explantory. And then we print the integer part of the mantissa, while taking care of the exponent. This is where a too big or too small exponent will screw up things. But for small integers everything is fine just yet.<\/p>\n<p>Now the fun begins, converting the mantissa from base 2 to base 10. Yipi kay hey. Let&#8217;s see. We store the fraction part of the floating point number and the base. For now let&#8217;s ignore this base variable and we will get back to it later. We limit the loop to print 6 digits or less when there is no more what to print. The algorithm here is to &#8216;pull&#8217; the digits over to be in the integer part of the number and print that part which is straight forward (though it&#8217;s only a digit and not a whole integer). Then we see how much more digits we have left to print and repeat the body of the loop until we&#8217;re done or printed enough digits.<\/p>\n<p>I will try to explain this loop again this way: Let&#8217;s say you want to print the number 5\/6 in decimal. How will you do that? That&#8217;s the key algorithm for converting the number to decimal as well in our case. I was told by a friend that children are taught this method in elemtary school, maybe I lacked of that class or we didn&#8217;t have it. :) Then what we are doing is: multiplying the 5 by 10 then see how many times it gets in the result: 50\/6 = 8, then we do a modulu with 6, getting 50%6=2. And starting again, 2*10=20; 20 \/ 6 = 3; 20%6=2; 2*10=20; 20\/6=3 and over and over again, the final result is 0.8333&#8230; This is similar to 1\/3, try this algo on 1\/4 and you will see that you get 2 and then 5 and then you reach 0 and stop, resulting in 0.25.<\/p>\n<p>Back to the code above, we take the fraction part and we have a base, take a long breath &#8211;\u00a0of 2 powered by the number of bits the fraction use to be stored. Why is that the base?<\/p>\n<p>Like when you convert an integer to decimal, you have to multiply every set bit by 2**index, where the index is the index of the set bit in the integer stream. For example: 111b is 1*2**0 + 1*2**1 + 1*2**2 = 1 + 2 + 4\u00a0= 7. The same goes for bits that are on the right side of the point (thus fractions): .11b is 1*2**(-1) + 1*2**(-2) = 1\/2 + 1\/4 = 0.75. Notice that the indices this time are negative, and power of negative number is division, therefore:\u00a01\/base**(-index). Now <em>instead of doing this conversion per bit<\/em>, we can do it simply by dividing the fraction <em>once<\/em>, in our example: 11b by 4. (base\u00a0powered by\u00a0number of bits, 2**2=4). Now we <em>treat the fraction as an integer and divide it by the new calculated base<\/em>; we get 3\/4 = 0.75. We saw how\u00a0the conversion can be done easily and we need a way to\u00a0print the result of such division&#8230;\u00a0And now we&#8217;re back to the description above of how to print a simple fraction. This time we know the reasons behind the fraction and the base. Note that the base is bigger than the fraction by nature, otherwise we won&#8217;t have a correct input for the algo and then it won&#8217;t work well.<\/p>\n<p>How to use the above code:<br \/>\nfloat x = 1337.99;<br \/>\npf(*(unsigned long*)&amp;x);<br \/>\nprintf(&#8220;%f&#8221;, x);<\/p>\n<p>Running the code using a different number every time, you will see that printf %f actually rounds the number where we print it as a raw floating number, without touching it. Therefore, next time I will talk about rounding the number.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I was always curios about how to convert a floating point number into a decimal ASCII string. The equation is trivial after you get to implement it. But the idea behind took me a long while to come up with. For the sake of example I will deal with a single precision floating point of [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"spay_email":"","jetpack_publicize_message":""},"categories":[21],"tags":[],"jetpack_featured_media_url":"","jetpack_publicize_connections":[],"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/pbWKd-V","_links":{"self":[{"href":"https:\/\/www.ragestorm.net\/blogs\/index.php?rest_route=\/wp\/v2\/posts\/57"}],"collection":[{"href":"https:\/\/www.ragestorm.net\/blogs\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.ragestorm.net\/blogs\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.ragestorm.net\/blogs\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.ragestorm.net\/blogs\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=57"}],"version-history":[{"count":0,"href":"https:\/\/www.ragestorm.net\/blogs\/index.php?rest_route=\/wp\/v2\/posts\/57\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.ragestorm.net\/blogs\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=57"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.ragestorm.net\/blogs\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=57"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.ragestorm.net\/blogs\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=57"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}