Shop OBEX P1 Docs P2 Docs Learn Events
Writing first Propeller program, need really basic help with rounding numbers — Parallax Forums

Writing first Propeller program, need really basic help with rounding numbers

BigMikeBigMike Posts: 34
edited 2014-12-11 19:28 in Propeller 1
Hello Parallax,

Looooooong time BASIC Stamp user here, bought my first Propeller and am building my first project!

I am struggling with a super basic issue and I can't seem to find helpful documentation. I'm using SimpleIDE v1.0.1 RC1 along with a USB Propeller Activity Board.

I am performing a calculation on a float variable and am outputting its value to a 20x4 blue LCD screen. I need it to be a float because I would like to display the number to two decimal points, so I am trying to use round() to trim as such but SimpleIDE says "undefined reference to `_roundf'". Hmmmm? What is _roundf ?

My programming background is mainly with PHP & MySQL (web development) and I figured I'd try num = round(num,2) to round/trim to 2 decimal points but its not allowing it. So I thought maybe the Spin language doesn't use round(), but after a Google search I found some Propeller Reference Manual (http://www.parallax.com/sites/default/files/downloads/P8X32A-Web-PropellerManual-v1.2.pdf) which indeed does list a ROUND function, but its not working for me.

I thought about writing spaces to the characters after the 2nd decimal spot to essentially hide the rest of the number, but there has got to be a proper way to do this?

I did do quite a bit of searching and found http://forums.parallax.com/showthread.php/130526-Rounding-Numbers-with-the-Propeller, but the link Martin_H suggests is dead and I don't understand why if round() is in the manual then why do we need additional libraries?

Thank you very much in advance for the help!

Regards,
BigMike

Comments

  • dgatelydgately Posts: 1,630
    edited 2014-12-07 16:25
    BigMike,

    Are you using Spin's round() function on a constant? That's the only way the function can be used (see below)...

    Link to the manual: http://www.parallax.com/downloads/p8x32a-propeller-manual

    From the Web-PropellerManual-v1.2.pdf manual:
    ROUND
    Directive: Round a floating-point constant to the nearest integer.
    
    Using ROUND
    ROUND can be used to round floating-point constants up or down to the
    nearest integer value. Note that this is for compile-time constant expressions
    only, not run-time variable expressions. For example:
    
      CON
        OneHalf = 0.5
        Smaller = 0.4999
        Rnd1    = round(OneHalf)
        Rnd2    = round(Smaller)
        Rnd3    = round(Smaller * 10.0) + 4
    


    dgately
  • Mike GreenMike Green Posts: 23,101
    edited 2014-12-07 19:57
    The built-in floating point is compile-time only. You have to use the float library functions for all floating point operations on variable values including rounding. I use the F32 library (see here: http://obex.parallax.com/object/229). FRound(x) will round the floating point variable x and return the resulting integer.
  • dbpagedbpage Posts: 217
    edited 2014-12-08 03:16
    If it's only for display purposes, I use integer math by properly scaling the factors and artificially setting the LCD decimal point. For example, if your result should be 1.25, it will be the integer 125 with properly scaled factors.
  • BigMikeBigMike Posts: 34
    edited 2014-12-08 08:58
    Thank you very much for the replies guys, I really appreciate all the help
    dgately wrote: »
    Are you using Spin's round() function on a constant? That's the only way the function can be used (see below)...
    Ahh, this makes sense now, I should have read more carefully.
    Mike Green wrote: »
    The built-in floating point is compile-time only. You have to use the float library functions for all floating point operations on variable values including rounding. I use the F32 library (see here: http://obex.parallax.com/object/229). FRound(x) will round the floating point variable x and return the resulting integer.
    Thank you for the link on this. If I read this correctly, it only rounds to the nearest integer? If so I think I like dbpage's idea below:
    dbpage wrote: »
    If it's only for display purposes, I use integer math by properly scaling the factors and artificially setting the LCD decimal point. For example, if your result should be 1.25, it will be the integer 125 with properly scaled factors.
    Ahh, I remember doing this for an assignment in a circuits lab back in college with my old Stamp. I already know how this can work and will go this route

    Thanks again everyone, I'll post up my code later tonight after work :)

    Regards,
    BigMike
  • BigMikeBigMike Posts: 34
    edited 2014-12-08 15:29
    Ok,

    Got some time during my lunch break to play with my code and I can't even figure out how to get a float converted to a int so I can do integer math on it.

    In a simple example, here is what I'm trying to do:
    #include "simpletools.h"
    #include "adcDCpropab.h"
    
    int main()
    {
      serial *lcd = serial_open(2, 2, 0, 9600); // Using a LCD117 that I've used on old BASIC Stamp projects (http://moderndevice.com/wp-content/uploads/resources/lcd117asmb/LCD117_Board_Command_Summary.pdf)
      adc_init(21, 20, 19, 18);
    
      float vdd;
      int test;
    
      while(1)
      {
        vdd = adc_volts(3);  // Reading 0-5 volts from an automotive intake manifold pressure sensor
    
        dprint(lcd, "?fVoltage: %f", vdd);  // Displays "Voltage: 2.657471" and the number changes per iteration
    
        // Now I'll try to convert to an int which should only display "2"
    
        test = (int) vdd;
    
        dprint(lcd, "?fTest: %f", test);  // Displays "Test: 0.000000"
    
        pause(200);
      }
    }
    

    So it's only displaying 0.000000. Converting it to an integer I'd assume would print just the number 2 but so far it's only printing exactly 0.000000. Even on the terminal, it's doing the same. I tried a direct "test = vdd" and I still get "0.000000"

    Any ideas?

    Thanks
    Mike
  • John AbshierJohn Abshier Posts: 1,116
    edited 2014-12-08 15:55
    > dprint(lcd, "?fTest: %f", test); // Displays "Test: 0.000000"

    Do you want a %f format specifier to print an int (test)? I haven't used C in a while, I think %d is for an int.

    John Abshier
  • BigMikeBigMike Posts: 34
    edited 2014-12-08 19:20
    %d is for an int.

    John, thank you, that did the trick. This is what I'm talking about....
    BigMike wrote: »
    ...and I can't seem to find helpful documentation.

    Maybe there just needs to be more basic examples on the Learn section of parallax.com. ......or I am spoiled in the way I came to Parallax, which was through a circuits lab class during college. Our professor taught us everything we needed and I never really browsed parallax.com. Now that I'm embarking on my own with the Propeller, it's a bunch of Google searches and trial and error, and of course excellent and speedy help now that I've begun posting to the forums :)'

    Glad to be receiving such great help here, looking forward to leaning a lot with the Propeller and using it to build some of my longstanding plans!

    Cheers,
    BigMike
  • BigMikeBigMike Posts: 34
    edited 2014-12-08 20:57
    Ok, got it working beautifully!

    Here is what I'm using:
    ...
    
    float vdd; // Input 0-5v reading
    int n, d;  // n = Whole Number, d = Decimal
    
    // assume vdd = 2.657471
    ...
    
    n = (int) vdd;
    d = (int) (vdd * 100) - (n * 100);
    dprint(lcd, "?fVoltage: %d.%d", n, d);
    pause(5);
    
    ...
    

    Displays, "Voltage: 2.65" and I'm not too concerned about the rounding so this works great for me.

    Later in my code I've converted the voltage into manifold pressure (PSI) and encounter negative numbers. Here is what I'm doing for that along with positioning the line of text just where I want it on my LCD. Recycling n & d variables throughout:
    ...
    
    psi = ((vdd - 2.5) * 14.69) / (5 - 2.5);       // Convert MAP Voltage to PSI.
    
    ...
    
        // PSI Display
        n = (int) psi;
        if (psi < 0)
          d = abs((int) (psi * 100) - (n * 100));
        else
          d = (int) (psi * 100) - (n * 100);
        if (n > 9)
          dprint(lcd, "?y2?x06%d.%d ", n, d);
        else if ((n < 10) && (n >= 0))
          dprint(lcd, "?y2?x05 %d.%d  ", n, d);
        else if ((n < 0) && (n > -10))
          dprint(lcd, "?y2?x05 %d.%d  ", n, d);
        else
          dprint(lcd, "?y2?x06%d.%d", n, d);
        pause(5);
    

    Added blank spaces after smaller numbers to write over lingering figures per refresh ;)

    Regards,
    BigMike
  • dbpagedbpage Posts: 217
    edited 2014-12-09 03:10
    To round before truncating, simply add 0.005 to positive floating point values and subtract 0.005 (or add -0.005) to negative values.
  • jazzedjazzed Posts: 11,803
    edited 2014-12-09 09:25
    What's up Docs?

    Documentation available through SimpleIDE Help ....


    SimpleIDE User Guide

    PropellerC Tutorials

    Simple Library Help

    PropGCC Reference

    Another starting point for beginners: learn.parallax.com/propellerc
    More experienced users may also learn about what parallax thinks is important in the parallax propellerc pages.

    Some favorite C programming documentation links:

    http://publications.gbdirect.co.uk/c_book/
    http://www.cplusplus.com/reference/clibrary/

    For curmudgeonous old C programmers:

    Use Linux and type "man " or whatever makes you happy.



    Hope this post helps a bit. If not, "we" can sort it out.
  • BigMikeBigMike Posts: 34
    edited 2014-12-11 19:28
    Thank you dbpage for the rounding, got it added, and thank you jazzed for the references.

    I am wondering, is there a way to use strings with the Propeller? Instead of having two variables and all these if, else if statements depending on variable size, I could just write the numbers to a string and display one string.

    As a simple example, if I have the number 2.55, I am currently displaying it as:
    dprint(lcd, "?y1?x06%d.%d", n, d);
    

    ...where '2' is stored to the 'n' int variable and '55' is stored to the 'd' int variable. I am having to code this as, %d.%d where the decimal is included between the two variables to simulate the full number.

    What I'm currently thinking would be easier is to try something like...
    char text;
    
    text = n . "." . d;
    
    dprint(lcd, "?y1?x06%s", text);
    

    This is like a mix of PHP and C I suppose, as I tried it and it doesn't work :P

    Where it becomes more beneficial is that I have other parts of my code where I have a display of, for example, "Thr: 12%, MAP: 2.55v", and what I'm having to do is move around on the same line with a dprint command for "Thr:", another dprint for "%, MAP:", then another dprint for the Throttle value, then another dprint for the MAP value, and then a final dprint for the voltage sign "v". So that is five dprint's that I'm shifting numbers and spaces around based on variable length when if I could just store all of this to a text string and then just send the one text string to the display in one dprint that would be much more efficient.

    Thoughts?

    Thanks
    Mike
Sign In or Register to comment.