Menu

Signed Math Libraries

Help
kent_twt4
2009-02-22
2013-05-30
  • kent_twt4

    kent_twt4 - 2009-02-22

    Santiago, tried your signed math library, and it looks very good, thanks for sharing it with us!  Posted here, as did not want to clutter up your contributors thread.

    Maybe a sign thing going on with the signed_add function?  Not really sure, it very likely is my output routine, so please take with a grain of salt.  Looking at assembly makes my gears grind to a slow crawl.  It occurs with value2 equal to result in your equation, with value2's of 0, -1, -2, -3, -4, -5 and the new result is -2, -1, 0, -1, -1, -3 ????

    One suggestion is make two sets of equations, one for bytes, one for words.  Then one would check the byte.7, and word_H.7 respectively for the sign bit.  That gives a range +/-127 and +/-32,767 respectively.  Having the +/-127 gives you binary radians, if my recollection is right.

    Made up a routine to test your modules using an LCD, along with a button, and a state machine.  It can be painful to look at others code, but will post it if you or others request.

     
    • Edward LaBudde

      Edward LaBudde - 2009-02-22

      Kent, I know nothing about this stuff.  Is this the solution to the problem I was struggling with in the PID and A_D threads?  The problem of dealing with negative numbers.

      I solved the problem but it was pretty ugly!  There must be a better way. 

      If not, what is the correct way of dealing with it?  Thanks for all your help.  Santiago is a smart fellow.

      Everything about these PIC is a struggle for me as I missed out on the hexadecimal stuff by avoiding digital crap, and all the programming stuff by discovering spreadsheets.

      These threads are an enormous help to learning this stuff.  I have Soooooooo Farrrrrrr to go!

      I think Great Cow is the best thing since sliced bread, or maybe the light bulb!!

      Regards, Ed.

       
    • Santiago

      Santiago - 2009-02-23

      Hi kent... thanks for the feed-back!!

      Ed:
      I did the functions for use it in my motors PID, but can be used (carefully) in any simple signed calculations.
      I saw the way you solved signs in your filter, in that case i think your's is the best solution; in the case of PID, things can be complex and signed math can help a lot to keep a simple and clear code. I'm just testing it... still starting to work in my PID, that's why i didn't offer you this as a solution until i'm sure about it; but it could be great if you want to try it, just for testing the functions, any feedback will be apreciated.

      Kent.. thought english is not my mother-tongue and sometimes is difficult for me understanding somethings...
      About the problem you report it could be great when you post a piece of code where the problem happens, including variable declarations to see what is really happening. I'm very interested in finding bugs, then this will be very apreciated.

      >One suggestion is make two sets of equations, one for bytes, one for words. Then one >would check the byte.7, and word_H.7 respectively for the sign bit. That gives a range >+/-127 and +/-32,767 respectively. Having the +/-127 gives you binary radians, if my >recollection is right.

      Good idea!!.. i have to think in it... but this should require to re-write the complet math routines ( or not... it needs some thoughts...).
      what i did in the signed functions is a very simple thing... is just a select case with all the possible combinations of signs, then doing standard add or substract low bytes in the proper order, and set or clear the first bit of the high byte as a sign flag... It stays in the easy side, can solve some basic calculations, but is not very eficient.

      Anyway i will try to explain how to use the functions and what you can and cannot do:

      One important thing is you cannot do standard math operations with the variables used in these functions... you can have erroneus results as bit0 of high byte is used as sign flag.
      The variables are declared as word just to have a high byte to manage sign flag, but they are just byte (0-255) variables for the functions (not for GCBasic).
      For example:

      dim value1 as word
      dim value2 as word
      dim result as word

      value1=2
      value2=8
      result=0

      result = Signed_Sub(value1, value2) 'result = 2-8 = -6

      Now result= 00000001 00000110

      this is:
      result = 00000110 = 6 'absolute value of the variable
      result_H = 000000001 'sign flag is high = this is a negative number

      But for GCBasic in terms of "word" value:
      result= 00000001 00000110 = 262

      if now you do "standard" math operation with this variable, for example:

      dim my_variable as word
      my_variable = result + 10

      you will have:

      my_variable = 262 + 10 = 272

      But if you do this:

      dim my_variable as byte
      my_variable = result + 10

      then you will have:

      my_variable = 6 +10 = 16

      When you want to "switch" to standard math you can do (for example):

      if result_H = 1 then
      result_H = 0
      my_variable = 10 - result
      End if
      if result_H = 0 then my_variable = 10 + result

      Then when using the resultant value you need to take in account that you cannot use it directly as a word variable, but you can use the absolute value in the low bit and the sign in the high bit.

      For example you can take low bit to set the motor speed and high bit to set direction of spining...

      You can take this values using byte variables, for example:
      dim output as byte
      dim sign as byte
      output = result
      sign = result_H

      And then you can do standard math with "output" variable.

      In order to solve this "problems" signed variables should be included in compiler's core... but i think this is not a child's play.

      Keep sharing ideas...

       
    • kent_twt4

      kent_twt4 - 2009-02-23

      >I know nothing about this stuff. Is this the solution to the problem I was struggling >with in the PID and A_D threads? The problem of dealing with negative numbers.

      Ed, not sure if the signed numbers is your solution or not.  Have yet to have a play with your a-d filter or PID.  In this regards, I am the student.

      Have been spending efforts on a 2 axis accelerometer used for angle calculation.  So, the joy of SIN lookup tables, of late.  It's been ages since I've cracked a math book.

      Santiago,  don't worry about your English, your explanations and code are very clear.

      Tracked down the piece of code that gives a hiccup.  It has to do with the reuse of the signed_add function by the signed_sub function.  First off, the signed_sub function appears fine.

      In order for the signed_add function to work properly the following code needs to be looked at.  The test condition is when the signed first_val is added to a positive second_val, and when the absolute first_val is less than the positive second_val.  For instance try using:

      value1 = -1
      value2 = 2

      result = Signed_Add(value1, value2) ;i.e. result = -1 + 2 = +1
      ;The returned value of result is -1 not +1 as you would expect.

      Signed_Add function
      ...
      ...
      general_sub:
      MOVF second_val,W
      SUBWF first_val,W 
      BTFSC STATUS,C
      goto exit_general_sub
      if Signed_Add_H.0 on then set Signed_Add_H.0 off 'toggle sign

      ;the following line of code needs to be commented out for signed_add to work
      ;but doing so busts the Signed_Sub function
      ;**************************************
      'if Signed_Add_H.0 off then set Signed_Add_H.0 on
      ;**************************************

      SUBLW 255
      ADDLW 1
      exit_general_sub:
      MOVWF Signed_Add
      goto exit_signed_add
      ...
      ...

      Regards,
      Kent

       
    • Santiago

      Santiago - 2009-02-23

      Ok Kent.. now i know what is the problem:

      The functions just do the maths, but assigning negative values to variables is not possible, then this will not work:

      value1 = -1

      Take in account that these are just some external functions... the compiler doesn't know anything about signs...
      in order to assign negative values to variables, authentic signed variables should be implemented in GCBasic compiler's core... that's still too much for me...

      these signed functions are a tool to deal with math operations that could result in negative values, anyway what you try is possible:

      to set initial negative values you can do this way:
      ____________________________________________________________

      dim value1 as word
      dim value2 as word
      dim result as word

      value1 = 10
      value1_H = 1 'this set negative flag to value1
      value2 = 20

      result = Signed_Add(value1, value2)
      ____________________________________________________________

      In this case result will be positive and there is no problem when you want to use this value, but you have to take in account that when result is a negative value you have to manage it properly...

      For example i did some testing in order to control a motor with pwm, the motor controller is conected to PIC at PWM pin and PORTC.0 pin
      I did the calculations with signed functions, and have a word variable called "result":
      _________________________________________________________________________

      dim result as word
      dim output as byte 'BYTE VARIABLE
      dim direction as byte

      'i do signed calculations
      ........
      .........
      ........
      'Now i have the resultant value in "result" variable ( type: word)
      'Now i proceed to pass the values to PWM and turn direction:

      output = result 'here only the low byte of result is passed to "output" as output is a byte variable

      direction = result_H 'here the high byte of result is passed to "direction" (just 1 or 0)

      PORTC.0 = direction.0 'this will determine the turn direction of the motor

      if direction.0 on then output = 255 - output 'if reverse turn then invert pwm

      HPWM 1, 10, output

      _______________________________________________________________________________

      Note that the "flag bit" (result_H.0) is used to determine if the motor turns ahead or reverse
      When in reverse turn, the "active" side of PWM is the low state (as PORTC.0=1) then inverting the signal is needed.
      Note that for using the "result" value and sing i used two BYTE variables not word variables.

      I hope this can be understood...

      This functions are not the most easy to use but can be a useful tool; anyway any idea to improove it will be apreciated.
      Anyway as external fuctions the capablities are very limited and far from real signed variables.

       
    • kent_twt4

      kent_twt4 - 2009-02-23

      Santiago, sorry didn't mean -1  in the literal sense.  My code is handling the negative sign in the value1_H.0 prior to the signed_add function, and then also after the returned value (result) of the signed_add function.

      If you can hook up and LCD and use the code below, then it better explains, than my words to you.  In the pressing of the state machine button input (pullup on input pin) you can toggle between the different signed math modules.

      Perhaps there is an error in my code?, in which case, all apologies extended.

      As previously noted in the signed_add function there is a discrepancy, when the absolute of the signed value (say value1) is less than an unsigned value (say value2).  When value1 goes from signed 0, 1, 2, 3, 4, 5, 6..., and added to say a value2 of 4, the resultant goes from -4, -3, -2, -1, 0, -1, -2.........When in fact the resultant should be 4, 3, 2, 1, 0, -1, -2......... Please beg your pardon for the visual representation of the resultant numbers, but it seems easiest to describe this way to me.

      You do not have to hook up the LCD example.  Just try to use your flow of the code, and you will find that the when the absolute value of value1 is less than the unsigned value2 number, the Signed_Add_H.0 needs to be set "off" to represent a positive (unsigned) number.  The addition of the following code makes it work.

      general_sub:
          ;additional code to fix bug
          absolute_first_val = first_val ;get lower byte of first_val
          if absolute_first_val < second_val then
              set Signed_Add_H.0 off
              MOVF first_val,W
              SUBWF second_val,W
              goto exit_general_sub
          end if

      Here is my test code for your modules with an LCD, hope it helps.

      'Test of Signed Math Library 2/21/09 by Santiago Glez
      'Chip model
      #chip 16f877a,20

      #include <SignedMath.h>
      #define LCD_IO 4
      #define LCD_DB4 PORTD.4
      #define LCD_DB5 PORTD.5
      #define LCD_DB6 PORTD.6
      #define LCD_DB7 PORTD.7
      #define LCD_RS PORTA.1
      #define LCD_RW PORTA.2
      #define LCD_Enable PORTA.3

      #define Button PortE.2  ;Button pulled up by hardware
      dir Button in

      #define waitbutton wait 1 10ms
      #define lcdwait wait 50 10ms
      dim value1 as word
      dim value2 as word
      dim result as word
      value2=4
      result=0
      counter = 0

      Main:

      Subtract:
      ExitModule = False
      counter += 1
      For testnum1 = 0 to 127  ;keep operations less than byte
          If Button Off then DebounceButton
          If ExitModule = True Then goto Exit1
          value1 = testnum1 + 256  ;make a negative value
          result = Signed_Sub(value1, value2)
          locate 0,0:Print "Subtract "
          Output  ;display on lcd
          lcdwait
      Next
      Exit1:

      Multiply:
      ExitModule = False
      counter += 1
      For testnum2 = 0 to 63
          If Button Off then DebounceButton
          If ExitModule = True Then goto Exit2
          value1 = testnum2 + 256  ;make negative value
          result = Signed_Mul(value1, value2)
          locate 0,0:Print "Multiply "
          Output
          lcdwait
      Next
      Exit2:

      Addition:
      ExitModule = False
      counter += 1
      For testnum3 = 0 to 127  ;keep operations less than byte
          If Button Off then DebounceButton
          If ExitModule = True Then goto Exit3
          value1 = testnum3 + 256  ;make negative value    
          result = Signed_Add(value1, value2)
          locate 0,0:Print "Addition "
          Output  ;display on lcd
          lcdwait
      Next
      Exit3:

      Division:
      ExitModule = False
      counter += 1
      For testnum4 = 0 to 252 step 4 ;keep operations less than byte
          If Button Off then DebounceButton
          If ExitModule = True Then goto Exit4
          value1 = testnum4 + 256  ;make negative value    
          result = Signed_Div(value1, value2)
          locate 0,0:Print "Division "
          Output  ;display on lcd
          lcdwait
      Next
      Exit4:    
          'Now result = 5, result_H = 1 (negative)
          
          'result = Signed_Mul(result, result) 'result = -5 * -5= 25
          
          'Now result = 25, result_H = 0 (positive)
         
          'Locate 1,0
          'If result >= 10000 then PRINT "Calc ":Print result
          'If result >= 1000 AND result < 10000 then Print "Calc  ":PRINT result

      'Next
      Goto Main

      Sub Output
          Minus = False
          If result.8 On Then
              result = result - 256
              If result >= 0 Then Minus = True
          End if
          If result >= 100 AND result < 1000 then NegSign:PRINT result
          If result >= 10 AND result < 100 then Print " ":NegSign:PRINT result
          If result < 10 AND result > 0 then Print "  ":NegSign:PRINT result
          If result = 0 Then Print "   0"
      end sub

      Sub NegSign
          If Minus = True Then
              Print "-"
          Else
              Print " "
          End if
      end sub

      Sub DebounceButton
      If Button Off then
          ButtonCount = 0
          Do While Button off
              waitButton
              ButtonCount += 1
          Loop
          If ButtonCount > 4 then ExitModule = True
      End if
      end sub

       
    • kent_twt4

      kent_twt4 - 2009-02-23

      Of course SourceForge Message algorithm messes with the code once again.  I should put a request in for code tags, because it crushes blank spaces like its no tomorrow.

      In the above code the LCD formatting is lost, so instead of using " " spaces I will use "b" spaces!!!

      If result >= 100 AND result < 1000 then NegSign:PRINT result
      If result >= 10 AND result < 100 then Print "b":NegSign:PRINT result
      If result < 10 AND result > 0 then Print "bb":NegSign:PRINT result
      If result = 0 Then Print "bbb0"

       
    • Santiago

      Santiago - 2009-02-24

      Ok Kent yopu are right!!.. there is an error in the code... thanks for finding it!!

      I went too quickly when supposing "value1 = -1" was the problem and didn't test it properly.

      The problem could be solved as you say, but there is already a routine that should do it... is not missing, but didn't work, the solution is just adding a "goto".

      Here is the solution:

          general_sub:

              MOVF  second_val,W
              SUBWF first_val,W 
              BTFSC STATUS,C
              goto exit_general_sub

              if Signed_Add_H.0 on then
              set Signed_Add_H.0 off    'toggle sign
              goto $+3 '..........................................<<<needed to jump over next "if"
              End if

              if Signed_Add_H.0 off then set Signed_Add_H.0 on

              SUBLW 255 '.........................................<<<program will jump here
              ADDLW 1
              exit_general_sub:
              MOVWF Signed_Add
              goto  exit_signed_add
      __________________________________________________________________________

      The BTFSC STATUS,C is for testing when the substracction result  is < 0 , in that case program come in the toggle sign routine, if the substracction result is positive then goto exit_general_sub and nothing else is done. (BTFSC = Bit Test F Skip if Cero : if status,c bit is 0 then skip next instruction)

      Then here was the problem:

              if Signed_Add_H.0 on then set Signed_Add_H.0 off    'toggle sign
              if Signed_Add_H.0 off then set Signed_Add_H.0 on

      As you can see when the first "if" is true and Signed_Add_H.0 is toggled to off then the second "if" will be true and the bit will be toggled again... :(

      what is needed is just jump over second "if" when first "if" is executed

      Thanks for reporting the error...

       
    • Santiago

      Santiago - 2009-02-24

      Hi Kent...

      I had a look to your test for signed math... it's a good way for testing a wide range of values in every function.

      I noticed that you managed to keep result values in the 0-255 range, this is a cuestion that could be solved...

      By now i aded some lines to set the Signed_Add_H.1 bit when the resultant value of the operation (add) is >255; i use this to set result to 255 when result > 255, but this bit can be used as the 9th bit (carry), then 0-511 values are available.
      But this will be a problem when using result value as you did:

      If result.8 On Then
      result = result - 256

      Still noy sure about how to mange >255 values, but i need it for PID.
      Perhaps using high_byte.0 for "carry" and high_byte.1 for sign....

      Still thinking how to implement this in Signed_Mul() function too...

      With "b" i understand why this lines... :)

      If result >= 100 AND result < 1000 then NegSign:PRINT result 
      If result >= 10 AND result < 100 then Print "b":NegSign:PRINT result 
      If result < 10 AND result > 0 then Print "bb":NegSign:PRINT result 
      If result = 0 Then Print "bbb0"

       

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.