user14717506
user14717506

Reputation:

Java binary literal: "Long number too large."

So I am writing a chess engine. I have separate method for each piece's moves, which return a long array of size 2, including the long representation of move mask and also attack mask. The problem is that for some reason, when the piece move method generates a long with the index(s) set towards the MSB, my other methods are inconsistent with this input. Here is the code with the example being the knight.

public long[] calculateKnightMoves(int square, long ownSideBitboard,long enemySide, long allPieces){

            /*
    [0, 0, 0, 0, 0, 0, 0, 0]
    [0, 0, 0, 0, 0, 0, 0, 0]
    [0, 0, 0, 2, 0, 3, 0, 0]
    [0, 0, 1, 0, 0, 0, 4, 0]
    [0, 0, 0, 0, x, 0, 0, 0]
    [0, 0, 8, 0, 0, 0, 5, 0]
    [0, 0, 0, 7, 0, 6, 0, 0]
    [0, 0, 0, 0, 0, 0, 0, 0]

     */

    //8 possible moves for a knight, depending on which file you are on. Cannot move into a discovered check for your own king.

    long knightLocation = 1L<<square;

    //checking to see if knight is on a or b file
    long spot1Clip = Lookups.fileTables[0] & Lookups.fileTables[1] & knightLocation;
    //checking to see if knight is on a file
    long spot2Clip = Lookups.fileTables[0] & knightLocation;
    //checking to see if knight is on h file
    long spot3Clip = Lookups.fileTables[Lookups.fileTables.length-2] & knightLocation;
    //checking to see if knight is on g or h file
    long spot4Clip = Lookups.fileTables[3] & Lookups.fileTables[Lookups.fileTables.length-2] & knightLocation;

    long spot5Clip = spot4Clip;
    long spot6Clip = spot3Clip;
    long spot7Clip = spot2Clip;
    long spot8Clip = spot1Clip;

    long spot1 = spot1Clip <<6;
    long spot2 = spot2Clip <<15;
    long spot3 = spot3Clip <<17;
    long spot4 = spot4Clip <<10;

    long spot5 = spot5Clip >> 6;
    long spot6 = spot6Clip >> 15;
    long spot7 = spot7Clip >>17;
    long spot8 = spot8Clip >>10;


    long knightPsuedos = spot1 | spot2 | spot3 | spot4 | spot5 | spot6| spot7 | spot8;
    long knightLegals = knightPsuedos & ~allPieces;
    long knightAttacks = knightPsuedos & enemySide;


    return new long[]{knightLegals,knightAttacks};


}

Say this method return the long of

1000000000000000000000000000000000000000000000000000000000000000

Signifying the knight could attack the upper right corner of the board, some of my methods take this and return null if taking the return long straight from the method. IF i hand type this long into the method, it gives me the error "Long number too large." Here is an example of a method which just returns nulls when passed the long directly from the other method, or throws an error if the long is hand typed in:

public static ArrayList<Integer> indexSetBits(Long bitboard){

    ArrayList<Integer> indices = new ArrayList<>();


    int count =0;
    while(bitboard >0L){
        if((bitboard & 1L) == 1L){
            indices.add(count);

        }
        bitboard >>= 1;
        count++;
    }



    return indices;

}

I get that what I am passing in is too large and is missing the binary literal, by why is it inconsistent and how can I fix it? For example this method works fine with the one example long i put above:

public static void printBitBoard(long pieceBoard) {

    String full = "";
    //String square = rank *8 + file;
    String s = Long.toBinaryString(pieceBoard);

    //System.out.println(64 - Long.toBinaryString(pieceBoard).length());

    if (Long.toBinaryString(pieceBoard).length() == 64) {
        full = Long.toBinaryString(pieceBoard);
        s = full;
    } else {

        full = String.format("%0" + (64 - Long.toBinaryString(pieceBoard).length()) + 'd', 0);
        s = full + "" + s;

    }

    System.out.println(s);


    int[][] board = new int[8][8];
    int p = 0;

    for (int rank = 0; rank < 8; rank++)
        for (int file = 7; file >=0; file--) {
            board[rank][file] = Integer.parseInt(s.substring(p, p + 1));
            p++;
        }


    //prints 2d array representation of the bitboard, making it look like a chessboard.
    for (int[] array : board) {

        System.out.println(Arrays.toString(array));

    }
}

How can I make sure what the method is returning is a binary literal instead of just a long, and why is this error only present in the one method and not the other? Thank you.

Upvotes: 0

Views: 543

Answers (1)

rzwitserloot
rzwitserloot

Reputation: 102953

1000000000000000000000000000000000000000000000000000000000000000

This is clearly written in binary representation. You asked for this, by using Long.toBinaryString(pieceBoard).

When you write this java code:

long x = 1000000000000000000000000000000000000000000000000000000000000000;

it does not compile because java defaults to decimal representation. So that is a much larger number (just like Long.toBinaryString(16) prints 10000).

To fix that, you'd convert that to decimal. Or, better yet, hexadecimal - that is a lot easier to read, and because hexadecimal works in groups of 16, which nicely divides into 2 (as in, binary is base 2, that 2), it's easy to do this. Here is that exact same number, but in hex:

long x = 0x8000000000000000;

And now we have one final problem: all of java's primitive data types, except char, are signed, and numeric. Therefore, 0x8000000000000000 is just a different way to write 9223372036854775808, and that's too large - longs have 64 bits, so can represent 2^64 values (fundamental math), and the long data type is decreed, by the java spec, to represent the numbers from -9223372036854775808 to + 9223372036854775807. (from -2^63 to +2^63-1).

There is no way in java to write a literal like that and ask java to interpret is as a 'sequence of bits, most significant to least significant'. There is only: "Here is a number, interpret it to a bit sequence using 2's complement, and then that is what this literal should resolve to if evaluated'.

In other words, the way to use a literal to represent that bit string you have is, entirely impractical. You'd have to write -9223372036854775808, which is a mystifying number without context.

So, don't. The job of 'I have this stream of bits stated in 1 and 0 symbols, please turn it into a long', cannot be done with literals. It is done with a utility method, just like how you are using Long.toBinaryString:

long x = Long.parseUnsignedLong("1000000000000000000000000000000000000000000000000000000000000000", 2);
System.out.printf("%x\n", x);
System.out.println(x);
System.out.println(Long.toBinaryString(x));

> 8000000000000000
> -9223372036854775808
> 1000000000000000000000000000000000000000000000000000000000000000

Upvotes: 1

Related Questions