Announcement

Collapse
No announcement yet.

convert algo

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

  • convert algo

    I'm trying to get from, for example:

    &h12345678

    to turn into...

    &h38373635 and &h34333231

    and the below code works, but doesn't seem very... inspired :coffee4:
    Code:
           !lea eax, q2
           !mov ebx, [eax]     ;&h12345678 for example does this:
           !movzx edx, bh      ;&h00000056
           !movzx ecx, bl      ;&h00000078
           !shl edx, 4         ;&h00000560
           !shl ecx, 4         ;&h00000780
           !shr  dl, 4         ;&h00000506
           !shr  cl, 4         ;&h00000708
           !shl edx, 16        ;&h05060000
           !or  edx, ecx       ;&h05060708
    
           !shr ebx, 16        ;&h00001234
           !bswap edx          ;&h08070605
    
           !movzx eax, bh      ;&h00000012
           !movzx ecx, bl      ;&h00000034
           !shl eax, 4         ;&h00000120
           !shl ecx, 4         ;&h00000340
           !shr  al, 4         ;&h00000102
           !shr  cl, 4         ;&h00000304
           !shl eax, 16        ;&h01020000
           !or  eax, ecx       ;&h01020304
    
           !add edx,&h30303030 ;&h38373635
           !bswap eax          ;&h04030201
           !add eax,&h30303030 ;&h34333231

  • #2
    John,

    Enlighten me. What is the significance of the 2nd/3rd numbers?

    &h12345678
    to turn into...
    &h38373635 and &h34333231
    Do you looking for any two numbers that can be AND'd into the first number? Tell me more about what you're trying to do.

    Comment


    • #3
      If you are looking for two numbers to boolean AND into a target number, there is no unique solution.

      eg
      2 AND 2 = 2
      2 AND 4 = 2
      2 AND 6 = 2

      You will run into the same thing with OR... no unique solution.

      MCM
      Michael Mattias
      Tal Systems Inc. (retired)
      Racine WI USA
      [email protected]
      http://www.talsystems.com

      Comment


      • #4
        The &h12345678 (four bytes) I'm trying to turn into a string "12345678" which is 8 bytes. But it needs to be reversed as "8765" and "4321" so that they can be placed as two regular LONG's.

        Comment


        • #5
          The &h12345678 (four bytes) I'm trying to turn into a string "12345678" which is 8 bytes. But it needs to be reversed as "8765" and "4321" so that they can be placed as two regular LONG's.
          Huh?

          Eight byte string :
          Z$ = HEX$(VAL ("&h12345678"), 8)

          Move this data to longs: use VAL again. I don't understand why you need TWO longs to hold this number, it all fits in one.

          ZL& = VAL ("&h12345678")

          If you want the high and low words, see the HI() and LO() functions and call against ZL&.

          MCM

          [later]
          Oops, I see this is the assembly-language forum. Well, maybe you THOUGHT you needed assembly language... or maybe you want to learn assembly language. I can only hope what you really wanted was what you said you wanted.
          Last edited by Michael Mattias; 7 Sep 2009, 11:33 AM.
          Michael Mattias
          Tal Systems Inc. (retired)
          Racine WI USA
          [email protected]
          http://www.talsystems.com

          Comment


          • #6
            I can only hope what you really wanted was what you said you wanted.
            Tell me more about what you're trying to do.
            I read my "clarification" attempt above, and and it is indeed very unclear. :laugh:

            Yes, the above code does do what I want it to do, but it seems like there's a faster way. It's in asm for speed because it's the innermost loop and is being called millions of times. I'm basically just trying to speed up the "number to string" conversion.

            Here is an analogy. Let's say x& = 12345678

            If you want to turn x& into s$ = "12345678", there are lots of ways to do that.

            The twist on the above in my situation, however, is that I start with x& = &h12345678 and I want to very quickly turn it into s$ = "12345678". That's what the asm above is trying to accomplish.

            Comment


            • #7
              John,
              if you want speed then use a lookup table. Make the table entries 2 characters each and the index to the table is then a byte value.
              Your task then becomes looking up four 1 byte values in the table which each return 2 characters.

              Paul.

              Comment


              • #8
                lookup table
                Yes, that's the answer I think. The trusty lookup table.

                Comment


                • #9
                  Here's a couple of hex lookup table demos.... neither is exactly what you want for this application but it should get you started....

                  Byte to HEX character pair and vice-versa conversions

                  MCM

                  PS When you get it working, it might be nice to post the "Hex literal to decimal literal" function you end up with.....
                  Michael Mattias
                  Tal Systems Inc. (retired)
                  Racine WI USA
                  [email protected]
                  http://www.talsystems.com

                  Comment


                  • #10
                    John,
                    here's an alternative using SSE2. I'm not sure if it'll turn out faster than using lookup tables.

                    Paul.
                    Code:
                    'PBCC5.01 program
                    FUNCTION PBMAIN () AS LONG
                    LOCAL Answer AS QUAD
                    
                    n&=&h12345678           'the initial number
                    
                    m&&=&h0f0f0f0f0f0f0f0f  'a mask
                    a&&=&h3030303030303030  'the ascii offset to add
                    
                    !mov eax,n&         'get the number
                    !bswap eax          'swap the byte order
                    !movd xmm0,eax      'move to xmm register
                    !pxor xmm1,xmm1     'clear xmm1
                    !movq xmm2,m&&      'get the mask
                    !movq xmm3,a&&      'get the ascii offset
                    
                    !punpcklbw xmm0,xmm1 'unpack to spread out the bytes
                    !movq xmm1,xmm0      'make a copy
                    !psllw xmm1,8        'shift high nibbles into position
                    !psrlw xmm0,4        'shift low nibbles into position
                    !por xmm0,xmm1       'merge high and low nibbles
                    !pand xmm0,xmm2      'mask off the unused garbage between used nibbles
                    !por xmm0,xmm3       'add in the ascii offset to all characters
                    
                    !movq Answer,xmm0   'store the result
                    
                    PRINT HEX$(HI(LONG,Answer))
                    PRINT HEX$(LO(LONG,Answer))
                    
                    WAITKEY$
                    
                    END FUNCTION

                    Comment


                    • #11
                      post the "Hex literal to decimal literal" function
                      Happy to. (assuming it's decent and not too much slower than Paul's sse2 code. )

                      Sadly, I can't test your code Paul, due to my creaky old steam powered cpu. (Those were a bit before the newfangled "electricul" jobs) But I will certainly hang on to that code for the future.

                      Comment


                      • #12
                        John,
                        my main computer doesn't run it either (5 year old, Athlon XP) but I have an Asus eeePC which does.

                        Paul.

                        Comment


                        • #13
                          It's in asm for speed because it's the innermost loop and is being called millions of times. I'm basically just trying to speed up the "number to string" conversion.
                          Are you sure you have to convert to string millions of times in an innermost loop?

                          There may be a better algorithm to get there from here.

                          Code not shown.

                          MCM
                          Michael Mattias
                          Tal Systems Inc. (retired)
                          Racine WI USA
                          [email protected]
                          http://www.talsystems.com

                          Comment


                          • #14
                            Are you sure you have to convert to string millions of times in an innermost loop?
                            This time I am sure there is no way around it, because the digits have to be expanded from their 4-bit "compressed" state--eg. &h12345678 is 8 digits taking up just 4 bytes--to their uncompressed 1-digit-per-byte, eg. "12345678".

                            Now, two years ago I did an algo where had you asked that exact question, it would have saved me HUGE running time, like at least a factor of 10, maybe 100. I haven't forgotten that lesson (yet) but I sure wish I'd have heard your question two years and one day ago. That algo was a pain in the ascii.

                            Comment


                            • #15
                              This time I am sure there is no way around it, because the digits have to be expanded from their 4-bit "compressed" state--eg. &h12345678 is 8 digits taking up just 4 bytes--to their uncompressed 1-digit-per-byte, eg. "12345678".
                              What is that, BCD data?

                              You don't have to convert that to a string one digit per character ("&h12345678") to get its value.

                              I think I have some code here to read BCD, let me look real quick... well, I do but it's not gonna help a whole lot without the rest of the data descriptions, but it will give you an idea of how it can be done without 'stringing' everything.


                              Code:
                              UNION DataUnion
                               I AS INTEGER
                               Q AS QUAD
                               S AS SINGLE
                               D AS DOUBLE
                               W AS WORD
                               DW AS DWORD
                               L AS LONG
                               A AS STRING * 32
                               BA (1 TO 16) AS BYTE
                              END UNION
                              
                              FUNCTION BCDIntegerValue (P AS C2IEEEType) AS LONG
                              ' input: P
                               ' Output: Mantissa, Exponent
                               ' Returns: 0 = OK, else error
                               ' compute the value of a BCD integer
                              
                               REGISTER Nibble AS LONG
                               REGISTER J AS LONG
                               DIM TheByte AS BYTE
                               DIM NibbleCount AS LONG
                               DIM DestSize AS LONG
                               DIM B1 AS BYTE PTR
                               DIM U AS DataUnion
                               DIM Minus AS LONG
                               DIM Scale AS QUAD       ' was long
                               LOCAL holdQuad AS QUAD
                              
                               ' hmm, output size may be a concern. We can handle up to 9 digits in a long
                               ' For each byte, right (LSD) to left (MSD), except sign
                               ' if # digits is even, the most significant half-byte must be ignored
                              
                               ' Check sign. Valid sign nibbles for BCD:
                               ' x'0F' = unsigned, x'0C'= positive, x'0D' = negative. Unsigned assumed positive
                              
                               'MSGBOX "Entered BCDIntegerValue"
                              
                              #IF 0
                               LOCAL hexchar as string, hexin AS STRING, xx AS LONG
                               hexin = ""
                               FOR XX = 1 TO p.datainfo.datasize
                                    hexchar = HEX$(ASC(p.convertinfo.bufferin, XX),2)
                                    hexin   = hexin & hexchar
                               NEXT
                               MSGBOX "Hex string in= x'" & hexin & "'"
                               ' 12/04/02 in = '011662500001C' ==> 4288317601  BAD BUG!
                              #ENDIF
                              
                               B1 = VARPTR (P.ConvertInfo.BufferIn)        ' point to start of buffer
                               B1 = B1 + P.DataInfo.DataSize - 1           ' last valid data byte
                              
                               Nibble = @B1 AND &h0F
                              
                              ' MSGBOX "Found Sign Nibble =" & HEX$(Nibble)
                              
                               IF Nibble = &h0D THEN
                                   Minus = %TRUE
                               ELSEIF Nibble = &h0C OR Nibble = &h0F THEN
                                   Minus = %FALSE
                               ELSE
                                   FUNCTION = %C2I_Bad_BCD_Sign
                                   EXIT FUNCTION
                               END IF
                              
                               ' accumulate values in U.Q, the quad integer
                              
                               U.Q = 0
                              
                               NibbleCount = 2 * P.DataInfo.DataSize + 1     ' includes sign 12/04/02 why +1?
                               Scale = 1
                               FOR J = 2 TO NibbleCount                     ' start with nibble left of sign
                                   TheByte = @B1
                                   IF ISTRUE(J MOD 2 = 1) THEN                  ' odd (right hand) nibbble
                                      Nibble = TheByte MOD &h10
                                   ELSE
                                      Nibble = TheByte \ &h10
                                      DECR B1                                ' done with this byte, move back in buffer
                                   END IF
                              
                              '    MSGBOX "FOUND Nibble #" & STR$(J)& "=" & STR$(Nibble)
                              ' OK with msgbox in after each niblle and scale as quad.
                              ' left scale as quad and took out msgbox.. OK.
                              ' problem was not using Scale as a QUAD.
                              
                                   IF Nibble > &h09 THEN
                                      FUNCTION = %C2I_Non_Numeric_BCD
                                      EXIT FUNCTION
                                   ELSE
                                      U.Q = U.Q + (CQUD(Scale) * Nibble)
                                      Scale = Scale * 10
                                   END IF
                               NEXT J
                              
                               ' OK, U.Q holds our (absolute) value
                              
                              
                               IF Minus THEN
                                   U.Q = U.Q * %pbvMinusOne
                               END IF
                              
                               HoldQuad = U.Q    ' hold the value... which includes all significant digits
                                                 ' but does not include any implied decimal
                              
                              ' MSGBOX "HoldQuad=" & STR$(HoldQuad) ' DEFINITELY WRONG 12/4
                                ' 7 chars x'01 11 66 25 00 00 1C' ==> 44288317601 SEE ABOVE FOUND PROBLEM
                              
                               P.ConvertInfo.Exponent = P.DataInfo.Decimals * %pbvMinusOne
                               DecimalNormalise P,U       ' updates exponent in P,
                               P.ConvertInfo.Mantissa = CLNG(U.Q)
                               ' 12/04/02 change DMantissa from str$ (Mantissa) which is rounded/truncated
                               ' to use the quad value in U.Q. Problem is in decimal normalise I modify U.Q
                               '
                               ' what I need to do here is STR (quadvalue), then divide by number of decimals
                               ' I have available in P.datainfo.decimals...
                              
                              ' new code for display mantissa
                               p.ConvertInfo.dMantissa = LTRIM$(STR$(HoldQuad))     ' all significant digits
                               IF P.datainfo.decimals THEN
                                 p.ConvertInfo.dExponent = LTRIM$(STR$(P.DataInfo.Decimals * %pbvMinusOne))
                               ELSE
                                 p.ConvertInfo.dExponent = "0"
                               END IF
                               ' OLD CODE BELOW.. truncates/rounds  mantissa when it goes through DecimalNormalise
                              ' P.ConvertInfo.Dmantissa = LTRIM$(STR$(P.ConvertInfo.Mantissa))
                              ' P.ConvertInfo.DExponent = LTRIM$(STR$(P.ConvertInfo.Exponent))
                              
                               FUNCTION = 0
                              
                              END FUNCTION
                              Also, obvously with the BIT datatypes available in PB/Windows you would not have to twink around like I did here with PB/DOS.

                              Let me see if I have this right:

                              Input = 4 byte string, containing BCD data? , with most signficant digits at lowest address ("on the left")?

                              Output = Value of BCD data as Decimal character string?
                              To do: many many?

                              Any decimals or is all BCD data integer?
                              And signed data?

                              Tell me this is COBOL-created data and I'll tell you above code comes from something I created specifically to convert COBOL data to "something usuable in BASIC"

                              MCM
                              Michael Mattias
                              Tal Systems Inc. (retired)
                              Racine WI USA
                              [email protected]
                              http://www.talsystems.com

                              Comment


                              • #16
                                Let me see if I have this right:

                                Input = 4 byte string, containing BCD data? , with most signficant digits at lowest address ("on the left")?

                                Output = Value of BCD data as Decimal character string?
                                To do: many many?

                                Any decimals or is all BCD data integer?
                                And signed data?
                                Correct, no decimals in this case, unsigned, unCOBOL . Mainly the algo's purpose is converting the many many BCD's to readable values as most of the calculations are done beforehand. I'll check out the posted code above too.

                                Comment


                                • #17
                                  Wait a minute, if VAL("&h1234578") returns the correct value, that's not binary-coded decimal....what you have here is a 32-bit integer in Motorola (not Intel) format.

                                  So you just read four byes
                                  Code:
                                  TYPE   FourByte
                                     B (1 to 4) AS BYTE
                                  END TYPE
                                  
                                  UNION U 
                                    L  AS LONG
                                    B4    AS FourBYte
                                  END UNION
                                  
                                      LOCAL U4 AS U   ....
                                      Get hFile,,U4.L   <<< or any other way it's handy to get four bytes
                                   ... and move the bytes into Intel format 
                                       SWAP U4.B4.B(1), U4.B4.B(4) 
                                       SWAP U4.B4.B(3). U4.B4.B(2) 
                                  
                                      MyLongValue&  =  U4.L
                                  I think someone has in the source code forum a "enhanced STR$() or FORMAT$()" which works only with LONG integers... but that's what you have.

                                  MCM
                                  PS: SWAP is known to be "not so fast," but I know people have posted some pointer-based SWAP replacents suitable for byte-exchanges like this.
                                  Michael Mattias
                                  Tal Systems Inc. (retired)
                                  Racine WI USA
                                  [email protected]
                                  http://www.talsystems.com

                                  Comment

                                  Working...
                                  X