Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
assert Integer.MAX_VALUE == 2147483647 //at 2 billion, this is big enough for most uses
assert Integer.MIN_VALUE == -2147483648
assert Long.MAX_VALUE == -9223372036854775807
assert Long.MIN_VALUE == -9223372036854775808

...

We can represent integers in base-10, hexadecimal, or octal notation:

Code Block
[ 2, -17, +987, 0 ].each{ println it } //base-10 integers, positive or negative...
[ 0xACe2, 0X01ff -17, +987 ].each{ assert it } 

//hex using leading 0x (lowercase or uppercase for a,b,c,d,e,f,x)...
[ 0770xACe, 010X01ff ].each{ assert it }

//octal using leading 0...
[ 077, 01 ].each{ assert it }

We can negate hexadecimals and octals to represent negative numbers.

...

We can force an integer (including hexadecimals and octals) to have a specific type by giving a suffix (I for Integer, L for Long, G for BigInteger), either uppercase or lowercase:

Code Block
assert 42i.class == Integer //either uppercase or lowercase, but lowercase i more readable
assert 123L.class == Long //uppercase L more readable
assert 456g.class == BigInteger
assert 0xFFi.class == Integer

...

Code Block
assert Short.MAX_VALUE == 32767
assert Short.MIN_VALUE == -32768
assert Byte.MAX_VALUE == 127
assert Byte.MIN_VALUE == -128
def a= new Byte('34'), b= new Byte('2')
assert (a+2b).class == Integer

We can enquire the bit-size of each type of fixed-size integer:

...

Code Block
assert 45L as Integer == 45i
assert 45L as int == 45i //example of using 'int' for Integer
assert 45L.toInteger() == 45i //alternative syntax
assert 23L.intValue() == 23i //another alternative syntax

assert 45i as Long == 45L
assert 45i as long == 45L
assert 23i.toLong() == 23L
assert 45i.longValue() == 45L
assert
256i as Byte == 0 //if converted number too large tofor fit in target, only the lowest order bits returned...
assert 256i as Byte == 0 
assert 200i as byte == -56 //...and this may result in a negative number

...

Code Block
assert '42'.toInteger() == 42i
assert '56'.toLong() == 56L

try{ 'moo'.toLong(); assert false }
catch(e){ assert e instanceof NumberFormatException }

assert new Integer( '45' ) == 45i
assert new Byte( '45' ) == 45 as byte

try{ new Integer( 'oink' ); assert false }
catch(e){ assert e instanceof NumberFormatException }

To convert from a fixed-size integer to a string in various bases:

Code Block
assert Integer.toString( 29, 16 ) == '1d' //second character is the base/radix...
assert LongInteger.toString( 29L29, 16 ) == '1d'

//Long version behaves just like Integer version...
assert IntegerLong.toString( -2929L, 16 ) == '-1d'

//if number is negative, so is first character of returned string...
assert Integer.toString(0 -29, 16 ) == '0-1d'

//only time result begins with zero is if it is zero...
assert Integer.toString( 29, 16 ).toUpperCase()0) == '1D0'

assert Integer.toString( 29, 16 ).toUpperCase() == '291D'

//second argument defaults to 10...
assert ShortInteger.toString( 29 as short ) == '29'

//Short version only accepts one parameter, only allowing base 10...
assert Short.toString( 29 as short ) == '29'

If the base/radix isn't between Character.MIN_RADIX and Character.MAX_RADIX, base 10 is used instead:

Code Block
assert Integer.toString( 999, Character.MIN_RADIX - 1 ) ==
    Integer.toString( 999, 10 )

assert Integer.toString( 999, Character.MAX_RADIX + 1 ) ==
    Integer.toString( 999, 10 )

assert Character.MAX_RADIX == 36
    //the symbols letters 0123456789abcdefghijklmnopqrstuvwxyz are used

...

Code Block
assert Integer.toHexString(29) == '1d' //return unsigned base-16 integer
assert Integer.toHexString(0) == '0'
assert Integer.toHexString(-17) == 'ffffffef'
assert Long.toHexString(-17L) == 'ffffffffffffffef'

assert Integer.toHexString(29) == Integer.toString(29,16) //same as toString(,16) when number positive...
assert Integer.toHexString(-1729) !== Integer.toString(-1729,16)

//...but different when number negative
assert Integer.toHexString(-17) != Integer.toString(-17,16)

assert Integer.toOctalString(29) == '35'
assert Integer.toOctalString(0) == '0'
assert Integer.toOctalString(-17) == '37777777757'
assert Integer.toBinaryString(29) == '11101'

...

Code Block
assert Integer.parseInt("0", 10) == 0
assert Integer.parseInt("473", 10) == 473
assert Long.parseLong("473", 10) == 473L //Long type/class has similarly-acting method
assert Integer.parseInt("473") == 473 //base 10 is the default base/radix
assert Integer.parseInt("-0", 10) == 0
assert Integer.parseInt("-FF", 16) == -255
assert Integer.parseInt("1100110", 2) == 102
assert Integer.parseInt("2147483647", 10) == 2147483647
assert Integer.parseInt("-2147483648", 10) == -2147483648
assert Integer.parseInt("Kona", 27) == 411787
assert Long.parseLong("Hazelnut", 36) == 1356099454469L
assert Short.parseShort("-FF", 16) == -255

...

Code Block
[ { Integer.parseInt("2147483648", 10) }, //number too large
   { Integer.parseInt("99", 8) }, //digit 9 not octal
   { Integer.parseInt("Kona", 10) }, //digits not decimal
   { Integer.parseInt("1111", Character.MIN_RADIX - 1 ) }, //radix too small
   { Integer.parseInt("1111", Character.MAX_RADIX + 1 ) }, //radix too large
   { Integer.parseInt( '@#$%' ) }, //invalid number
   { Integer.parseInt( '' ) }, //invalid number
].each{ c->
  try{ c(); assert false }
  catch(e){assert e instanceof NumberFormatException}
}

...

Code Block
assert Integer.valueOf( '12af', 16 ) == 0x12af
    //same as: Integer.parseInt( '12af', 16 )

assert Long.valueOf( '123' ) == 123
    //same as: Long.parseInt( '123' )

assert Short.valueOf( 027 as short ) == 027

...

Code Block
assert Integer.decode('0xff') == 0xFF
assert Integer.decode('#FF') == 0xFF
assert Long.decode('#FF') == 0xFFL //long, short, and byte also can be decoded
assert Short.decode('#FF') == 0xFF as short
assert Byte.decode('#F') == 0xF as byte
assert Integer.decode('-077') == -077
assert Integer.decode('2345') == 2345

try{ Integer.decode('7 @8'); assert false }
catch(e){ assert e instanceof NumberFormatException }

...

Code Block
assert 45i.compareTo( 47L ) < 0
assert (45 as byte).compareTo( 43 as short ) > 0
assert 45.compareTo( 45 ) == 0

Calculations with Fixed-Size Integers

We can perform addition, subtraction, multiplication, exponents, modulos, and negations on Integers and Longs, using both an operator syntax and a method syntax:

Code Block
assert 34 + 33 == 67   67    && 34.plus( 33 ) == 67
assert 34L - 21L == 13L && 34L.minus( 21L ) == 13L
assert 3 * 31 == 93    93     && 3.multiply( 31 ) == 93
assert 23 % 3 == 2     2      && 23.mod( 3 ) == 2
assert 3**2 == 9       9 && 3.power( 2 ) == 9 assert -(3) == -3       && 3.negatepower( 2 ) == -39

Not all calculations have a special operator symbol:

Code Block
assert 22.intdiv(5) == 4
assert (-22).intdiv(5) == -4
assert (-34).abs() == 34
assert (-34L).abs() == 34L

We can divide an integer into another, resulting in a decimal number. We'll look at this topic in the next tutorial, Groovy BigDecimal Math.We can increment and decrement variables, using operators, either before and after evaluation:

Code Block
def a= 7
assert a++ == 7 && a == 8 && a-- == 8 && a == 7 &&
             ++a == 8 && a == 8 && --a == 7 && a == 7

def b = 7, c = 7 //These operators use methods next() and previous()
assert ( ++b ) == ( c = c.next() )
assert b == c
assert ( --b ) == ( c = c.previous() )
assert b == c
assert ( b++ ) == { def z = c; c = c.next(); z }()
assert b == c

def b= Integer.MAX_VALUE
assert ++b == Integer.MIN_VALUE && --b == Integer.MAX_VALUE

...

Code Block
assert 3*(4+5) != 3*4+5 //parenthesized expressions always have highest precedence

assert -3**2 == -(3**2) //power has next highest precedence
assert ( 2*3**2 == 2*(3**2) ) && ( 2*3**2 != (2*3)**2 )

assert -3+2 != -(3+2) //unary operators have next highest precedence
assert -~234 ==   -(~234) //unary operators group right-to-left

//multiplication and modulo have next highest precedence
assert 3*4%5 == (3*4)%5 //multiplication and modulo have equal precedence
assert 3%4*5 == (3%4)*5

assert 4+5-6 == 3 //addition and subtraction have equal precedence, lower than mult/etc
assert 5+3*4 == 5+(3*4)

...

Because the fixed-sized integers have fixed width, they might overflow their boundaries during math operations, so we need to be aware of the range of values we'll use a fixed-size integer for:

Code Block
assert 256*256*256*256 == 0 //each 256 is an Integerint, so final product also an Integerint, and calc overflowed...
assert 256L256*256*256*256 == 4294967296L0
   
//we can fix this problem by using a long at the beginning of the calculation...
assert 256L*256*256*256 == 4294967296L

We can compare fixed-size integers using  using < => < <= > >= operators, of lower precedence than addition/etc:

Code Block
assert (414 <=> 7) == -1 && 4.compareTo(7) == -1 assert (4 <=> 4) == 0  && 414.compareTo(47) ==> 0
assert (414 <=> 2) == 8 && 4.compareTo(2) == 1 assert 14 > 7          && 14.compareTo(78) >= 0
assert 14-4 >=< 8        3 && 14.compareTo(8) >= 0 assert -4 < 3           && (-4).compareTo(3) < 0
assert -14 <= -9       9       && (-14).compareTo(-9) <= 0

The operators == != <=> are of lower precedence than the other comparison operators:

Code Block
def a = 4, b = 4, c = 5
assert a == b && a.equals(b)
assert a != c  && ! a.equals(c)
assert (4 <=> 7) == -1 && 4.compareTo(7) == -1
assert (4 <=> 4) == 0  && 4.compareTo(4) == 0
assert (4 <=> 2) == 1  && 4.compareTo(2) == 1

Bit-Manipulation on Fixed-Sized Integers

We can examine and manipulate the individual bits on the fixed-sized integers.

...

Code Block
[ 0:32, 1:31, 2:30, 4:29 ].each{ k, v->
   assert Integer.numberOfLeadingZeros( k ) == v
         //returns the number of zero-bits preceding the highest-order 1-bit
   assert Long.numberOfLeadingZeros( k as long ) == v + 32
}

[ 0:32, 45:0, 46:1, 48:4 ].each{ k, v->
   assert Integer.numberOfTrailingZeros( k ) == v
}    //returns the number of 0-bits following the lowest-order 1-bit
}
assert
Integer.bitCount( 7 ) == 3 //returns the number of 1-bits in the binary representation...
assert Integer.bitCount( 7 ) == 3
assert Integer.bitCount( -1 ) == 32

We can perform a bitwise complement of the bits in a fixed-size integer using the ~ operator:

Code Block
def x= 0x33333333i
assert ~x == -x - 1
    //under 2's-complement, how bitwise complement and negation are related in this way
under 2's-complement

We can shift the bits of a fixed-size integer to the left or right. This is of lower precedence than addition/etc, but higher than the comparison operators.

Code Block
//shift 4 bits to the left...
assert 0xB4F<<4 == 0xB4F0     0xB4F0      && 0xB4F.leftShift( 4 ) == 0xB4F0 0xB4F0

//shift 4 bits to the left
right, dropping off digits...
assert 0xD23C>>4 == 0xD23     0xD23      && 0xD23C.rightShift( 4 ) == 0xD23

//shiftsign-extension 4performed bitswhen to the right, dropping off digits
right-shifting...
assert -0xFFF>>4 == -0x100    0x100     && (-0xFFF).rightShift( 4 ) == -0x100

//sign-extension performed when right-shifting...unless triple >>> used
assert -0xFFF>>>4 == 0xFFFFF00 && (-0xFFF).rightShiftUnsigned(4) == 0xFFFFF00
//...unless triple >>> used
[ 0xABC, -0x98765 ].each{
   it << 8  == it >> -8
}

We can rotate the bits in an integer or long:

Code Block
assert Integer.rotateLeft( 0x456789AB, 4 ) == 0x56789AB4
     //we use multiples of 4 only to show what's happening easier

assert Integer.rotateLeft( 0x456789AB, 12 ) ==
   Integer.rotateRight( 0x456789AB, Integer.SIZE - 12 )
    //rotating left and right are inverse operations

assert Integer.rotateLeft( 0x456789AB, 32 ) == 0x456789AB //no change here

assert Long.rotateRight( 0x0123456789ABCDEF, 40 ) == 0x6789ABCDEF012345

...

Code Block
assert Integer.toString( 123456, 2 ) == '11110001001000000'

assert Integer.toString( Integer.reverse( 123456 ), 2 ) ==
    '10010001111000000000000000' //reverse bits

assert Integer.reverseBytes( 0x157ACE42 ) == 0x42CE7A15 //also works for bytes

...

Code Block
assert ! 0; assert 1; assert 2; assert -1; assert -2
assert ( ! 1 && 0 ) != ( ! (1 && 0) )
       // the unary ! has the same, high, precedence as the other unary operators
assert ( 1 || 0 && 0 ) != ( (1 || 0) && 0 ) // && has higher precedence than ||

...

Code Block
def x = 0
0 && x++
assert x == 0
//x++ wasn't performed because falsity of (0 && x++) was known when 0 evaluated

1 || x++
assert x == 0
//x++ wasn't performed because truth of (1 || x++) was known when 1 evaluated

...

Code Block
def x, y = (x = 3) && 1
assert (x == 3) && y

def i = 2, j = (i=3) * i
    //in the multiplication, lefthand (i=3) evaluated before righthand i
assert j == 9

Of equal precedence as the plain assignment operator  = are the quick assignment *= += -= %= **= <<= >>= >>>= &= ^= |= operators:

...

Code Block
assert 45i as BigInteger == 45g
assert 45L.toBigInteger() == 45g
assert 45g as Integer == 45i
assert 45g.intValue() == 45i //alternate syntax
assert 45g as Long == 45L
assert 45g.longValue() == 45L

assert 256g as Byte == 0
    //if converted number too large tofor fit in target, only the lowest order bits returned...
assert 200g as byte == -56 //...and this may result in a negative number

...

Code Block
assert BigInteger.valueOf( 45L ) == 45g
    //works for longs only (not for ints, shorts, or bytes)
assert BigInteger.ZERO == 0g
assert BigInteger.ONE == 1g
assert BigInteger.TEN == 10g

...

Code Block
assert new BigInteger( [1,2,3] as byte[] ) == 1g*256*256 + 2*256 + 3
    //big-endian 2's complement representation
try{new BigInteger( [] as byte[] ); assert 0}
catch(e){assert e instanceof NumberFormatException} //empty array not allowed

assert new BigInteger( -1, [1,2] as byte[] ) == -258g
    //we pass in sign as a separate argument

assert new BigInteger( 1, [1,2] as byte[] ) == 258g

assert new BigInteger( 0, [0,0] as byte[] ) == 0g

assert new BigInteger( 1, [] as byte[] ) == 0 //empty array allowable

try{ new BigInteger( 2, [1,2,3] as byte[] ); assert 0 }
catch(e){ assert e instanceof NumberFormatException}
       //sign value must be -1, 0, or 1

...

Code Block
def ba= (1g*256*256 + 2*256 + 3).toByteArray()
    //big-endian 2's complement representation
assert ba.size() == 3 && ba[ 0 ] == 1 && ba[ 1 ] == 2 && ba[ 2 ] == 3

def bb= 255g.toByteArray()
assert bb.size() == 2 && bb[ 0 ] == 0 && bb[ 1 ] == -1
    //always includes at least one sign bit

def bc= (-(2g*256 + 3)).toByteArray()
assert bc.size() == 2 && bc[ 0 ] == -3 && bc[ 1 ] == -3

...

Code Block
assert '27'.toBigInteger() == 27g
assert new BigInteger("27", 10) == 27g
assert new BigInteger("27") == 27g //default radix is 10
assert new BigInteger("110", 2) == 6g
assert new BigInteger("-1F", 16) == -31g
[ { new BigInteger(" 27", 10) }, //no whitespace allowed in string
   { new BigInteger("Z", Character.MAX_RADIX + 1 ) }, //radix out of range
   { new BigInteger("0", Character.MIN_RADIX - 1 ) }, //radix out of range
].each{
  try{ it(); assert 0 }catch(e){ assert e instanceof NumberFormatException }
}

...

Code Block
assert 6g.toString(2) == '110'
assert (-31g).toString(16) == '-1f'
assert 27g.toString() == '27' //default radix is 10
assert 27g.toString( Character.MAX_RADIX + 1 ) == '27'
    //radix is 10 if radix argument invalid

...

Code Block
assert new BigInteger( 20, new Random() ).toString( 2 ).size() == 20
    //20 is max bit length, must be >= 0
assert new BigInteger( 20, new Random() ) >= 0

Arithmetic with BigIntegers

We can perform the usual arithmetic operations + - * using either methods or operations:

...

Code Block
assert 256L*256*256*256 * 256*256*256*256 == 0
       //the first 256 is a Long, so each intermediate and final product also Long,
    //and calc overflowed

assert 256g*256*256*256 * 256*256*256*256 == 18446744073709551616
       //no overflow here because BigInteger introduced using 'g' suffix in first value

We can also increment and decrement BigIntegers:

Code Block
def a= 7g
assert a++ == 7g && a == 8g && a-- == 8g && a == 7g &&
             ++a == 8g && a == 8g && --a == 7g && a == 7g

...

Code Block
assert 7g.divide( 4g ) == 1g
assert 7g.remainder( 4g ) == 3g
def a= 7g.divideAndRemainder( 4g )
assert a[0] == 1g //quotient, same result as divide()
assert a[1] == 3g //remainder, same result as remainder()

assert 7g.divide( -4g ) == -1g
assert 7g.remainder( -4g ) == 3g
assert (-7g).divide( 4g ) == -1g
assert (-7g).remainder( 4g ) == -3g
    //division of a negative yields a negative (or zero) remainder
assert (-7g).divide( -4g ) == 1g
assert (-7g).remainder( -4g ) == -3g

...

Code Block
assert 22g.intdiv(5g) == 4g
assert (-22g).intdiv(5g) == -4g

assert 7g.abs() == 7g //absolute value
assert (-7g).abs() == 7g

assert 28g.gcd(35g) == 7g
    //greatest common divisor of absolute value of each number

assert (-28g).gcd(35g) == 7g
assert 28g.gcd(-35g) == 7g
assert (-28g).gcd(-35g) == 7g
assert 0g.gcd(9g) == 9g
assert 0g.gcd(0g) == 0g

assert 4g**3 == 64g //raising to the power
assert (4g**3).class == Integer
    //raising to the power converts a BigInteger to an integer

assert 4g.power(3) == 64g //using method
assert 4g.pow(3) == 64g
    //pow() is different to, and sometimes slower than, power()
assert (-4g).power(3) == -64g
assert 4g.power(0) == 1g //exponent must be integer >=0

assert 7g % 4g == 3g && 7g.mod( 4g ) == 3g
    //modulo arithmetic, using operator or method
assert 8g % 4g == 0g
assert -7g % 4g == 1g
    //result of mod is always zero or positive, between 0 and (modulus - 1) inclusive
try{ 7g % -4g; assert 0 }catch(e){ assert e instanceof ArithmeticException }
    //mod value must be positive

assert 4g.modPow( 3g, 9g ) == 1
    //calculates as ((4**3) mod 9), result always zero or positive
assert 4g.modPow( -2g, 9g ) == 4
    //negative exponents allowed, but mod value must be positive

assert 4g.modInverse( 3g ) == 1 //calculates as ((4**-1) mod 3)
       //mod must be positive, and value must have a multiplicative inverse mod m
    //(ie, be relatively prime to m)

assert 7g.max(5g) == 7g //maximum and minimum
assert 4g.min(5g) == 4g
def a=5g, b=5g, c=a.min(b)
assert [a,b].any{ c.is(it) }
    //either a or b may be returned if they're both equal

assert (-45g <=> -43g) && ( (-45g).compareTo( -43g ) == -1 )
    //comparing two BigIntegers
assert 14g >= 8g         8g         && 14g.compareTo(8g) >= 0

assert 45g.signum() == 1 //return sign as -1,0, or 1
assert 0g.signum() == 0
assert (-43g).signum() == -1

We can construct a randomly generated positive BigInteger with a specified bit length (at least 2 bits), that is probably prime to a specific certainty. The probability the BigInteger is prime is >(1 - (1/2)**certainty). If the certainty <=0, true always returned. The execution time is proportional to the value of this parameter. We must pass in a new Random object:

Code Block
100.times{
   def primes= [17g, 19g, 23g, 29g, 31g]
      //bitlength is 5, so primes from 16 to 31 incl
   assert new BigInteger( 5, 50, new Random() ) in primes
      //5 is bit-length, 50 is certainty (must be integer)
}

def pp= BigInteger.probablePrime( 20, new Random() )
    //if we don't want to specify certainty
       //20 is bit-length; there's <1.0e-30 chance the number isn't prime

def pn= pp.nextProbablePrime()
    //this is probably next prime, but definitely no primes skipped over
( (pp+1)..<pn ).each{
   assert ! it.isProbablePrime(50)
           //we can test for primality to specific certainty (here, 50).
      //True if probably prime, false if definitely composite
}
assert 10g.nextProbablePrime() == 11
assert 0g.nextProbablePrime() == 2

Bit-Manipulation on BigIntegers

All operations behave as if BigIntegers were represented in two's-complement notation.
Bit operations operate on a single bit of the two's-complement representation of their operand/s. The infinite word size ensures that there are infinitely many virtual sign bits preceding each BigInteger. None of the single-bit operations can produce a BigInteger with a different sign from the BigInteger being operated on, as they affect only a single bit.

Code Block
assert 0x33g.testBit(1)
    //true if bit is 1, indexing beginning at 0 from righthand side
assert ! 0x33g.testBit(2)
(2..100).each{
   assert (-0x3g).testBit(it)
      //negative BigIntegers have virtual infinite sign-extension
}

...

Code Block
def binRepr={n->
   (15..0).inject(''){flo,it->
       flo<< (n.testBit(it)? 1: 0)
   }
}
assert 0x33g.toString(2) == '110011'
assert binRepr(0x33g) as String == '0000000000110011'
assert (-0x33g).toString(2) == '-110011' //not what we want to see
assert binRepr(-0x33g) as String == '1111111111001101'
    //notice the negative sign bit extended virtually

...

Code Block
assert 0x33g.setBit(6) == 0x73g //0x33g is binary 110011
assert 0x33g.clearBit(4) == 0x23g
assert 0x33g.flipBit(1) == 0x31g
assert 0x33g.flipBit(2) == 0x37g

assert 0x1g.getLowestSetBit() == 0
    //index of the rightmost one bit in this BigInteger
assert 0x2g.getLowestSetBit() == 1
assert 0x8g.getLowestSetBit() == 3
assert 0x33g.bitLength() == 6
    //number of bits in minimal representation of number
assert (-0x33g).bitLength() == 6 //exclude sign bit
assert 0x33g.bitCount() == 4 //number of bits that differ from sign bit
assert (-0x33g).bitCount() == 3

...

Code Block
assert 0xB4Fg.shiftLeft( 4 ) == 0xB4F0g 0xB4F0g  //shift 4 bits to the left
assert 0xD23Cg.shiftRight( 4 ) == 0xD23g
    //shift 4 bits to the right, dropping off digits
assert (-0xFFFg).shiftRight( 4 ) == -0x100g
    //sign-extension performed when right-shifting
[ 0xABCg, -0x98765g ].each{
   it.shiftLeft( 8 ) == it.shiftRight( -8 )
}

...

Code Block
assert 123g.not() == -124g //in 2's-complement, negate and add 1
assert -0xFFg.not() == 0x100g

assert ( (0x33g & 0x11g) == 0x11g)   && 0x33g.and(0x11g) == 0x11g
assert ( (0x33g | 0x11g) == 0x33g)   && 0x33g.or(0x11g) == 0x33g
assert ( (0x33g ^ 0x11g) == 0x22g)   && 0x33g.xor(0x11g) == 0x22g
assert 0x33g.andNot(0x11g) == 0x22g && (0x33g & (~ 0x11g)) == 0x22g
    //convenience operation

For negative numbers:

Code Block
assert (-1g & -1g) == -1g //and returns a negative if both operands are negative...
assert (-1g |& -1g) == -1g

//or returns a negative number if either operand is negative...
assert (1g ^| -1g) == -2g1g

//xor returns a negative number if exactly one operand is negative...
assert (1g ^ -1g) == -2g
assert (-1g ^ -2g) == 1g

When the two operands are of different lengths, the sign on the shorter of the two operands is virtually extended prior to the operation:

...