Announcement

Collapse
No announcement yet.

Add/subtract 2 quad integers as if they were unsigned?

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

  • Add/subtract 2 quad integers as if they were unsigned?

    Using inline assembler is it possible to write a function to add or subtract 2 quad integers as if they were unsigned?

    The function should receive 2 PB quad integer as parameters and return the result as quad integer.
    Something like:

    Code:
    function addquad(byval a as quad, byval b as quad) as quad
       local result as quad
       ! some inline assembler to add a + b giving result
       function=result
    end function
    Same to subtract 2 numbers.
    If simpler, it's ok even to use a sub, pass the first parameter byref and receive the result in it.

    Addition and subtraction should be done ignoring that quad in PB are signed, so the bit 63 is used to represents negative numbers.

    Thank you!

  • #2
    Claudio,

    Its probably not worth the effort, the x87 maths in PowerBASIC is very efficient. You could try and use 80 bit x87 instructions or 64 bit SSE2 Scalar double but I doubt you would improve on the existing capacity.
    hutch at movsd dot com
    The MASM Forum - SLL Modules and PB Libraries

    http://www.masm32.com/board/index.php?board=69.0

    Comment


    • #3
      Thank you Steve, but I don't understand your answer (due to my lack of knowledge on the subject).

      I'm translating to PB a short C++ program which uses addition, subtraction and left/right shift on uint64 variables (and must use these, because it manipulates numbers beyond the signed int 64 limit), so it would be nice to have a PB function to do the same operations on PB signed quads (shift is already ok).

      It is not a question of performance, but a way to simplify the translation.

      Comment


      • #4
        After your answer I found this on our forum:
        https://forum.powerbasic.com/forum/u...int-using-sse2
        Not sure it's useful, because it works with double, but I'll read it.

        Comment


        • #5
          Claudio,

          If you can use floating point DOUBLE values, the scalar double instructions are easy enough to use and fast enough. In 32 bit, the SD instruction, cvtsd2si works fine with a 32 bit DWORD but it won't work with a 32 bit quad.
          hutch at movsd dot com
          The MASM Forum - SLL Modules and PB Libraries

          http://www.masm32.com/board/index.php?board=69.0

          Comment


          • #6
            Thanks, I'll try.

            Comment


            • #7
              Tried this, but it doesn't work (code for PBCC).

              Code:
              function PBMain() as long
                 dim a as quad
                 dim b as quad
                 a=&hfe169b4c0a73d852
                 b=&h1
                 print bin$(a,64)
                 print bin$(b,64)
                 print bin$(addquad(a,b),64)
              end function
              
              function addquad(byval a as quad,byval b as quad) as quad
                 local x as double
                 local y as double
                 local z as double
                 local q as quad
                 x=a
                 y=b
                 ! movsd xmm0,x
                 ! addsd xmm0,y
                 ! movsd z,xmm0
                 q=z '?
                 function=q
              end function
              It's ok if a and b are small values, but when a has a BIG value (with bit 63 on), as in the example, it lost precision.
              I think the problem is in q=z.

              Comment


              • #8
                Yes, in assembly two 64 bit variables can be added and result stored in a QUAD. But all other PB statements/functions will assume bit 63 being set means 2s compliment negative. If you have a way use a quad as if was unsigned, I'll do example code.

                Cheers,
                Dale

                Comment


                • #9
                  Steve or Dale will have to check my work but this seems to work...
                  Code:
                  #COMPILER PBWIN
                  #COMPILE EXE
                  #DIM ALL
                  
                  '********************************************************************************
                  FUNCTION PBMAIN() AS LONG
                  '********************************************************************************
                    LOCAL lDebug AS LONG: TXT.WINDOW "Debug", 10,10,20,90 TO lDebug 'Thanks Dave!
                  
                    LOCAL qX, qY, qZ AS QUAD
                    LOCAL dHigh, dLow AS DWORD
                  
                    qX = &hfe169b4c0a73d852
                    qY = 1
                  
                    TXT.PRINT BIN$(qX, 64) & "(" & DEC$(qX) & ")"
                    TXT.PRINT BIN$(qY, 64) & "(" & DEC$(qY) & ")"
                  
                    TXT.PRINT BIN$(qX + qY, 64) & "(" & DEC$(qX + qY) & ")"
                    TXT.PRINT
                  
                    dHigh = HI(DWORD, qX)
                    dLow = LO(DWORD, qX)
                  
                    !mov eax,dLow
                    !mov edx,dHigh
                    !mov ecx,0
                    !mov ebx,1
                  
                    !add eax,ebx
                    !adc edx,ecx
                  
                    !mov dHigh,edx
                    !mov dLow,eax
                  
                    qZ = MAK(QUAD, dLow, dHigh)
                    TXT.PRINT BIN$(qZ, 64) & "(" & DEC$(qZ) & ")"
                  
                    TXT.PRINT "Press any key to exit (just like the old days!)": TXT.WAITKEY$: TXT.END
                  END FUNCTION

                  Comment


                  • #10
                    Hi Frank,

                    That looks like the right way to do it, eax - edx pair. I have not touched this stuff for years years as I mainly work in 64 bit but I would check your results against another source, internet perhaps and if you are getting the right results, the algo is usable.

                    I just attached a 64 bit test piece that does a simple add to test Frank's technique against. Bare bones, enter 2 numbers on the command line.

                    Code:
                    ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                    
                        include \masm32\include64\masm64rt.inc
                    
                        .code
                    
                    ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                    
                     entry_point proc
                    
                        USING r12,r13,r14
                        LOCAL pcmd :QWORD
                        LOCAL parr :QWORD
                        LOCAL acnt :QWORD
                        LOCAL pstr :QWORD
                    
                        SaveRegs
                    
                        mov pcmd, rvcall(cmd_tail)
                        mov acnt, rvcall(wtok,pcmd,ptr$(parr),0)
                    
                        mov r12, parr                               ; load the pointer array address
                    
                        conout QWORD PTR [r12]," 1st number",lf
                        mov r13, uval(QWORD PTR [r12])              ; 1st number
                    
                        add r12, 8
                    
                        conout QWORD PTR [r12]," 2nd number",lf
                        mov r14, uval(QWORD PTR [r12])              ; 2nd number
                    
                        add r13, r14                                ; add the two bumbers
                    
                        conout str$(r13)," result",lf,lf            ; display result
                    
                        waitkey
                        RestoreRegs
                        .exit
                    
                     entry_point endp
                    
                    ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                    
                        end
                    Attached Files
                    hutch at movsd dot com
                    The MASM Forum - SLL Modules and PB Libraries

                    http://www.masm32.com/board/index.php?board=69.0

                    Comment


                    • #11
                      Frank,

                      The PRINT . . . DEC$() prints a negative number. Claudio wants unsigned stored in a QUAD, which is signed. The ADD/ADC additions are ok as shown by the BIN$().

                      Cheers,
                      Dale

                      Comment


                      • #12
                        Signed or unsigned... &hfe169b4c0a73d852 + 1 is &hfe169b4c0a73d853. I chose to display with DEC$ which shows a sign. Change DEC$ to HEX$ if you want.

                        Comment


                        • #13
                          Frank's code works and is just what I need; thank you!
                          However, I see that also bin$(qX+qY) give the same result (at bits level), so I wonder if I can simply add 2 quad in PB without worrying about the sign.
                          I have to try both solutions applied to the real program; I'll let you know how it works.
                          Thanks again.

                          Comment


                          • #14
                            Change DEC$ to HEX$ if you want.
                            I don't want or not want. That is why I asked what he was going to do with the result in post 8. DEC$ demonstrates the probable unwanted effect.

                            Claudio seems to like what you gave. So it no longer matters.

                            Cheers,
                            Dale

                            Comment


                            • #15
                              It seems that there is no problem using addition, subtraction and left/right shifting on quad variables as if they were unsigned; at bits level it works.
                              Of course it is not possible to use tests for greater or less than zero because very large numbers can be "negative".

                              However, assembler methods can always be useful.
                              Thank you all.

                              Comment


                              • #16
                                Of course it is not possible to use tests for greater or less than zero because very large numbers can be "negative".
                                ??Less than zero means negative?? Anyway, assembly CMP does not care about signed or unsigned. You pick which conditional jump to used based on signed, unsigned, equal, less than, etc., etc., Compare the high dwords first, if equal then compare the low dwords.

                                By using HI() and LO() to split the QUADs; you can make a BASIC function for greater than and less than.

                                Cheers,
                                Dale

                                Comment


                                • #17
                                  Claudio,

                                  Some questions, was the C++ code you ported 32 or 64 bit ? Also, in the app, can you use floating point instead of integer ? Floating point has got a lot faster over time, mainly for the games guys and they prefer 32 bit floating point as its faster than 64 bit. Franks's code was the right technology but as 32 bit must use 2 registers, eax - edx pairs, I wondered what you were doing as the task design to require integers.
                                  hutch at movsd dot com
                                  The MASM Forum - SLL Modules and PB Libraries

                                  http://www.masm32.com/board/index.php?board=69.0

                                  Comment


                                  • #18
                                    Example less than and less than or equal in BASIC, less than in assembly. Greater than, greater than or equal, and equals would be similar.
                                    '
                                    Code:
                                    #compile exe
                                    #dim all
                                    'Less Than ---------------------------------------------------------------------
                                    function A64_LT_B64(A as quad, B as quad) as long
                                      if hi(dword, A) < hi(dword, B) then
                                        function = -1
                                        exit function
                                      elseif hi(dword, A) = hi(dword, B) then
                                        if lo(dword, A) < lo(dword, B) then
                                          function = -1
                                        end if
                                      end if
                                    end function
                                    'Less Than or Equal ------------------------------------------------------------
                                    function A64_LTE_B64(A as quad, B as quad) as long
                                      if hi(dword, A) < hi(dword, B) then
                                        function = -1
                                      elseif hi(dword, A) = hi(dword, B) then
                                        if lo(dword, A) <= lo(dword, B) then
                                          function = -1
                                        end if
                                      end if
                                    end function
                                    'Assembly Less Than - because question in Assembly section----------------------
                                    function AsmA64_LT_B64(A as quad, B as quad) as long
                                      #register none
                                      local pA, pB as long
                                      pA = varptr(A)
                                      pB = varptr(B)
                                      ! mov eax, pA
                                      ! mov ebx, pB
                                      ! mov eax, [eax + 4]
                                      ! mov ebx, [ebx + 4]
                                      ! cmp eax, ebx
                                      ! jb IsLT
                                      ! je TestLo
                                      ! jmp Done
                                      TestLo:
                                      ! mov eax, pA
                                      ! mov ebx, pB
                                      ! mov eax, [eax]
                                      ! mov ebx, [ebx]
                                      ! cmp eax, ebx
                                      ! jb IsLT
                                      ! jmp Done
                                      IsLT:
                                      function = -1
                                      Done:
                                    end function
                                    'PBMain demos the above ========================================================
                                    function pbmain () as long
                                      local T1, T2 as quad
                                      T1 = &h0000000100000000&&
                                      T2 = &h8000000000000000&&
                                      ? T1 < T2 ; " as Quad, is false because T2 compared as negative signed."
                                      ? A64_LT_B64( T1, T2); " is true using unsigned for compares."
                                      ? AsmA64_LT_B64(T1, T2); " assembly version of Less Than"
                                      ? A64_LT_B64(T2, T1); " should be false"
                                      ? A64_LTE_B64(T1, T2); " true for less than"
                                      T1 = &h8000000100000000&&
                                      T2 = &h8000000100000000&&
                                      ? A64_LTE_B64(T1, T2); " true for equals."
                                      waitkey$
                                    end function '
                                    Cheers,
                                    Dale

                                    Comment


                                    • #19
                                      What is your C+ program DOING that you have to copy its technique of manipulating UINT64 data items?

                                      My opinion of mindless verb-for-verb, function-for-function, statement-for-statement ports from one O/S to another or from one source language to another is well known to be 'stone loser.'

                                      So what are you doing that you want to treat PB QUADs as unsigned integers? Could you instead use a BIT ARRAY to perform your manipulation?
                                      Michael Mattias
                                      Tal Systems (retired)
                                      Port Washington WI USA
                                      [email protected]
                                      http://www.talsystems.com

                                      Comment


                                      • #20
                                        Or you could use a modified version of the method I used to display the factorial of one hundred (100) on the screen, accurate to all significant digits.

                                        Go to my website at http://www.talsystems.com/tsihome_html/techcorner.html and download FACTOR.ZIP to see how I did it.
                                        Michael Mattias
                                        Tal Systems (retired)
                                        Port Washington WI USA
                                        [email protected]
                                        http://www.talsystems.com

                                        Comment

                                        Working...
                                        X