Groovy numbers are either decimals or integers. The 3 main types of integers are Integer, Long, and BigInteger. BigInteger has no size limit, while Integer and Long do. We can enquire their minimum and maximum values:

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

Integers will normally be the smallest type into which the value will fit (using 2's-complement representation):

assert 110.class == Integer
assert 3000000000.class == Long //value too large for an Integer
assert 10000000000000000000.class == BigInteger //value too large for a Long

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

//base-10 integers, positive or negative...
[ 2, -17, +987 ].each{ assert it }

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

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

We can negate hexadecimals and octals to represent negative numbers.

assert 0x7FFFFFFF.class == Integer
assert (-0x7FFFFFFF).class == Integer //we must negate using the minus sign
assert 0x80000000.class == Long
assert (-0x80000000).class == Integer
assert (-0x80000001).class == Long

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:

assert 42i.class == Integer //lowercase i more readable
assert 123L.class == Long //uppercase L more readable
assert 456g.class == BigInteger
assert 0xFFi.class == Integer

Fixed-Size Integers

The fixed-size integers, Integer and Long, each have size limits but are more efficient in calculations.

There are also the less common Byte and Short types of integer, which act like the Integer type in math operations.

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+b).class == Integer

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

assert Integer.SIZE == 32
assert Long.SIZE == 64
assert Short.SIZE == 16
assert Byte.SIZE == 8

The class Integer can often be written int. The classes Long, Short, and Byte can each also often be written uncapitalized, ie, long, short,  and byte. We can enquire these alternative (aka "primitive type") names:

assert Integer.TYPE == int
assert Long.TYPE == long
assert Short.TYPE == short
assert Byte.TYPE == byte

The fixed-size integer classes can be converted to one another:

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

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

We can create new fixed-sized integers from strings:

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:

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

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

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

//only time result begins with zero is if it is zero...
assert Integer.toString(0) == '0'

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

//second argument defaults to 10...
assert Integer.toString( 29 ) == '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:

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

The common bases have similar methods which always return an unsigned integer:

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'

//same as toString(,16) when number positive...
assert Integer.toHexString(29) == Integer.toString(29,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'

We can convert a string representation to an integer, using a specified base/radix:

assert Integer.parseInt("0", 10) == 0
assert Integer.parseInt("473", 10) == 473
assert Long.parseLong("473", 10) == 473L //Long type 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

A NumberFormatException may be thrown:

[ { 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}
}

An alternative method name is:

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

We can convert a string to a fixed-size integer, similar to parseInt() etc, but with the radix instead indicated inside the string:

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 }

We can return an integer representing the sign:

assert Integer.signum(45i) == 1
assert Integer.signum(0i) == 0
assert Integer.signum(-43i) == -1
assert Long.signum(-43L) == -1

We can compare fixed-size integers with each other:

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:

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

Not all calculations have a special operator symbol:

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

We can increment and decrement variables, using operators, either before and after evaluation:

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

Rules of parentheses and precedence apply to these operators. The operators have the same precedence irrespective of what type of values they operate on.

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

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

Integers often convert their types during math operations. For + - *, a Long with an Integer converts the Integer to a Long:

assert (23i+45L).class == Long

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:

//each 256 is an int, so final product also an int, and calc overflowed...
assert 256*256*256*256 == 0

//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 < <= > >= operators, of lower precedence than addition/etc:

assert 14 > 7          && 14.compareTo(7) > 0
assert 14 >= 8         && 14.compareTo(8) >= 0
assert -4 < 3          && (-4).compareTo(3) < 0
assert -14 <= -9       && (-14).compareTo(-9) <= 0

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

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.

To return an int or long with a single 1-bit in the position of the highest-order 1-bit in the argument:

assert Integer.highestOneBit( 45 ) == 32
assert Integer.highestOneBit( 27 ) == 16
assert Integer.highestOneBit( 0 ) == 0
assert Integer.highestOneBit( -1 ) == -128*256*256*256
assert Long.highestOneBit( -1L ) == -128*256*256*256 * 256*256*256*256

assert Integer.lowestOneBit( 45i ) == 1 //match lowest order 1-bit in argument
assert Integer.lowestOneBit( 46i ) == 2
assert Integer.lowestOneBit( 48i ) == 16

To return the number of zero bits preceding the highest-order 1-bit:

[ 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
}

//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:

def x= 0x33333333i
assert ~x == -x - 1
    //how bitwise complement and negation are related 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.

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

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

//sign-extension performed when right-shifting...
assert -0xFFF>>4 == -0x100     && (-0xFFF).rightShift( 4 ) == -0x100

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

We can rotate the bits in an integer or long:

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

We can perform bitwise 'and', 'or', and 'xor' operations on fixed-size integers. This is of lower precedence than the comparison operators.

assert (0x33 & 0x11) == 0x11 && 0x33.and(0x11) == 0x11
assert (0x33 | 0x11) == 0x33 && 0x33.or(0x11) == 0x33
assert (0x33 ^ 0x11) == 0x22 && 0x33.xor(0x11) == 0x22

We can reverse the bits or bytes of the binary representation of an int or long:

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

Boolean, Conditional, and Assignment Operators with Fixed-Sized Integers

The boolean, conditional, and assignment operators are of even lower precedence than the bitwise operators.

When using an integer with boolean operators !, &&, and ||, 0 evaluates to false, while every other integer evaluates to true:

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 ||

The boolean operators && and || only have their operands evaluated until the final result is known. This affects operands with side effects, such as increment or decrement operators:

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

We can use the conditional operator ?:, of lower precedence than the boolean operators, to choose between two values:

def x= 1? 7: -5
assert x == 7

We can put the assignment operator  = within expressions, but must surround it with parentheses because its precedence is lower than the conditional:

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:

def a = 7
a += 2 //short for a = a + 2
assert a == 9
a += (a = 3) //expands to a = a + (a = 3) before any part is evaluated
assert a == 12

BigIntegers

The BigInteger has arbitrary precision, growing as large as necessary to accommodate the results of an operation.

We can explicitly convert fixed-sized integers to a BigInteger, and vice versa:

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 for target, only lowest order bits returned
assert 200g as byte == -56 //...and this may result in a negative number

A method and some fields that give a little more efficiency:

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

We can construct a BigInteger using an array of bytes:

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

We can convert a BigInteger back to an array of bytes:

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

We can pass in a string in a certain base/radix:

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 }
}

We can convert the BigInteger back to a string:

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

We can construct a randomly-generated BigInteger:

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:

assert 34g.plus( 33g ) == 34g + 33g
assert 34g.add( 33g ) == 34g + 33g //alternative name for plus
assert 34g.minus( 21g ) == 34g - 21g
assert 34g.subtract( 21g ) == 34g - 21g //alternative name for minus
assert 3g.multiply( 31g ) == 3g * 31g
assert 7g.negate() == -7g //unary operation/method
assert (-7g).negate() == 7g

For + - *, a BigInteger causes any fixed-width integers in the calculation to be converted to a BigInteger:

assert (45L + 123g).class == BigInteger
assert (23 - 123g).class == BigInteger
assert ( 3g * 31 ).class == BigInteger
assert ( 3 * 31g ).class == BigInteger
assert 3g.multiply( 31 ).class == BigInteger
assert 3.multiply( 31g ).class == BigInteger

We can introduce a BigInteger into an expression with Integers or Longs if overflow may occur. But make sure the BigInteger is introduced before an intermediate value that may overflow, for example, the first-used value in a calculation:

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 in first value

We can also increment and decrement BigIntegers:

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

We can find out the quotient and remainder:

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

Other methods for arithmetic:

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 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         && 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:

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.

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
}

Unlike with fixed-width integers, BigIntegers don't have a method to show the hex, octal, or binary representation of a negative number. We can use this code instead to look at the first 16 lowest-order virtual bits:

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

More bit-manip methods:

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

Setting, clearing, or flipping bit in virtual sign makes that bit part of the number:

assert (-0x33g).clearBit(9) == -0x233g

We can perform bit-shifting on BigIntegers. The shortcut operators >> and << can't be used, only the method names can be (they're also spelt differently to the fixed-size integer versions of the names, eg, "shiftLeft" instead of "leftShift"). There's no shift-right-unsigned method because this doesn't make sense for BigIntegers with virtual infinite-length sign bits.

assert 0xB4Fg.shiftLeft( 4 ) == 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 )
}

We can perform 'not', 'and', 'or', and 'xor' bitwise operations on BigIntegers:

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:

//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) == -1g

//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:

assert 11g.and(-2g) == 10g //01011 and 11110 is 01010, ie, 10g