Converting between signed and unsigned numbers.

Share your advanced PureBasic knowledge/code with the community.
TassyJim
Enthusiast
Enthusiast
Posts: 186
Joined: Sun Jun 16, 2013 6:27 am
Location: Tasmania (Australia)

Converting between signed and unsigned numbers.

Post by TassyJim »

Converting between signed and unsigned numbers.
Taken from a Microsoft Knowledge-base article aimed at VBA.

I have come from a dialect of Basic which uses floating point numbers only so all this discussion about signed/unsigned is interesting.

Code: Select all

;unsigned.pbi
;How To Convert Between Signed and Unsigned Numbers
;http://support.microsoft.com/kb/189323

Procedure ErrorHandler()
  MessageRequester("OnError", "Overflow error, Code: "+ Str(ErrorCode()))
EndProcedure

Procedure.l UnsignedToLong(Value.q)
  Protected OFFSET_4.q = 4294967296, MAXINT_4 = 2147483647
  If Value < 0 Or Value >= OFFSET_4 
    RaiseError(6) ; Overflow
  EndIf
  If Value <= MAXINT_4 
    UnsignedToLong.l = Value
  Else
    UnsignedToLong = Value - OFFSET_4
  EndIf
  ProcedureReturn UnsignedToLong
EndProcedure

Procedure.q LongToUnsigned(Value.l)
  Protected OFFSET_4.q = 4294967296, MAXINT_4 = 2147483647
  If Value < 0
    LongToUnsigned.q = Value + OFFSET_4
  Else
    LongToUnsigned = Value
  EndIf
  ProcedureReturn LongToUnsigned
EndProcedure

Procedure.l UnsignedToWord(Value.l)
  Protected  OFFSET_2 = 65536, MAXINT_2 = 32767
  If Value < 0 Or Value >= OFFSET_2 
    RaiseError(6); Overflow
  EndIf
  If Value <= MAXINT_2
    UnsignedToWord = Value
  Else
    UnsignedToWord = Value - OFFSET_2
  EndIf
  ProcedureReturn UnsignedToWord
EndProcedure

Procedure.l WordToUnsigned(Value.l)
  Protected  OFFSET_2 = 65536, MAXINT_2 = 32767
  If Value < 0
    WordToUnsigned = Value + OFFSET_2
  Else
    WordToUnsigned = Value
  EndIf
  ProcedureReturn WordToUnsigned
EndProcedure

OnErrorCall(@ErrorHandler())

Debug UnsignedToLong(3300000000)
Debug LongToUnsigned(-55)
Debug UnsignedToWord(45000)
Debug WordToUnsigned(-3000)

; You will get the following results:
; -994967296
; 4294967241
; -20536
; 62536

;Debug UnsignedToLong(-3300000000) ; this line results in an error due to negative input
As I am a very new beginner with PureBasic, any improvements to the code style would be welcome.
Jim
Little John
Addict
Addict
Posts: 4791
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Converting between signed and unsigned numbers.

Post by Little John »

Hi, welcome to the forum, :-)

and thanks for this contribution.
TassyJim wrote:As I am a very new beginner with PureBasic, any improvements to the code style would be welcome.
Some comments and suggestions:

A good tip is to always use EnableExplicit. This will prevent you from nasty bugs caused by typos in your variable names. If you use EnableExplicit here, then you'll have to add Protected UnsignedToLong.l etc. inside of the procedures. However, with the given code I personally prefer to do without these additional variables, and to directly return the results (see code below).

OFFSET_4 etc. are constants by their "nature". So I think it's a bit better readable when we actually use constants for those values rather than variables. An additional advantage is that we have to define the constants in the code only once. I'd also prefer to use a named constant for the error code.

With enabled debugger, the OnError library may not catch all errors. So we might want to test this code with the debugger switched off. But then we'll not see anything, because all the output is done by Debug statements. :-) So better replace the Debug statements with MessageRequester() here.

For a little more precision, replace .l with .w two times (see code below).

Since version 5.10, PureBasic has a nice feature that allows to put some code in an include file, which is only executed if that file is the main file, i.e. if it's not included in another file. That's perfect for code aimed at demonstrating the usage of the library functions in an include file.

Code: Select all

; unsigned.pbi
; How To Convert Between Signed and Unsigned Numbers
; http://support.microsoft.com/kb/189323

EnableExplicit

#OFFSET_4 = 4294967296
#MAXINT_4 = 2147483647
#OFFSET_2 = 65536
#MAXINT_2 = 32767

#OnError_Overflow = 6


Procedure ErrorHandler()
   MessageRequester("OnError", "Overflow error, Code: "+ Str(ErrorCode()))
EndProcedure

Procedure.l UnsignedToLong(Value.q)
   If Value < 0 Or Value >= #OFFSET_4
      RaiseError(#OnError_Overflow)
   EndIf
   
   If Value <= #MAXINT_4
      ProcedureReturn Value
   Else
      ProcedureReturn Value - #OFFSET_4
   EndIf
EndProcedure

Procedure.q LongToUnsigned(Value.l)
   If Value < 0
      ProcedureReturn Value + #OFFSET_4
   Else
      ProcedureReturn Value
   EndIf
EndProcedure

Procedure.w UnsignedToWord(Value.l)
   If Value < 0 Or Value >= #OFFSET_2
      RaiseError(#OnError_Overflow)
   EndIf
   
   If Value <= #MAXINT_2
      ProcedureReturn Value
   Else
      ProcedureReturn Value - #OFFSET_2
   EndIf
EndProcedure

Procedure.l WordToUnsigned(Value.w)
   If Value < 0
      ProcedureReturn Value + #OFFSET_2
   Else
      ProcedureReturn Value
   EndIf
EndProcedure


CompilerIf #PB_Compiler_IsMainFile
   ;-- Demo
   OnErrorCall(@ErrorHandler())
   
   MessageRequester("Result", Str(UnsignedToLong(3300000000)))  ; -994967296
   MessageRequester("Result", Str(LongToUnsigned(-55)))         ; 4294967241
   MessageRequester("Result", Str(UnsignedToWord(45000)))       ; -20536
   MessageRequester("Result", Str(WordToUnsigned(-3000)))       ; 62536
   
   MessageRequester("Result", Str(UnsignedToLong(-3300000000))) ; error due to negative input
CompilerEndIf
BTW: Here is similar code for peeking and poking unsigned long values.
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: Converting between signed and unsigned numbers.

Post by davido »

Hi TassyJim,

Welcome and thank you for sharing.

Hi Little John,

Thank you for the Peek/Poke information.
DE AA EB
Post Reply