Announcement

Collapse

Forum Guidelines

This forum is for finished source code that is working properly. If you have questions about this or any other source code, please post it in one of the Discussion Forums, not here.
See more
See less

SI Units Prefix A Floating Point Number.

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • PBWin/PBCC SI Units Prefix A Floating Point Number.

    'This project makes a previous project more complete. And that project will
    'complete a still earlier project. This source code is also at"
    ' http://www.yarker-dsyc.info/D_Notebo...fixFormat.html
    'along code to demonstrate the function, and more description than I want
    'to put here.
    'For questions please start a thread in "Programming".
    '
    'SI prefix format
    'Significand formated as 1 to less than 1000, and append prefix for exponents
    'that are a multiple of 3.
    '
    Code:
    'Copyleft 2022 by Dale Yarker; do what you want with this code except claim it
    'as yours.
    #compile sll "SI_PrefixFormatB3.sll"
    #dim all
    
    function SI_Format(byval NumToFormat as ext, _
                   opt byval DigitsOut as long, _
                   opt byval DP_Align as long) common as wstring
      'local AbsNumToFormat, Inverse10E,  as ext
      local SignificandStr, SI_Prefix as wstring
      local NumIsNeg, NumIsPos, e_location, E, E_Mod3 as long
    
      '------------------------------------------- Format zero and set sign variabes
      if NumToFormat = 0& then
        if DP_Align then
          function = "   0.0"
        else
          function = "0.0"
        end if
        exit function
      elseif NumToFormat < 0& then
        NumIsNeg = 1&
      else
        NumIsPos = 1&
      end if
      '----------------------------------------------- Check/Set number of DigitsOut
      if DigitsOut = 0 then 'set default if optional parameter not used
        DigitsOut = 6&
      else                   'set to min or max if parameter outside limits
        if DigitsOut < 3& then
          DigitsOut = 3&
        elseif DigitsOut > 18& then
          DigitsOut = 18&
        end if
      end if
      '-----------------------------------------------
      SignificandStr = format$(NumToFormat, string$(DigitsOut, "#") + "e-##")
      e_location = instr(SignificandStr, "e")
      E = val(mid$(SignificandStr, e_location + 1&)) + DigitsOut - 1
      SignificandStr = mid$(SignificandStr, 1 to e_location)
     if E >= 0& then
        E_Mod3 = E mod 3&
        E \= 3&
      else
        E += -2&
        E_Mod3 = E mod 3& + -1&
        E \= 3&
      end if        '=============================
      '------------------ Use modulus to place decimal point, and space to align. --
      if E_Mod3 = 2 then ' · · · · · · · · · · · · · · · · · · · · · is hundreds · ·
        if DigitsOut > 3 then
          SignificandStr = strinsert$(SignificandStr, ".", 4 + NumIsNeg)
        end if
        if DP_Align and NumIsPos then
          SignificandStr = strinsert$(SignificandStr, " "$$, 1)
        end if
      elseif E_Mod3 = 1 then ' · · · · · · · · · · · · · · · · · · · · · is tens · ·
        SignificandStr = strinsert$(SignificandStr, ".", 3 + NumIsNeg)
        if DP_Align then
          SignificandStr = strinsert$(SignificandStr, space$(1 + NumIsPos), 1)
        end if
      elseif E_Mod3 = 0 then ' · · · · · · · · · · · · · · · · · · · ·  is units · ·
        SignificandStr = strinsert$(SignificandStr, ".", 2 + NumIsNeg)
        if DP_Align then
          SignificandStr = strinsert$(SignificandStr, space$(2 + NumIsPos), 1)
        end if
      elseif E_Mod3 = -1 then '· · · · · · · · · · · · · · · · ·  is hundreds of · ·
        if DigitsOut > 3 then
          SignificandStr = strinsert$(SignificandStr, ".", 4 + NumIsNeg)
        end if
        if DP_Align and NumIsPos then
          SignificandStr = strinsert$(SignificandStr, " "$$, 1)
        end if
      elseif E_Mod3 = -2 then '· · · · · · · · · · · · · · · · · · ·  is tens of · ·
        SignificandStr = strinsert$(SignificandStr, ".", 3 + NumIsNeg)
        if DP_Align then
          SignificandStr = strinsert$(SignificandStr, space$(1 + NumIsPos), 1)
        end if
      else '· · · · · · · · · · · · · · · · · · ·· · · · · · · · · · is units of · ·
        SignificandStr = strinsert$(SignificandStr, ".", 2 + NumIsNeg)
        if DP_Align then
          SignificandStr = strinsert$(SignificandStr, space$(2 -+ NumIsPos), 1)
        end if
      end if
      '. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
      '----------------------- Use exponent divided by 3 to select prefix letter. --
      if abs(NumToFormat) >= 1& then '·························· AbsNumtoFormat >= 1
        if E > 3& then '························································ E>3
          if E > 7& then '······················································ E>7
            if E >= 9& then '·················································· E>=9
              '++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Error ++
              goto OutOfRange
            else '······························································ E<9
              '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ e24«»e26 ++
              SI_Prefix = "Y"$$
            end if '
          elseif E < 7& then '·················································· E<7
            if E > 5& then '···················································· E>5
              '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ e18«»e20 ++
              SI_Prefix = "E"$$
            elseif E < 5 then '··················································E<5
              '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ e12«»e14 ++
              SI_Prefix = "T"$$
            else '······························································ E=5
              '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ e15«»e17 ++
              SI_Prefix = "P"$$
            end if
          else '································································ E=7
            '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ e21«»e23 ++
            SI_Prefix = "Z"$$
          end if
        elseif E < 3& then '···················································· E<3
          if E > 1& then '·······················································E>1
            '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ e6«»e8 ++
            SI_Prefix = "M"$$
          elseif E < 1& then '·················································· E<1
            '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ e0«»e2 ++
            SI_Prefix = ""$$
            SignificandStr = rtrim$(SignificandStr, "e")
          else '································································ E=1
            SI_Prefix = "k"$$
          end if 'E1
        else '·································································· E=3
          '++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 9«»11 ++
          SI_Prefix = "G"$$
        end if 'E3
      else '·····················································(fractions)·· NTF<1
        if E < -4& then '······················································ E<-4
          if E < -8& then '···················································· E<-8
            '++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Error ++
            goto OutOfRange
          elseif E > -8& then '················································ E>-8
            if E < -6& then '·················································· E<-6
              '+++++++++++++++++++++++++++++++++++++++++++++++++++++++ e-19«»e-21 ++
              SI_Prefix = "z"$$
            elseif E > -6& then '·············································· E>-6
              '+++++++++++++++++++++++++++++++++++++++++++++++++++++++ e-13«»e-15 ++
              SI_Prefix = "f"$$
            else '····························································· E=-6
              '+++++++++++++++++++++++++++++++++++++++++++++++++++++++ e-16«»e-18 ++
              SI_Prefix = "a"$$
            end if 'E-6
          else '······························································· E=-8
            '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ e-22«»e-24 ++
            SI_Prefix = "y"$$
          end if 'E-8
        elseif E > -4& then '·················································· E>-4
          if E < -2& then '···················································· E<-2
            '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ e-7«»e-9 ++
            SI_Prefix = "n"$$
          elseif E > -2& then '
            '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ e-1«»e-3 ++
            SI_Prefix = "m"$$
          else '······························································· E=-2
            '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ e-4«»e-6 ++
            SI_Prefix = "µ"$$
          end if 'E-2
        else '································································· E=-4
          '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ e-10«»e-12 ++
          SI_Prefix = "p"$$
        end if 'E-4
      end if 'NTF1
      '
      mid$(SignificandStr, len(SignificandStr), 1&) = $$spc
      function = SignificandStr + SI_Prefix'
      '
      exit function '===============================================================
      OutOfRange:
        function = "Out of SI range."$$
    end function '
    '
    '
    Dale

  • #2
    Apparently, two days ago, 4 more prefixes were added by SI; Q (10^30), R (10^27), r (10^-27) and q (10^-30). I have a couple other things to do before revising this. If you have need of the new prefixes, post in Programming. That will boost it in my priority list.

    Updated to include thousands separators.
    Compiled version, code description and apps to demo the function at:

    http://www.yarker-dsyc.info/D_Notebo...mat/index.html
    Link in post 1 now dead, use this one

    Main code follows include code with comments.
    For comments/questions on PB Forum please start a thread in Programming.
    '
    Code:
    'file SI_PrefixFormat.inc
    'Not really needed for one #LINK line. It has to be somewhere.
    '
    #link "SI_PrefixFormat.sll" 'adjust path as needed
    '
    '-------------------------------------------------------------------------------
    'for info if you only have compiled SLL -
    '
    'declare function SI_PrefixFormat alias "SI_PrefixFormat" _
    '                                          (byref NumToFormat as ext, _
    '                                       opt byval DigitsOut as long, _
    '                                       opt byval DP_Align as long, _
    '                                       opt byval No3DigGrps as long) as wstring
    'DigitsOut allows 3 to 18, default 6.
    '··3 minimum for hundreds in any prefix.
    '····option not used or 0 sets default.
    '····1, 2 or negative are corrected to 3.
    '··18 is maximum for Extended floating point type.
    '····greater than 18 is corrected to 18.
    '
    'DP_Align, not aligned is default.
    '··option not used or 0 for left aligned.
    '··non 0 (suggest -1) for left padded with spaces for decimal points alignment.
    '··(for best results use non-proportional (fixed width) font)
    '
    '###############################################################################
    'A MACRO for aligning on the decimal point posted elsewhere on PB forum. It
    'works with either proportional or non-proportional fonts. If you use that
    'MACRO, or similar code, do not use DP_Align option of this function.
    '
    'No3DigGrps, 3 digit groups (with thousands separators) is default.
    '··option not used or 0 for default.
    '··non 0 (suggest -1) for no separation.
    '-------------------------------------------------------------------------------
    'If you'd rather have a DLL than SLL, or pasting the function into your code;
    'comment the #LINK line, uncomment the whole DECLARE. In source file change
    '#COMPILE SLL to #COMPILE DLL, and COMMON to EXPORT in FUNCTION definition,
    'add ALIAS.
    '
    'SI prefix format updated version.
    '
    'Now thousands separation applied to fraction part of value with spaces by
    'default per the General Conference on Weights and Measures. This can optionally
    'be disabled. The significand (integer part) does not need thousands separation
    'because it is already limited to 1 to 999 in order to use the prefix.
    '
    'The units, or their abreviations, should be appended directly on the resulting
    'wide string. (Byte oriented strings should only used for DIBs, numeric types
    'and UTF-8 over a network.)
    '
    'Description of optional parameters in INCLUDE file in following code block.
    '
    '
    Code:
    'Copyleft 2022 by Dale Yarker; do what you want with this code except claim it,
    'or sell it, as yours. No warranty of any kind.
    #compile sll "SI_PrefixFormat.sll"
    #dim all
    '
    function SI_PrefixFormat(byval NumToFormat as ext, _
                         opt byval DigitsOut as long, _
                         opt byval DP_Align as long, _
                         opt byval No3DigitGrps as long) common as wstring
      #register none
      local NumInStr, NumOutStr as wstring
      local pNumInChar, pNumOutChar, pLastInChar, pLenNumOutStr as dword
      local NumIsNeg, ExpntIsNeg, RemainBytes as long
      local E as long '1st as exponent of normatized number in, then it
                      'is exponent integer divided by 3.
      local E_Mod3 as long 'Remainder of exponent integer divided by 3.
      '------------------------------------------- Check/Set number of DigitsOut. --
      ! push eax
      ! mov eax, DigitsOut
      ! cmp eax, 0&             'optional parameter not used or set to 0
      ! jne DigitsOutNotDefault 'go check minimum
        ! mov DigitsOut, 6&     'set default
        ! jmp DigitsOutDone
      DigitsOutNotDefault:
      ! cmp eax, 3&             'non-valid 1, 2 or negative
      ! jge DigitsOutNotLTMin   'go check maximum
      ! mov DigitsOut, 3&       'set minimum
      ! jmp DigitsOutDone
      DigitsOutNotLTMin:
      ! cmp eax, 18&            'non-valid greater than 18
      ! jle DigitsOutDone       'not above max
      ! mov DigitsOut, 18&      'set maximum
      DigitsOutDone:
      ! pop eax
      '------------------- Binary to string; get last digit, current digit and E. --
      'extended float input to string of integer plus exponent
      NumInStr = format$(NumToFormat, string$(DigitsOut, "#") + "e-##")
      '
      'Exponent of input as integer
      E = val(NumInStr, instr(-1, NumInStr, "e") + 1)
      '
      pNumInChar = strptr(NumInStr)
      NumOutStr = string$(30, $$nul)
      pNumOutChar = strptr(NumOutStr)
     ' ?
      '  ? E, NumInStr
      '  exit function
      '
      ! push eax
      ! push ebx
      ! push ecx
      ! push edx
      ! push edi
      ! push esi
      '------ Set variabes, leave in register if possible, or Format zero result. --
      'calculate pointer to last digit of input string
      ! mov ebx, DigitsOut
      ! sal ebx, 1???
      ! mov ecx, pNumInChar
      ! add ebx, ecx
      ! mov pLastInChar, ebx
    
     ' ! sal pLastInChar, 1& 'number characters times 2 for number of bytes
    
      ! sub pLastInChar, 2&
      'result character pointer to register and calculate pointer to
      'pointer to byte length of result string
      ! mov edi, pNumOutChar
      ! mov esi, edi
      ! sub esi, 4& 'is pLenNumOutStr
      'Check for negative
      ! cmp word ptr [ecx], &h002d??   '"-"
      ! je Sgnfcnd_Is_Neg              'can't be 0 if negative
        'Check "1" or greater than
        ! cmp word ptr [ecx], &h0031?? '"1"
        ! jae Sgnfcnd_NotZero
          'CHeck DP_Align
          ! cmp DP_Align, 0&
          ! jne SgnfcndIsZeroIsDPAlgn
          'SgnfcndIsZeroNotDPAlign
            ! mov dword ptr [edi], &h002E0030??? 'zero dp
            ! add edi, 4???
            ! mov  word ptr [edi], &h0030??      'zero
            ! mov dword ptr [esi], &h00000006??? '6 to pLenNumOutStr
          ! jmp FunctionDone
          SgnfcndIsZeroIsDPAlgn:
            ! mov dword ptr [edi], &h00200020??? 'space space
            ! add edi, 4???
            ! mov dword ptr [edi], &h00300020??? 'space zero
            ! add edi, 4???
            ! mov dword ptr [edi], &h0030002E??? 'dp zero
            ! mov dword ptr [esi], &h00000012??? '12 to pLenNumOutStr
          ! jmp FunctionDone
      Sgnfcnd_Is_Neg:
        ! mov NumIsNeg, -1&
      Sgnfcnd_NotZero: 'non-zero to here, positive skips past Sgnfcnd_Is_Neg
      '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ only EBX available ~~~~
      '-------------- Calc E \ 3 and E MOD 3, both modified for negative E MOD 3. --
      ! mov eax, E
      ! add eax, DigitsOut
      ! sub eax, 1&
      ! bt  eax, 31??? 'bit 31 can only be set if LONG is negative
      ! jnc E_IsPositive1
      ! mov ExpntIsNeg, -1&
      ! mov edx, -1& 'make edx upper part of 64 bit 2s compliment to eax's lower
      ! sub eax, 2&  '
      ! jmp DoDivide
      E_IsPositive1:
      ! xor edx, edx 'edx to 0
      DoDivide:
      ! mov ebx, 3& 'divisor
      ! idiv ebx
      ! cmp ExpntIsNeg, 0&
      ! je E_IsPositive2
      ! add edx, 2&
      E_IsPositive2:
      '-------------------- Use E MOD 3 for dp align, and to place decimal point. --
      '. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . is tens . .
      ! cmp edx, 1&
      ! jg HundredsInteger
      ! jl UnitsInteger
        'Tens Padding and minus sign
        ! cmp DP_Align, 0&
        ! je TensNoAlignPad
          'Tens Align Pad
          ! cmp NumIsNeg, 0&
          ! jne TensAlignNegPad
          'TensAlignPosPad
            ! mov dword ptr [edi], &h00200020??? 'space space
            ! add edi, 4&                        'OutChar ptr adjust
            ! mov dword ptr [esi], 4&             'Out Len set
            ! jmp TensIntegerDigits
          TensAlignNegPad:
            ! mov dword ptr [edi], &h002D0020??? 'space minus
            ! add ecx, 2&                        'InChar ptr adjust
            ! add edi, 4&                        'OutChar ptr adjust
            ! mov dword ptr [esi], 4&             'Out Len set
            ! jmp TensIntegerDigits
        TensNoAlignPad:
          ! cmp NumIsNeg, 0&
          ! jne TensNoAlignPadNeg
          'TensNoAlignPosPad
            ! mov dword ptr [esi], 0&             'Out Len set
            ! jmp TensIntegerDigits
          TensNoAlignPadNeg:
            ! mov word ptr [edi], &h002D??       'minus
            ! add ecx, 2&                        'InChar ptr adjust
            ! add edi, 2&                        'OutChar ptr adjust
            ! mov dword ptr [esi], 2&             'Out Len set
        TensIntegerDigits:
          ! mov ebx, dword ptr [ecx]             '2 digits InChar to register
          ! mov dword ptr [edi], ebx             '2 digits register to OutChar
          ! add ecx, 4&                          'InChar ptr adjust
          ! add edi, 4&                          'OutChar ptr adjust
          ! add dword ptr [esi], 4&               'Out Len adjust
          ! jmp DoDecimalPoint
      '· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · is hundreds · ·
      HundredsInteger:
        'Hundreds Padding and minus sign
        ! cmp DP_Align, 0&
        ! je HundredsNoAlignPad
          'Hundreds Align Pad
          ! cmp NumIsNeg, 0&
          ! jne HundredsAlignPadNeg
          'HundredsAlignPadPos
            ! mov word ptr [edi], &h0020??       'space
            ! add edi, 2???
            ! mov dword ptr [esi], 2&
            ! jmp HundredsIntegerDigits
          HundredsAlignPadNeg:
            ! mov word ptr [edi], &h002D??       'minus
            ! add ecx, 2???
            ! add edi, 2???
            ! mov dword ptr [esi], 2&
            ! jmp HundredsIntegerDigits
        HundredsNoAlignPad:
          ! cmp NumIsNeg, 0&
          ! jne HundredsNoAlignPadNeg
          'HundredsnoAlignPadPos
            ! mov dword ptr [esi], 0&             'set length of OutStr to 0
            ! jmp HundredsIntegerDigits
          HundredsNoAlignPadNeg:
            ! mov word ptr [edi], &h002D??       'minus
            ! add ecx, 2???
            ! add edi, 2???
            ! mov dword ptr [esi], 2&
            '"fall" to HundredsIntegerDigits
        HundredsIntegerDigits:
          ! mov ebx, dword ptr [ecx]
          ! mov dword ptr [edi], ebx             '1st and 2nd digits
          ! add ecx, 4&
          ! add edi, 4&
          ! mov  bx, word ptr [ecx]
          ! mov word ptr [edi], bx               '3rd digit
          ! add ecx, 2&
          ! add edi, 2?
          ! add dword ptr [esi], 6&
        ! cmp DigitsOut, 3&
        ! jg DoDecimalPoint
        ! je DoPrefix
        'Error
          ! mov dword ptr [esi], 10&
          ! mov edi, esi
          ! add edi, 4???
          ! mov dword ptr [edi], &h00520045??? 'E R
          ! add edi, 4???
          ! mov dword ptr [edi], &h004F0052??? 'R O
          ! add edi, 4???
          ! mov dword ptr [edi], &h00000052??? 'R nul
          ! jmp FunctionDone
      '· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·  is units · ·
      UnitsInteger:
        ! cmp DP_Align, 0&
        ! je UnitsNoAlignPad
        'UnitsAlignPad
          ! cmp NumIsNeg, 0&
          ! jne UnitsAlignPadNeg
          'UnitsAlignPadPos
            ! mov dword ptr [edi], &h00200020??? 'space space
            ! add edi, 4???
            ! mov word ptr [edi], &h0020??       'space
            ! add edi, 2??
            ! mov dword ptr [esi], 6&
            ! jmp UnitsIntegerDigits
          UnitsAlignPadNeg:
            ! mov dword ptr [edi], &h00200020??? 'space space
            ! add edi, 4???
            ! mov word ptr [edi], &h002D??       'minus
            ! add ecx, 2??
            ! add edi, 2??
            ! mov dword ptr [esi], 6&
            ! jmp UnitsIntegerDigits
        UnitsNoAlignPad:
          ! cmp NumIsNeg, 0&
          ! jne UnitsNoAlignPadNeg
          'UnitsNoAlignPadPos
            ! mov dword ptr [esi], 0&
            ! jmp UnitsIntegerDigits
          UnitsNoAlignPadNeg:
            ! mov word ptr [edi], &h002D??
            ! add ecx, 2??
            ! add edi, 2??
            ! mov dword ptr [esi], 2&
            '"fall" to UnitsIntegerDigits
        UnitsIntegerDigits:
          ! mov bx, word ptr [ecx]              'InChar to register
          ! mov word ptr [edi], bx
          ! add ecx, 2???
          ! add edi, 2???
          ! add dword ptr [esi], 2&
          '"fall" to DoDecimalPoint
      '· · · · · · · · · · · · · · · · · · · · · · · · · ·  append decimal point · ·
      DoDecimalPoint:
        ! mov word ptr [edi], &h002E??  'decimal point
        ! add edi, 2???
        ! add dword ptr [esi], 2&
        '"fall" to FractionDigits
      '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EDX now available ~~~~
      '---------------------------- Fraction digits - continuous or 3 digit groups -
      FractionDigits:
      ! mov ebx, pLastInChar
      ! sub ebx, ecx
      ! add ebx, 2???                            'Remaining Bytes
      '''
      ! cmp No3DigitGrps, 0&
      ! jne FractionGrpsNoTop
        FractionGrpsYesTop:
        ! cmp ebx, 6???
        ! jg FractionGrpsYesGT6
        ! jl FractionGrpsYesLT6
        'FractionGrpsYesET6
          ! mov edx, dword ptr [ecx]       '2 InChars of last 3 char group to EDX
          ! mov dword ptr [edi], edx       'EDX to OutChars
          ! add ecx, 4???                  'adjust ECX point 3rd InChar of group
          ! add edi, 4???                  'adjust EDI point 3rd OutChar of group
          ! mov  dx, word ptr [ecx]        '3rd InChar to DX. Is last, no adjust ECX
          ! mov word ptr [edi], dx         'DX to OutChar
          ! add edi, 2???                  'adjust EDI point space by DoPrefix
          ! add dword ptr [esi], 6&        'adjust LEN OutChars by appended bytes
          ! jmp DoPrefix
        FractionGrpsYesGT6:
          ! mov edx, dword ptr [ecx]       '1st and 2nd InChars to EDX
          ! mov dword ptr [edi], edx       'EDX to OutChars
          ! add ecx, 4???                  'adjust ECX point to 3rd InChar of group
          ! add edi, 4???                  'adjust EDI point to 3rd OutChar of group
          ! mov  dx, word ptr [ecx]        '3rd InChar to DX
          ! mov word ptr [edi], dx         'DX to OutChar
          ! add ecx, 2???                  'adjust ECX point 1st InChar next of group
          ! add edi, 2???                  'adjust EDI point to group separator
          ! mov word ptr [edi], &h0020???  'space
          ! add edi, 2???                  'adjust EDI point 1st OutChar next of group
          ! add dword ptr [esi], 8&        'adjust LEN OutChars by appended bytes
          ! sub ebx, 6???                  'reduce remaining bytes of InChar by 6
          ! jmp FractionGrpsYesTop
        FractionGrpsYesLT6:
          ! cmp ebx, 4???
          ! je FractionGrpsBothET4   'je
          ! jl FractionGrpsBothLT4
      FractionGrpsNoTop:
        ! cmp ebx, 4???
        ! je FractionGrpsBothET4
        ! jl FractionGrpsBothLT4
        'FractionGrpsNoGT4:
          ! mov edx, dword ptr [ecx]
          ! mov dword ptr [edi], edx
          ! add ecx, 4???
          ! add edi, 4???
          ! add dword ptr [esi], 4&
          ! sub ebx, 4???   '6
          ! jmp FractionGrpsNoTop
      'these the same for 3 digit groups and ungrouped
      '--------------------------------------------------------
      FractionGrpsBothET4:
        ! mov edx, dword ptr [ecx]         '2 InChars to EDX
        ! mov dword ptr [edi], edx         'EDX to OutChar. Is last, no adjust ECX
        ! add edi, 4???                    'adjust EDI point space by DoPrefix
        ! add dword ptr [esi], 4&          'adjust LEN OutChars by appended bytes
        ! jmp DoPrefix
      FractionGrpsBothLT4:
        ! mov  dx, word ptr [ecx]
        ! mov word ptr [edi], dx
        ! add edi, 2???
        ! add dword ptr [esi], 2&
        ! jmp DoPrefix
      '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EBX, ECX EDX now available ~~~~
      '------------------------------------------- Use E \ 3 for prefix selection --
      DoPrefix:
        ! cmp eax, 0&
        ! jg PrefixGT0
        ! jl PrefixLt0
        'PrefixET0
          ! mov word ptr [edi], &h0020?? 'space for no prefix unit symbol
          ! add dword ptr [esi], 2&
          ! jmp FunctionDone
        PrefixGT0:
          ! cmp eax, 4&
          ! jg PrefixGT4
          ! jl PrefixLt4
          'PrefixET4
            ! mov dword ptr [edi], &h00540020???        'space T
            ! jmp PrefixLenNumOutStr
          PrefixGT4:
            ! cmp eax, 8&
            ! jg PrefixGT8
            ! jl PrefixLT8
            'PrefixET8
              ! mov dword ptr [edi], &h00590020???      'space Y
              ! jmp PrefixLenNumOutStr
            PrefixGT8:
              ! jmp OutOfRange
            PrefixLt8:
              ! cmp eax, 6&
              ! jg PrefixGT6
              ! jl PrefixLT6
              'PrefixET6
                 ! mov dword ptr [edi], &h00450020???   'space E
                 ! jmp PrefixLenNumOutStr
               PrefixGT6:
                 ! mov dword ptr [edi], &h005A0020???   'space Z
                 ! jmp PrefixLenNumOutStr
               PrefixLT6:
                 ! mov dword ptr [edi], &h00500020???   'space P
                 ! jmp PrefixLenNumOutStr
          PrefixLT4:
            ! cmp eax, 2&
            ! jg PrefixGT2
            ! jl PrefixLT2
            'PrefixET2
              ! mov dword ptr [edi], &h004D0020???      'space M
              ! jmp PrefixLenNumOutStr
            PrefixGT2:
              ! mov dword ptr [edi], &h00470020???      'space G
              ! jmp PrefixLenNumOutStr
            PrefixLT2:
              ! mov dword ptr [edi], &h006B0020???      'space k
              ! jmp PrefixLenNumOutStr
      PrefixLT0:
        ! cmp eax, -4&
        ! jl  PrefixLTm4
        ! jg  PrefixGTm4
        'PrefixETm4
          ! mov dword ptr [edi], &h00700020???          'space p
          ! jmp PrefixLenNumOutStr
        PrefixLTm4:
          ! cmp eax, -8&
          ! jl PrefixLTm8
          ! jg PrefixGTm8
          'PrefixETm8
            ! mov dword ptr [edi], &h00790020???        'space y
            ! jmp PrefixLenNumOutStr
          PrefixLTm8:
            ! jmp OutOfRange
          PrefixGTm8:
            ! cmp eax, -6&
            ! jl PrefixLTm6
            ! jg PrefixGTm6
            'PrefixETm6
              ! mov dword ptr [edi], &h00610020???      'space a
              ! jmp PrefixLenNumOutStr
            PrefixLTm6:
              ! mov dword ptr [edi], &h007A0020???      'space z
              ! jmp PrefixLenNumOutStr
            PrefixGTm6:
              ! mov dword ptr [edi], &h00660020???      'space f
              ! jmp PrefixLenNumOutStr
        PrefixGTm4:
          ! cmp eax, -2&
          ! jl PrefixLTm2
          ! jg PrefixGTm2
          'PrefixETm2
            ! mov dword ptr [edi], &h00B50020???        'space µ
            ! jmp PrefixLenNumOutStr
          PrefixLTm2:
            ! mov dword ptr [edi], &h006E0020???        'space n
            ! jmp PrefixLenNumOutStr
          PrefixGTm2:
            ! mov dword ptr [edi], &h006D0020???        'space m
            '"fall" to PrefixLenNumOutStr
      PrefixLenNumOutStr:
        ! add dword ptr [esi], 4&
      FunctionDone:
      ! pop esi
      ! pop edi
      ! pop edx
      ! pop ecx
      ! pop ebx
      ! pop eax
      function = NumOutStr
      '
      exit function '===============================================================
      '
      OutOfRange:
      ! pop esi  '(if here, never gets to POPs above)
      ! pop edi
      ! pop edx
      ! pop ecx
      ! pop ebx
      ! pop eax
      function = "Out of prefix range."$$
    end function '
    Last edited by Dale Yarker; 20 Nov 2022, 06:49 PM.
    Dale

    Comment


    • #3
      Dale,
      Looks like the "also at" link is incorrect. It should be
      http://www.yarker-dsyc.info/D_Notebo...mat/index.html

      (ADDED: Dale points out that the second post contains the correct link.)
      Last edited by Mark Hunter; 20 Nov 2022, 10:12 PM.
      Algorithms - interesting mathematical techniques with program code included.

      Comment


      • #4
        'SI prefix format updated version.
        '
        'release 20221209, added prefixes Q, R, r and q.
        '
        'This source code also at
        ' http://www.yarker-dsyc.info/D_Notebo...fixFormat.html
        'with explanation and demo code.
        'URLs in previous posts now have redirectors.
        '
        'Now thousands separation applied to fraction part of value with spaces by
        'default per the General Conference on Weights and Measures. This can optionally
        'be disabled. The significand (integer part) does not need thousands separation
        'because it is already limited to 1 to 999 in order to use the prefix.
        '
        'The units, or their abreviations, should be appended directly on the resulting
        'wide string. (Byte oriented strings should only used for DIBs, numeric types
        'and UTF-8 over a network.)
        '
        'Description of optional parameters in INCLUDE file in following code block.
        '
        '
        Code:
        'Copyleft 2022 by Dale Yarker; do what you want with this code except claim it,
        'or sell it, as yours. No warranty of any kind.
        #compile sll "SI_PrefixFormat.sll"
        #dim all
        '
        function SI_PrefixFormat(byval NumToFormat as ext, _
                             opt byval DigitsOut as long, _
                             opt byval DP_Align as long, _
                             opt byval No3DigitGrps as long) common as wstring
          #register none
          local NumInStr, NumOutStr as wstring
          local pNumInChar, pNumOutChar, pLastInChar, pLenNumOutStr as dword
          local NumIsNeg, ExpntIsNeg, RemainBytes as long
          local E as long '1st as exponent of normatized number in, then it
                          'is exponent integer divided by 3.
          local E_Mod3 as long 'Remainder of exponent integer divided by 3.
          '------------------------------------------- Check/Set number of DigitsOut. --
          ! push eax
          ! mov eax, DigitsOut
          ! cmp eax, 0&             'optional parameter not used or set to 0
          ! jne DigitsOutNotDefault 'go check minimum
            ! mov DigitsOut, 6&     'set default
            ! jmp DigitsOutDone
          DigitsOutNotDefault:
          ! cmp eax, 3&             'non-valid 1, 2 or negative
          ! jge DigitsOutNotLTMin   'go check maximum
          ! mov DigitsOut, 3&       'set minimum
          ! jmp DigitsOutDone
          DigitsOutNotLTMin:
          ! cmp eax, 18&            'non-valid greater than 18
          ! jle DigitsOutDone       'not above max
          ! mov DigitsOut, 18&      'set maximum
          DigitsOutDone:
          ! pop eax
          '------------------- Binary to string; get last digit, current digit and E. --
          'extended float input to string of integer plus exponent
          NumInStr = format$(NumToFormat, string$(DigitsOut, "#") + "e-##")
          '
          'Exponent of input as integer
          E = val(NumInStr, instr(-1, NumInStr, "e") + 1)
          '
          pNumInChar = strptr(NumInStr)
          NumOutStr = string$(30, $$nul)
          pNumOutChar = strptr(NumOutStr)
         ' ?
          '  ? E, NumInStr
          '  exit function
          '
          ! push eax
          ! push ebx
          ! push ecx
          ! push edx
          ! push edi
          ! push esi
          '------ Set variabes, leave in register if possible, or Format zero result. --
          'calculate pointer to last digit of input string
          ! mov ebx, DigitsOut
          ! sal ebx, 1???
          ! mov ecx, pNumInChar
          ! add ebx, ecx
          ! mov pLastInChar, ebx
        
         ' ! sal pLastInChar, 1& 'number characters times 2 for number of bytes
        
          ! sub pLastInChar, 2&
          'result character pointer to register and calculate pointer to
          'pointer to byte length of result string
          ! mov edi, pNumOutChar
          ! mov esi, edi
          ! sub esi, 4& 'is pLenNumOutStr
          'Check for negative
          ! cmp word ptr [ecx], &h002d??   '"-"
          ! je Sgnfcnd_Is_Neg              'can't be 0 if negative
            'Check "1" or greater than
            ! cmp word ptr [ecx], &h0031?? '"1"
            ! jae Sgnfcnd_NotZero
              'CHeck DP_Align
              ! cmp DP_Align, 0&
              ! jne SgnfcndIsZeroIsDPAlgn
              'SgnfcndIsZeroNotDPAlign
                ! mov dword ptr [edi], &h002E0030??? 'zero dp
                ! add edi, 4???
                ! mov  word ptr [edi], &h0030??      'zero
                ! mov dword ptr [esi], &h00000006??? '6 to pLenNumOutStr
              ! jmp FunctionDone
              SgnfcndIsZeroIsDPAlgn:
                ! mov dword ptr [edi], &h00200020??? 'space space
                ! add edi, 4???
                ! mov dword ptr [edi], &h00300020??? 'space zero
                ! add edi, 4???
                ! mov dword ptr [edi], &h0030002E??? 'dp zero
                ! mov dword ptr [esi], &h00000012??? '12 to pLenNumOutStr
              ! jmp FunctionDone
          Sgnfcnd_Is_Neg:
            ! mov NumIsNeg, -1&
          Sgnfcnd_NotZero: 'non-zero to here, positive skips past Sgnfcnd_Is_Neg
          '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ only EBX available ~~~~
          '-------------- Calc E \ 3 and E MOD 3, both modified for negative E MOD 3. --
          ! mov eax, E
          ! add eax, DigitsOut
          ! sub eax, 1&
          ! bt  eax, 31??? 'bit 31 can only be set if LONG is negative
          ! jnc E_IsPositive1
          ! mov ExpntIsNeg, -1&
          ! mov edx, -1& 'make edx upper part of 64 bit 2s compliment to eax's lower
          ! sub eax, 2&  '
          ! jmp DoDivide
          E_IsPositive1:
          ! xor edx, edx 'edx to 0
          DoDivide:
          ! mov ebx, 3& 'divisor
          ! idiv ebx
          ! cmp ExpntIsNeg, 0&
          ! je E_IsPositive2
          ! add edx, 2&
          E_IsPositive2:
          '-------------------- Use E MOD 3 for dp align, and to place decimal point. --
          '. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . is tens . .
          ! cmp edx, 1&
          ! jg HundredsInteger
          ! jl UnitsInteger
            'Tens Padding and minus sign
            ! cmp DP_Align, 0&
            ! je TensNoAlignPad
              'Tens Align Pad
              ! cmp NumIsNeg, 0&
              ! jne TensAlignNegPad
              'TensAlignPosPad
                ! mov dword ptr [edi], &h00200020??? 'space space
                ! add edi, 4&                        'OutChar ptr adjust
                ! mov dword ptr [esi], 4&             'Out Len set
                ! jmp TensIntegerDigits
              TensAlignNegPad:
                ! mov dword ptr [edi], &h002D0020??? 'space minus
                ! add ecx, 2&                        'InChar ptr adjust
                ! add edi, 4&                        'OutChar ptr adjust
                ! mov dword ptr [esi], 4&             'Out Len set
                ! jmp TensIntegerDigits
            TensNoAlignPad:
              ! cmp NumIsNeg, 0&
              ! jne TensNoAlignPadNeg
              'TensNoAlignPosPad
                ! mov dword ptr [esi], 0&             'Out Len set
                ! jmp TensIntegerDigits
              TensNoAlignPadNeg:
                ! mov word ptr [edi], &h002D??       'minus
                ! add ecx, 2&                        'InChar ptr adjust
                ! add edi, 2&                        'OutChar ptr adjust
                ! mov dword ptr [esi], 2&             'Out Len set
            TensIntegerDigits:
              ! mov ebx, dword ptr [ecx]             '2 digits InChar to register
              ! mov dword ptr [edi], ebx             '2 digits register to OutChar
              ! add ecx, 4&                          'InChar ptr adjust
              ! add edi, 4&                          'OutChar ptr adjust
              ! add dword ptr [esi], 4&               'Out Len adjust
              ! jmp DoDecimalPoint
          '· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · is hundreds · ·
          HundredsInteger:
            'Hundreds Padding and minus sign
            ! cmp DP_Align, 0&
            ! je HundredsNoAlignPad
              'Hundreds Align Pad
              ! cmp NumIsNeg, 0&
              ! jne HundredsAlignPadNeg
              'HundredsAlignPadPos
                ! mov word ptr [edi], &h0020??       'space
                ! add edi, 2???
                ! mov dword ptr [esi], 2&
                ! jmp HundredsIntegerDigits
              HundredsAlignPadNeg:
                ! mov word ptr [edi], &h002D??       'minus
                ! add ecx, 2???
                ! add edi, 2???
                ! mov dword ptr [esi], 2&
                ! jmp HundredsIntegerDigits
            HundredsNoAlignPad:
              ! cmp NumIsNeg, 0&
              ! jne HundredsNoAlignPadNeg
              'HundredsnoAlignPadPos
                ! mov dword ptr [esi], 0&             'set length of OutStr to 0
                ! jmp HundredsIntegerDigits
              HundredsNoAlignPadNeg:
                ! mov word ptr [edi], &h002D??       'minus
                ! add ecx, 2???
                ! add edi, 2???
                ! mov dword ptr [esi], 2&
                '"fall" to HundredsIntegerDigits
            HundredsIntegerDigits:
              ! mov ebx, dword ptr [ecx]
              ! mov dword ptr [edi], ebx             '1st and 2nd digits
              ! add ecx, 4&
              ! add edi, 4&
              ! mov  bx, word ptr [ecx]
              ! mov word ptr [edi], bx               '3rd digit
              ! add ecx, 2&
              ! add edi, 2?
              ! add dword ptr [esi], 6&
            ! cmp DigitsOut, 3&
            ! jg DoDecimalPoint
            ! je DoPrefix
            'Error
              ! mov dword ptr [esi], 10&
              ! mov edi, esi
              ! add edi, 4???
              ! mov dword ptr [edi], &h00520045??? 'E R
              ! add edi, 4???
              ! mov dword ptr [edi], &h004F0052??? 'R O
              ! add edi, 4???
              ! mov dword ptr [edi], &h00000052??? 'R nul
              ! jmp FunctionDone
          '· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·  is units · ·
          UnitsInteger:
            ! cmp DP_Align, 0&
            ! je UnitsNoAlignPad
            'UnitsAlignPad
              ! cmp NumIsNeg, 0&
              ! jne UnitsAlignPadNeg
              'UnitsAlignPadPos
                ! mov dword ptr [edi], &h00200020??? 'space space
                ! add edi, 4???
                ! mov word ptr [edi], &h0020??       'space
                ! add edi, 2??
                ! mov dword ptr [esi], 6&
                ! jmp UnitsIntegerDigits
              UnitsAlignPadNeg:
                ! mov dword ptr [edi], &h00200020??? 'space space
                ! add edi, 4???
                ! mov word ptr [edi], &h002D??       'minus
                ! add ecx, 2??
                ! add edi, 2??
                ! mov dword ptr [esi], 6&
                ! jmp UnitsIntegerDigits
            UnitsNoAlignPad:
              ! cmp NumIsNeg, 0&
              ! jne UnitsNoAlignPadNeg
              'UnitsNoAlignPadPos
                ! mov dword ptr [esi], 0&
                ! jmp UnitsIntegerDigits
              UnitsNoAlignPadNeg:
                ! mov word ptr [edi], &h002D??
                ! add ecx, 2??
                ! add edi, 2??
                ! mov dword ptr [esi], 2&
                '"fall" to UnitsIntegerDigits
            UnitsIntegerDigits:
              ! mov bx, word ptr [ecx]              'InChar to register
              ! mov word ptr [edi], bx
              ! add ecx, 2???
              ! add edi, 2???
              ! add dword ptr [esi], 2&
              '"fall" to DoDecimalPoint
          '· · · · · · · · · · · · · · · · · · · · · · · · · ·  append decimal point · ·
          DoDecimalPoint:
            ! mov word ptr [edi], &h002E??  'decimal point
            ! add edi, 2???
            ! add dword ptr [esi], 2&
            '"fall" to FractionDigits
          '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EDX now available ~~~~
          '---------------------------- Fraction digits - continuous or 3 digit groups -
          FractionDigits:
          ! mov ebx, pLastInChar
          ! sub ebx, ecx
          ! add ebx, 2???                            'Remaining Bytes
          '''
          ! cmp No3DigitGrps, 0&
          ! jne FractionGrpsNoTop
            FractionGrpsYesTop:
            ! cmp ebx, 6???
            ! jg FractionGrpsYesGT6
            ! jl FractionGrpsYesLT6
            'FractionGrpsYesET6
              ! mov edx, dword ptr [ecx]       '2 InChars of last 3 char group to EDX
              ! mov dword ptr [edi], edx       'EDX to OutChars
              ! add ecx, 4???                  'adjust ECX point 3rd InChar of group
              ! add edi, 4???                  'adjust EDI point 3rd OutChar of group
              ! mov  dx, word ptr [ecx]        '3rd InChar to DX. Is last, no adjust ECX
              ! mov word ptr [edi], dx         'DX to OutChar
              ! add edi, 2???                  'adjust EDI point space by DoPrefix
              ! add dword ptr [esi], 6&        'adjust LEN OutChars by appended bytes
              ! jmp DoPrefix
            FractionGrpsYesGT6:
              ! mov edx, dword ptr [ecx]       '1st and 2nd InChars to EDX
              ! mov dword ptr [edi], edx       'EDX to OutChars
              ! add ecx, 4???                  'adjust ECX point to 3rd InChar of group
              ! add edi, 4???                  'adjust EDI point to 3rd OutChar of group
              ! mov  dx, word ptr [ecx]        '3rd InChar to DX
              ! mov word ptr [edi], dx         'DX to OutChar
              ! add ecx, 2???                  'adjust ECX point 1st InChar next of group
              ! add edi, 2???                  'adjust EDI point to group separator
              ! mov word ptr [edi], &h0020???  'space
              ! add edi, 2???                  'adjust EDI point 1st OutChar next of group
              ! add dword ptr [esi], 8&        'adjust LEN OutChars by appended bytes
              ! sub ebx, 6???                  'reduce remaining bytes of InChar by 6
              ! jmp FractionGrpsYesTop
            FractionGrpsYesLT6:
              ! cmp ebx, 4???
              ! je FractionGrpsBothET4   'je
              ! jl FractionGrpsBothLT4
          FractionGrpsNoTop:
            ! cmp ebx, 4???
            ! je FractionGrpsBothET4
            ! jl FractionGrpsBothLT4
            'FractionGrpsNoGT4:
              ! mov edx, dword ptr [ecx]
              ! mov dword ptr [edi], edx
              ! add ecx, 4???
              ! add edi, 4???
              ! add dword ptr [esi], 4&
              ! sub ebx, 4???   '6
              ! jmp FractionGrpsNoTop
          'these the same for 3 digit groups and ungrouped
          '--------------------------------------------------------
          FractionGrpsBothET4:
            ! mov edx, dword ptr [ecx]         '2 InChars to EDX
            ! mov dword ptr [edi], edx         'EDX to OutChar. Is last, no adjust ECX
            ! add edi, 4???                    'adjust EDI point space by DoPrefix
            ! add dword ptr [esi], 4&          'adjust LEN OutChars by appended bytes
            ! jmp DoPrefix
          FractionGrpsBothLT4:
            ! mov  dx, word ptr [ecx]
            ! mov word ptr [edi], dx
            ! add edi, 2???
            ! add dword ptr [esi], 2&
            ! jmp DoPrefix
          '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EBX, ECX EDX now available ~~~~
          '------------------------------------------- Use E \ 3 for prefix selection --
          DoPrefix:
            ! cmp eax, 0&
            ! jg PrefixGT0
            ! jl PrefixLt0
            'PrefixET0
              ! mov word ptr [edi], &h0020?? 'space for no prefix unit symbol
              ! add dword ptr [esi], 2&
              ! jmp FunctionDone
            PrefixGT0:
              ! cmp eax, 4&
              ! jg PrefixGT4
              ! jl PrefixLt4
              'PrefixET4
                ! mov dword ptr [edi], &h00540020???        'space T
                ! jmp PrefixLenNumOutStr
              PrefixGT4:
                ! cmp eax, 8&
                ! jg PrefixGT8
                ! jl PrefixLT8
                'PrefixET8
                  ! mov dword ptr [edi], &h00590020???      'space Y
                  ! jmp PrefixLenNumOutStr
                PrefixGT8:
                  ! cmp eax, 10&
                  ! jg PrefixGT10
                  ! jl PrefixLT10
                  'PrefixET10:
                    ! mov dword ptr [edi], &h00510020???     'space Q
                    ! jmp PrefixLenNumOutStr
                  PrefixGT10:
                    ! jmp OutOfRange
                  PrefixLT10:
                    ! mov dword ptr [edi], &h00520020???      'space R
                    ! jmp PrefixLenNumOutStr
                PrefixLt8:
                  ! cmp eax, 6&
                  ! jg PrefixGT6
                  ! jl PrefixLT6
                  'PrefixET6
                    ! mov dword ptr [edi], &h00450020???   'space E
                    ! jmp PrefixLenNumOutStr
                   PrefixGT6:
                     ! mov dword ptr [edi], &h005A0020???   'space Z
                     ! jmp PrefixLenNumOutStr
                   PrefixLT6:
                     ! mov dword ptr [edi], &h00500020???   'space P
                     ! jmp PrefixLenNumOutStr
              PrefixLT4:
                ! cmp eax, 2&
                ! jg PrefixGT2
                ! jl PrefixLT2
                'PrefixET2
                  ! mov dword ptr [edi], &h004D0020???      'space M
                  ! jmp PrefixLenNumOutStr
                PrefixGT2:
                  ! mov dword ptr [edi], &h00470020???      'space G
                  ! jmp PrefixLenNumOutStr
                PrefixLT2:
                  ! mov dword ptr [edi], &h006B0020???      'space k
                  ! jmp PrefixLenNumOutStr
          PrefixLT0:
            ! cmp eax, -4&
            ! jl  PrefixLTm4
            ! jg  PrefixGTm4
            'PrefixETm4
              ! mov dword ptr [edi], &h00700020???          'space p
              ! jmp PrefixLenNumOutStr
            PrefixLTm4:
              ! cmp eax, -8&
              ! jl PrefixLTm8
              ! jg PrefixGTm8
              'PrefixETm8
                ! mov dword ptr [edi], &h00790020???        'space y
                ! jmp PrefixLenNumOutStr
              PrefixLTm8:
                ! cmp eax, -10&                                       '
                ! jl PrefixLTm10
                ! jg PrefixGTm10
                'PrefixETm10
                   ! mov dword ptr [edi], &h00710020???     'space q
                   ! jmp PrefixLenNumOutStr
                 PrefixLTm10:
                   ! jmp OutOfRange
                 PrefixGTm10:
                   ! mov dword ptr [edi], &h00720020???     'space r
                   ! jmp PrefixLenNumOutStr
              PrefixGTm8:
                ! cmp eax, -6&
                ! jl PrefixLTm6
                ! jg PrefixGTm6
                'PrefixETm6
                  ! mov dword ptr [edi], &h00610020???      'space a
                  ! jmp PrefixLenNumOutStr
                PrefixLTm6:
                  ! mov dword ptr [edi], &h007A0020???      'space z
                  ! jmp PrefixLenNumOutStr
                PrefixGTm6:
                  ! mov dword ptr [edi], &h00660020???      'space f
                  ! jmp PrefixLenNumOutStr
            PrefixGTm4:
              ! cmp eax, -2&
              ! jl PrefixLTm2
              ! jg PrefixGTm2
              'PrefixETm2
                ! mov dword ptr [edi], &h00B50020???        'space µ
                ! jmp PrefixLenNumOutStr
              PrefixLTm2:
                ! mov dword ptr [edi], &h006E0020???        'space n
                ! jmp PrefixLenNumOutStr
              PrefixGTm2:
                ! mov dword ptr [edi], &h006D0020???        'space m
                '"fall" to PrefixLenNumOutStr
          PrefixLenNumOutStr:
            ! add dword ptr [esi], 4&
          FunctionDone:
          ! pop esi
          ! pop edi
          ! pop edx
          ! pop ecx
          ! pop ebx
          ! pop eax
          function = NumOutStr
          '
          exit function '===============================================================
          '
          OutOfRange:
          ! pop esi  '(if here, never gets to POPs above)
          ! pop edi
          ! pop edx
          ! pop ecx
          ! pop ebx
          ! pop eax
          function = "Out of prefix range."$$
        end function '
        Dale

        Comment

        Working...
        X