This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Float to ASCII conversion without using sprintf function

Hello,

I am removing all sprintf() function from my souce code as this function does not allow me to set the proper thread stack size. Does anyone have any function that implements this conversion?

Thanks
Andre Moutinho

  • What do you mean by "proper stack size". sprintf() doesn't stop you from defining a stack size.

    That the analysis tool can't perform a 100% analysis of call depth and stack need? Is that really a problem. Multiple calls to sprintf() with same formatting string should not have any larger difference in stack needs. You can "paint" the stack with magic marker bytes and then check the waterlevel to see how much stack your thread did consume with different parameters. If you have a processor with 128 bytes of RAM, you really have to consider every single byte when trying to decide on stack size. If you have an ARM chip with 8kB or 32kB or whatever, you can normally survive with 128 byte extra for a specific thread just to make sure.

    If you are bored, you can always roll your own implementation to convert a floating point number to a text string - it isn't rocket sience.

  • Yes, the proper stack size because of the keil anaysis tool cannot perform 100% with functions such as sprintf(). I am already using the stack "paint" method but this is not a safe option for implementing complex systems on an embedded environment. I should have to run tests to guarantee the code is working but it is very complex and time consuming. I prefer trust on analysis tools instead.
    Implementing ftoa() is not difficult but I usually always try findining something ready instead of implementing everything. I have found some on google.
    Thanks
    Andre

  • Note that the use of sprintf() only affects tree branches using it.

    It isn't too hard to get a good estimate of stack depth from sprintf() itself for relevant formatting strings and parameter sets.

    The world have managed quit well with setting stack sizes without automatic tools at times when four bytes extra stack costed too much to waste - and where all your interrupts used the same stack. If you have only one thread with sprintf() then it really isn't too costly to add in a safety margin.

  • Too answer your first question, I don't believe it's obvious too you but making such a function is NO TRIVIAL matter. In fact it is quite a bit of work, you must account for +-INF 0 +-NAN just to name a few for floating point. In addition to these you must take care to get correct rounding and the sign of the number as well.

    Don't belittle the lowly printf formatting functions because Keil put an inordinate amount of effort to get those to work let alone work correctly (they are very good).

    I say this because I've had to do just what you were asking a while ago, it's not exactly a simple exercise AND you MUST know the format of the floating point data you are working with, there is lot of research needed before even starting. If you plan on doing this, good luck, it's about 8 days of work and testing. Also there are a considerable number of academic papers on the subject matter. It's not trivial, and that's just floating point (not the other myriad of functions that the vaprintf family performs).

    You may wish to look at the SDCC library if you want a reference. I had to write all of my code in C, and it cannot be made freely available (I don't own it).

    I can say it's doable, but you must select carefully what you wish to use out of the vaprintf family of formatting commands first.

    Stephen

  • Hello, I have implemented a ftoa function and made some tests. What do you think? I have spent around 1 hour with tests.. Maybe I have missed something. The str array must be size 20.

    void ftoa(float num, char *str)
    {
      int intpart = num;
      int intdecimal;
      int i;
      float decimal_part;
      char decimal[20];
    
      memset(str, 0x0, 20);
      itoa(num, str, 10);
    
      strcat(str, ".");
    
      decimal_part = num - intpart;
      intdecimal = decimal_part * 1000000;
    
      if(intdecimal < 0)
      {
        intdecimal = -intdecimal;
      }
      itoa(intdecimal, decimal, 10);
      for(i =0;i < (PRECISION - strlen(decimal));i++)
      {
        strcat(str, "0");
      }
      strcat(str, decimal);
    }
    

  • itoa(num, str, 10);
    


    And what happens if num is 12345678? You really think a function named IntegerToAscii is up to the task?

    Or what do you do if the number is 0.000000000000000012345678?

    How do you then store the fractional part in an integer?
    Or make itoa() make a string of it?
    Or make the number fit in a 20-character array?

    Also remember that sprintf() has more than one way to express a floating point value depending on the formatting string.

    Here is the deal - if using sprintf(), you must care about the stack needs. If using own function to convert a floating point value, you must care about the size of the target buffer.

    How much do you gain by not getting a stack overflow but instead a buffer overrun?

  • As Per mentioned there are a lot of things you are ignoring. I did give a strong HINT you should look at the EXISTING papers on this subject. It's not trivial the code your provided will work in narrow circumstances by the way (a lot of constraints). Perhaps you should define what you need to do before you go further? Also you may need to consider why you need to use sprintf in a thread separate from your primary thread.

    I believe you need to DEFINE your problem not just write code. It makes things much easier for yourself and other people when you set constraints that reduce possible difficulties in implementation. In my case for writing something equivalent to sprintf floating point formatting it was for what Per mentioned, to prevent buffer overrun. sprintf does not perform buffer overrun check, thus I had to make a variant that in no way could have a buffer overrun.

    You would be best served to do more research and planning on paper before you write any code. If you haven't defined your problem so that you can explain precisely and accurately what the constraints are "IE I can't use more than 128 bytes of stack space for this thread, this thread formats a double precision floating point for the user and places it on an LCD. The thread may not overrun the string buffer." etc etc. Those are constraints. Without specifications you are 'nailing jelly too a tree' (great book by the way).

    Stephen

  • Hello Westermark, thanks for your reply.

    Let me explain what I am doing first. My application is a module that has GPS and GPRS communication. I have a can interface and get some vehicle values such as speed, rotation, hodometer. The ftoa() function will be used only for debug of these values. I have checked their range and will be no larger than 2147483647 and not smaller than 0.00001.

    Please read the answers bellow:

    >And what happens if num is 12345678? You really think
    >a function named IntegerToAscii is up to the task?

    Yes, it converted with success. Why an itoa() function will not convert this number? The ftoa() function returned 12345678.00000. 12345678 < 2147483647 (0x7ffffff)

    >Or what do you do if the number is >0.000000000000000012345678?

    This will result in 0.00. But this value is out of the range precision I have stabilished. The result was 0.00000. Thats OK once I have stablished 6 digits of precision.

    >How do you then store the fractional part in an >integer?

    By multiplying for the precision I want. If I want 0.00001 I then multiply it for 100000.

    >Or make itoa() make a string of it?
    >Or make the number fit in a 20-character array?

    Limiting the higher value and precision. I have forgotten to limit the higher value. Will do it.

    >Also remember that sprintf() has more than one way to >express a floating point value depending on the >formatting string.

    Will not need this.

    >Here is the deal - if using sprintf(), you must care
    >about the stack needs. If using own function to
    >convert a floating point value, you must care about
    >the size of the target buffer.

    Yes, correct. I will narrow the higher value to 2147483647 (0x7FFFFFFF) or 10 digits. The decimal part in constrained to 5 digits. More one for the '.' and an extra 0x0 for final termination. Total used will be 17 characteres and no buffer overrun.

    >How much do you gain by not getting a stack overflow >but instead a buffer overrun?

    Nothing, but creating such constraints that works 100% in my application I eliminated both problems.

    Regards,
    Andre

  • Hello Stephen,

    Please read my previous reply. My application has more than 20 task and each task must have debug.

    Thanks
    Andre Moutinho

  • If you haven't debugged anything under an RTOS then I suggest you get some advice. Printfs in 20 different threads to debug your code is inadvisable and not likely to help you remain sane. It's difficult enough trying to debug something with a single thread but 20 is asking for serious trouble if you don't have a VERY well defined method.

    Break it down. Test each thread's code with all of it's possible states of error individually. This is not far fetched as I mentioned I wrote my own variant of printf, I had to guarantee that it WORKED correctly EVERY time and gave the correct answer EVERY time irregardless of what was thrown at it. I performed float point prints from -9999.99 to 9999.99 in 0.001 increments to verify it worked correctly (yes 2 million tests), and then -999.999 to 999.999 (another 2 million tests). That covers single precision floating points significant digits and all digits that would possibly be used. THEN I had to test out of range values and illegal floating point values etc. (generating random integers and type casting them as floats as well).

    This is a simple unit test. The specs are in the test itself (number ranges and digit count).

    You should do this amount of testing too each thread individually to insure that by itself (or 2 threads if it needs another to feed data too it etc) it works correctly.

    Printf on everything tends to just confuse things, and if you have 20 sources of debug data then you have 2^20 times the amount of possible confusion (binary joke had to be done).

    Once you have guaranteed each part of your program works correctly and leaves no unknown states the rest is relatively easy.

    Stephen