Shop OBEX P1 Docs P2 Docs Learn Events
Display unsigned cnt in spin — Parallax Forums

Display unsigned cnt in spin

dbpagedbpage Posts: 217
edited 2016-09-23 02:29 in Propeller 1
Do you have an elegant spin method to convert cnt to display unsigned 10 ASCII characters in the range of 0 to 4,294,967,295 without PASM support? It seems easy for someone smarter than me.

Comments

  • kwinnkwinn Posts: 8,697
    Take a look at the "Dec" code in the FullDuplexSerial object.
  • FullDuplexSerial "Dec" outputs a signed number in the range of -2,147,483,648 to 2,147,483,647.
  • I can't think of a simple way to do this.

    I think you need to test to see if the number if negative and if it's negative split the number into to parts.

    I can't think of an easy way to split the number to allow you output the 10 characters but I'm sure this is possible.
  • kwinnkwinn Posts: 8,697
    dbpage wrote: »
    FullDuplexSerial "Dec" outputs a signed number in the range of -2,147,483,648 to 2,147,483,647.

    True, but it is simple to modify the code to print as an unsigned binary number.
  • I'm sure it is simple and I'll be embarrassed for asking the forum to show me how.
  • kwinn wrote: »
    True, but it is simple to modify the code to print as an unsigned binary number.

    Is it? I've modified dec methods a bunch of times but I can't think of a simple way to output an unsigned 32-bit number.

    Spin treats all longs as signed numbers.

  • AribaAriba Posts: 2,690
    edited 2016-09-22 19:02
    How about this:
      temp := CNT
      ser.dec((temp>>1) / 5)        'show first 9 chars (max.)
      if temp < 0
        temp := POSX-1+temp
      ser.dec(temp // 10)           'show last char
    
    It's not so simple because *, / and // works also with signed numbers. >> allows an unsigned division by 2.

    Andy

    Edit: There seems to be a Problem with $8000_0000 and $8000_0001 for the lowest digit.
  • Dave HeinDave Hein Posts: 6,347
    edited 2016-09-22 19:02
    Ariba, I like your solution. However, if CNT is between 0 and 9 you will get a "0X", where X is the value of CNT. The first ser.dec should be done only if temp < 0 or temp > 9.
  • PUB uDec(value) | i, x, s  
    {{
       Transmit the ASCII string equivalent of an un-signed decimal value
    
       Parameters: value = the numeric value to be transmitted unsigned
       return:     none
    
       example usage: serial.uDec(-1)
    
       expected outcome of example usage call: Will print the string "4294967295" to a listening terminal.
    }}
    
      s := 0
      if value < 0
        repeat until value => 0
          value -= 1_000_000_000
          s++
    
      i := 1_000_000_000
    
      repeat 10
        if value => i
          fds.Tx(value / i + s~ + "0")
          value //= i
          result~~
        elseif result or i == 1
          fds.Tx("0")
        i /= 10      
      
    
  • ersmithersmith Posts: 6,053
    edited 2016-09-22 20:21
    You'll have to adjust the last digit because POSX-1 has a last digit of 6 rather than 0. This should work:
    PUB dec_uns(tmp) | last
      if (tmp => 0)
          ser.dec(tmp)
          return
      last := (tmp // 10) + 6
      if (last < 0)
        last += 10
      tmp := (tmp>>1)/5
      ser.dec(tmp)
      ser.dec(last)
    
    (Edited for somewhat cleaner code)
  • ersmith,

    I think your method always displays a leading zero.

    -Phil
  • ersmith,

    I think your method always displays a leading zero.

    -Phil

    The first test for "tmp => 0" ensures that any single digit positive numbers will be printed normally. The rest of the code only deals with unsigned numbers that are much greater than 10 (greater than 2 billion, in fact) so "tmp" will always be non-zero after the divide by 10.

    Eric
  • I see. :)

    -Phil
  • tmp := (tmp>>1)/5 is elegant. Too bad the last digit is messy.

    Good work guys. Thanks.

  • AribaAriba Posts: 2,690
    Here is another solution for the last digit:
        tmp := cnt
        if tmp<0 or tmp>9
          ser.dec(tmp>>1 / 5)
        ser.dec(tmp>>1 // 5 * 2 + (tmp & 1))
    

    Andy
  • dbpage wrote: »
    Good work guys. Thanks.

    +1 from me.

    I appreciate seeing these solutions.

  • dbpagedbpage Posts: 217
    edited 2016-09-23 02:46
    Ariba wrote: »
    Here is another solution for the last digit:
        tmp := cnt
        if tmp<0 or tmp>9
          ser.dec(tmp>>1 / 5)
        ser.dec(tmp>>1 // 5 * 2 + (tmp & 1))
    

    Andy

    Nice. Elegant.
  • I think
    tmp>>1 // 5 << 1 + (tmp & 1)
    
    is a little faster than
    tmp>>1 // 5 * 2 + (tmp & 1)
    
  • dbpagedbpage Posts: 217
    edited 2016-09-23 23:02
    While analyzing my last post, I found that, due to differences in operator precedence levels between "<<" and "*", the following snippets give different results:
    tmp := -10
    tmp>>1 // 5 * 2   ' = 6
    tmp>>1 // 5 << 1  ' = 3
    

    By controlling the operator precedence levels, following give identical results:
    tmp := -10
    tmp>>1 // 5 * 2     ' = 6
    (tmp>>1 // 5) << 1  ' = 6
    

    Yet, even though the above snippet results differ, the following give identical results:
    tmp := -10
    tmp>>1 // 5 << 1 + (tmp & 1)    ' = 6
    (tmp>>1 // 5) << 1 + (tmp & 1)  ' = 6
    

    Interesting.
  • I get a value of 3 from the expression "tmp>>1 // 5 << 1 + (tmp & 1)" when tmp is -10.
  • dbpagedbpage Posts: 217
    edited 2016-09-24 01:22
    You're right. My mistake.
    tmp := -10
    tmp>>1 // 5 * 2 + (tmp & 1)     ' = 6
    (tmp>>1 // 5) << 1 + (tmp & 1)  ' = 6
    tmp>>1 // 5 << 1 + (tmp & 1)    ' = 3  Incorrect
    (tmp>>1 // 5) << 1 + (tmp & 1)  ' = 6  Correct
    
Sign In or Register to comment.