Shop OBEX P1 Docs P2 Docs Learn Events
Leading spaces in numbers.spin — Parallax Forums

Leading spaces in numbers.spin

Steve Hicks (N5AC)Steve Hicks (N5AC) Posts: 20
edited 2006-11-10 17:18 in Propeller 1
I really like numbers.spin.· It is a real work of art!· I have been using it to display numbers, but I'm having trouble getting rid of the leading space for positive numbers.· Upon investigation, it appears that there is a mandatory sign character on the front of a string created with ToStr -- if the number is positive and no display of a sign is selected in the config, it·places a space on the front of the string instead.· I prefer, however,·to not have anything on the front of the number if it is positive and I've not selected a sign.· I made a slight modification to the internal routine, BCXToText as shown below that accomplishes this.· Just in case someone else has the same desire...· Just replace this one routine in your numbers.spin file·or you can use·the attached modified numbers.spin file.

PRI BCXToText(IChar, Grouping, ShowPlus, SPad, Field, Digits): Size | Idx, GCnt, SChar, GChar, X
'Convert BCX Buffer contents to z-string at StrBuf.
'IChar..Field each correspond to elements of Format.  See "FORMAT SYNTAX" for more information.
'If Field = 0, Digits+1+Grouping is the effective field (always limited to max of 49).
'Digits  : Number of significant digits (not counting zero-left-padding).
'RETURNS:    Actual Size (length) of output string, not including null terminator.
  SChar := "+" + 2*(BCX3 >> 28) + 11*(not (ShowPlus | (BCX3 >> 28)) or ((Digits == 1) and (BCX0 == 0))) 'Determine sign character ('+', ' ' or '-')
  X := -(SChar <> " ")-(IChar > 0)                                                                      'Xtra char count (0, 1 or 2, for sign and optional base indicator)
  IChar := Symbols[noparse][[/noparse]--IChar]                                                                             'Get base indicator character
  GChar := Symbols[noparse][[/noparse]Grouping & 7 - 1 #> 0]                                                               'Get group character
  if Field > 0 and SPad^1 and Digits < 32                                                               'Need to add extra zero-padding?
    BCX3 &= $0FFFFFFF                                                                                   '  then clear negative flag and set to 32 digits
    Digits := 32
  Grouping := -((Grouping >>= 3) - (Grouping > 0))*(Grouping+1 < Digits)                                'Get group size (0 if not enough Digits)
  Size := (Field - (Field==0)*(Digits+X+((Digits-1)/Grouping))) <# 49                                   'Field = 0?  Set Size to Digits+X+Grouping (max 49).
  if Grouping                                                                                           'Insert group chars
    bytefill(@StrBuf+(Size-Digits-(Digits-1)/Grouping #> 2), GChar, Digits+(Digits-1)/Grouping <# Size-4)
  Idx~~                                                                                                 'Insert digits
  repeat while (++Idx < Digits) and (Idx + (GCnt := Idx/Grouping) < Size-X)
    byte[noparse][[/noparse]@StrBuf][noparse][[/noparse]Size-Idx-1-GCnt] := lookupz(byte[noparse][[/noparse]@BCX0][noparse][[/noparse]Idx>>1] >> (4 * Idx&1) // 16: "0".."9","A".."F")
  bytefill(@StrBuf, " ", Size-Idx-(Idx-1)/Grouping #> 0)                                                'Left pad with spaces, if necessary
  IF SChar <> " "
    byte[noparse][[/noparse]@StrBuf][noparse][[/noparse]Size-X-Idx-(Idx-1)/Grouping #> 0] := SChar                                            'Insert sign
  if X == 2
    byte[noparse][[/noparse]@StrBuf][noparse][[/noparse]Size-1-Idx-(Idx-1)/Grouping #> 1] := IChar                                            'Insert base indicator, if necessary
  byte[noparse][[/noparse]@StrBuf][noparse][[/noparse]Size] := 0                                                                              'Zero-terminate string


▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔


Steve, N5AC

Post Edited (Steve Hicks (N5AC)) : 11/10/2006 3:57:18 AM GMT

Comments

  • Jeff MartinJeff Martin Posts: 755
    edited 2006-11-10 16:43
    Hi Steve,

    Wow, what a great compliment!· Thank you!

    When·creating the Numbers object, I spent a lot of time thinking about formatting the output.··In past experience, I have often run into frustrating problems formatting a group of numbers on a screen·so that they line up properly in relation to text and other numbers (not necessarily when right justifying, but when using the default left justification).· This is made worse when you have numbers that may be either positive or negative and a limited space in which to display them (like on a small LCD text display).

    Though I really didn't like the idea of forcing the leftmost character to be the sign character, it turned out to be the most beneficial because it's deterministic (it always does it that way) so that when faced with both positive and negative numbers that you may want to left-justify, for example, you don't get the numbers shifting to the right all of a sudden just because they are negative... or worse, not displaying the whole number in the space provided because they suddenly include an extra character for sign.· So, I chose to make it always have a sign character, that is either a space, plus sign or negative sign.

    But... here's a cool trick (and is the final reason I chose to make it the way it is):· If you know you have·positive-only numbers, you can always choose to display them starting with the second character of the returned string, all the time, by adding 1 to the string address that is returned.·

    For example, this code...
    CON
      _CLKMODE = xtal1 + pll16x
      _XINFREQ = 5_000_000
     
    OBJ
      TV :  "TV_Text"
      Num : "Numbers"
     
    PUB Main
      TV.Start(12)
      Num.Init
      TV.Str(string("Hello"))
      TV.Out(13)
      TV.Str(Num.ToStr(1024, Num#DDEC))
    

    ·prints the following on a TV screen:
    Hello
     1,024
    

    which, of course may not be what you wanted because it reserves the first character as the sign character, just in case it is negative, or in case the user wanted +/- shown all the time.·

    But, if you change the last line of that code to:
    TV.Str(Num.ToStr(1024, Num#DDEC) [b][color=blue]+ 1[/color][/b])
    

    You've told TV.Str to start with the second character of the string (by adding 1 to the string address returned by Num.ToStr).

    This change causes the display to look like:
    Hello
    1,024
    

    Of course, if it were really trying to print -1,024, it would appear as positive 1,024.


    I'm interested in seeing how your modification works, but I ran into problems.· When I·tried·using the DDEC formatting option, it only seems to print "1" on the screen instead of 1,024.

    I just copied and pasted it in its entirety.· Was that the only routine that you changed to make it work?

    Thanks.


    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    --Jeff Martin

    · Sr. Software Engineer
    · Parallax, Inc.
  • Steve Hicks (N5AC)Steve Hicks (N5AC) Posts: 20
    edited 2006-11-10 17:18
    Well, I didn't do "extensive" testing so your mileage may vary, but what I changed was to move the SChar definition up to the top line of BCXToText so that it gets defined first and I can look at it.· Then I changed the calculation of X from what you had (that would produce a 1 or a 2 for the number of leading characters) to make X 0,1, or 2· --- the calcuation should be the same in all circumstances except when SChar is a space. Old code:
      X := 1-(IChar > 0)
    

    New code:
      X := -(SChar <> " ")-(IChar > 0)
    

    Then lower down, I just look to see if there is a space char for SChar and, if so, I just suppress writing it (since there's no space for it now!)... old code:

      byte[noparse][[/noparse]@StrBuf][noparse][[/noparse]Size-X-Idx-(Idx-1)/Grouping #> 0] := SChar   IF X == 2
        byte[noparse][[/noparse]@StrBuf][noparse][[/noparse]Size-1-Idx-(Idx-1)/Grouping #> 1] := IChar
    
    

    New code:
      IF SChar <> " "
        byte[noparse][[/noparse]@StrBuf][noparse][[/noparse]Size-X-Idx-(Idx-1)/Grouping #> 0] := SChar 
      if X == 2
        byte[noparse][[/noparse]@StrBuf][noparse][[/noparse]Size-1-Idx-(Idx-1)/Grouping #> 1] := IChar
    
    

    I tried to study the code and make minimal changes that wouldn't break anything, but hey you know how it is when you work on someone else's code sometimes!


    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔


    Steve, N5AC
Sign In or Register to comment.