【问题标题】:Java binary literal: "Long number too large."Java 二进制文字:“Long number too large”。
【发布时间】:2021-06-19 14:47:36
【问题描述】:

所以我正在编写一个国际象棋引擎。我对每个棋子的移动都有单独的方法,它返回一个大小为 2 的长数组,包括移动掩码的长表示和攻击掩码。问题是,由于某种原因,当块移动方法生成一个 long 并且索引设置为 MSB 时,我的其他方法与此输入不一致。这是以骑士为例的代码。

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


}

说这个方法返回long of

1000000000000000000000000000000000000000000000000000000000000000

表示马可以攻击棋盘的右上角,我的一些方法采用这个并返回null,如果直接从该方法返回。如果我在方法中手动输入这么长,它会给我错误“Long number too large”。这是一个方法的示例,当直接从另一个方法传递 long 时只返回空值,或者如果手动输入 long 则抛出错误:

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;

}

我知道我传入的内容太大并且缺少二进制文字,为什么它不一致,我该如何解决?例如,这种方法适用于我上面放的一个例子:

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

    }
}

如何确定方法返回的是二进制文字而不是 long,为什么这个错误只出现在一个方法中而不出现在另一个方法中?谢谢。

【问题讨论】:

  • Java 8 引入了Unsigned arithmetic。看看有没有帮助?
  • 您必须将文字标记为二进制和长:0xb1000000000000000000000000000000000000000000000000000000000000000L
  • @ NomadMaker - 我实际上以为我在我的 cmets 中提到了前导“b”和尾随“L”。但是当我看的时候,他们不在那里 :( 无论如何 - 这基本上是 OP 的全部问题:不正确的二进制文字语法。谢谢你提到它!

标签: java binary bit-manipulation long-integer


【解决方案1】:

1000000000000000000000000000000000000000000000000000000000000000

这清楚地写在二进制表示。您使用 Long.toBinaryString(pieceBoard) 提出了这个要求。

当你编写这个 java 代码时:

long x = 1000000000000000000000000000000000000000000000000000000000000000;

它无法编译,因为 java 默认使用十进制表示。所以这是一个很多更大的数字(就像Long.toBinaryString(16) 打印10000)。

要解决这个问题,您需要将其转换为十进制。或者,更好的是,十六进制 - 这更容易阅读,并且因为十六进制以 16 个为一组工作,很好地分为 2(例如,二进制是基数 2,即 2),所以很容易做到这一点。这是完全相同的数字,但是是十六进制的:

long x = 0x8000000000000000;

现在我们有最后一个问题:所有java的原始数据类型,除了char,都是signednumeric。因此,0x8000000000000000 只是编写 9223372036854775808 的另一种方式,它太大了——long 有 64 位,因此可以表示 2^64 个值(基本数学),并且 long 数据类型是由 java 规范规定的, 表示从 -9223372036854775808 到 + 9223372036854775807 的数字。(从 -2^63 到 +2^63-1)。

在 java 中没有办法编写这样的文字并要求 java 将其解释为“位序列,从最高有效到最低有效”。只有:“这是一个数字,使用 2 的补码将其解释为位序列,然后这就是该文字在评估时应解析的内容”。

换句话说,使用文字来表示您拥有的位串的方式是完全不切实际的。你必须写 -9223372036854775808,这是一个没有上下文的神秘数字。

所以,不要。 “我有这个用 1 和 0 符号表示的比特流,请把它变成一个长整数”的工作,不能用文字来完成。它是通过实用方法完成的,就像您使用 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-08
    • 1970-01-01
    • 2013-03-05
    • 1970-01-01
    相关资源
    最近更新 更多