View Full Version : Leading spaces in numbers.spin

Steve Hicks (N5AC)
11-10-2006, 10:35 AM
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[--IChar] 'Get base indicator character
GChar := Symbols[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[@StrBuf][Size-Idx-1-GCnt] := lookupz(byte[@BCX0][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[@StrBuf][Size-X-Idx-(Idx-1)/Grouping #> 0] := SChar 'Insert sign
if X == 2
byte[@StrBuf][Size-1-Idx-(Idx-1)/Grouping #> 1] := IChar 'Insert base indicator, if necessary
byte[@StrBuf][Size] := 0 'Zero-terminate string


Steve, N5AC

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

Jeff Martin
11-10-2006, 11:43 PM
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...

_CLKMODE = xtal1 + pll16x
_XINFREQ = 5_000_000

TV : "TV_Text"
Num : "Numbers"

PUB Main
TV.Str(Num.ToStr(1024, Num#DDEC))

·prints the following on a TV screen:


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) + 1)

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:


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?


--Jeff Martin

· Sr. Software Engineer
· Parallax, Inc.

Steve Hicks (N5AC)
11-11-2006, 12:18 AM
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[@StrBuf][Size-X-Idx-(Idx-1)/Grouping #> 0] := SChar IF X == 2
byte[@StrBuf][Size-1-Idx-(Idx-1)/Grouping #> 1] := IChar

New code:

IF SChar <> " "
byte[@StrBuf][Size-X-Idx-(Idx-1)/Grouping #> 0] := SChar
if X == 2
byte[@StrBuf][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