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






