Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java中的Luhn校验和验证_Java_Algorithm - Fatal编程技术网

Java中的Luhn校验和验证

Java中的Luhn校验和验证,java,algorithm,Java,Algorithm,我必须在Java中复制luhn算法,我面临的问题是如何以高效、优雅的方式实现这一点,这不是一个要求,而是我想要的 luhn算法的工作原理如下: 你要一个数字,比如说56789 循环下一步,直到没有剩余的数字 您选择最左边的数字并将其添加到总和中。总和=5 您放弃这个数字,然后转到下一个数字。数字=6789 你把这个数字加倍,如果超过一个数字,你就把这个数字分开,分别加到总和上。2*6=12,所以求和=5+1=6,然后求和=6+2=8。 附加限制 对于这个特殊的问题,我被要求一次读取一个数字,并在

我必须在Java中复制luhn算法,我面临的问题是如何以高效、优雅的方式实现这一点,这不是一个要求,而是我想要的

luhn算法的工作原理如下: 你要一个数字,比如说56789 循环下一步,直到没有剩余的数字

您选择最左边的数字并将其添加到总和中。总和=5 您放弃这个数字,然后转到下一个数字。数字=6789 你把这个数字加倍,如果超过一个数字,你就把这个数字分开,分别加到总和上。2*6=12,所以求和=5+1=6,然后求和=6+2=8。 附加限制 对于这个特殊的问题,我被要求一次读取一个数字,并在继续之前分别对每个数字进行计算。我还假设所有数字都是正数

我面临的问题和我的问题 如前所述,我试图以一种优雅而有效的方式解决这个问题。这就是为什么我不想对数字调用toString方法来访问所有需要大量转换的单个数字。我也不能用模的方式,因为上面的限制,一旦我读到一个数字,我也应该马上对它进行计算。我只能在事先知道字符串长度的情况下使用模,但这感觉就像我首先必须对所有数字进行一次计数,这是违反限制的。现在我只能想到一种方法,但这也需要大量计算,而且只关心第一个数字*:

int firstDigit(int x) {
    while (x > 9) {
        x /= 10;
    }
    return x;
}
可在此处找到:

*然而,当我思考这个问题时,这基本上是一种不同且奇怪的方法,通过将一个数字除以一个数字,来利用它的长度属性

所以基本上我现在被卡住了,我想我必须使用一个数字的长度属性,它实际上没有,所以我应该手工找到它。有什么好办法吗?现在我想我应该把模和数的长度结合起来。 这样我就知道总位数是不均匀的还是偶数的,然后我就可以从右到左进行计算了。只是为了好玩,我想我可以用这个来提高效率,得到一个数字的长度:


这个问题出现在《像程序员一样思考》一书中。

你可以通过展开循环一次或多次来优化它。如果你喜欢,这将使大数字的速度接近两倍,但会使小数字变慢。如果你有一个典型的数字范围的想法,你将有你可以决定多少展开这个循环

int firstDigit(int x) {
    while (x > 99)
        x /= 100;
    if (x > 9) 
        x /= 10;
    return x;
}

您可以通过展开循环一次或多次来优化它。这样,对于大数字,速度将接近两倍,但会使小数字变慢。如果你有一个典型的数字范围的想法,你将有你可以决定多少展开这个循环

int firstDigit(int x) {
    while (x > 99)
        x /= 100;
    if (x > 9) 
        x /= 10;
    return x;
}

据我所知,您最终需要读取每个数字,因此将初始数字转换为字符串并因此转换为char[]有什么问题,然后您可以轻松实现迭代该char数组的算法

Integer.toString的JDK实现是相当优化的,因此您需要实现自己的优化,例如,它使用不同的查找表进行优化转换,一次转换两个字符等

final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
                                  99999999, 999999999, Integer.MAX_VALUE };

// Requires positive x
static int stringSize(int x) {
    for (int i=0; ; i++)
        if (x <= sizeTable[i])
            return i+1;
}

这只是一个示例,但请随意检查完整的实现:

据我所知,您最终需要读取每个数字,因此将初始数字转换为字符串并因此转换为char[]有什么问题,然后您可以轻松实现迭代该char数组的算法

Integer.toString的JDK实现是相当优化的,因此您需要实现自己的优化,例如,它使用不同的查找表进行优化转换,一次转换两个字符等

final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
                                  99999999, 999999999, Integer.MAX_VALUE };

// Requires positive x
static int stringSize(int x) {
    for (int i=0; ; i++)
        if (x <= sizeTable[i])
            return i+1;
}

这只是一个示例,但请随意检查完整的实现:

通常,您将使用除10来移动数字,并使用模10来提取最后一个数字,从右到左处理数字。在从左到右处理数字时,仍然可以使用此技术。只需使用“除以100000000”提取第一个数字,然后乘以10将其左移:

0000056789
0000567890
0005678900
0056789000
0567890000
5678900000
6789000000
7890000000
8900000000
9000000000
其中一些数字超过了int的最大值。如果必须支持全范围输入,则必须将数字存储为:

static int checksum(int x) {
    long n = x;
    int sum = 0;
    while (n != 0) {
        long d = 1000000000l;
        int digit = (int) (n / d);
        n %= d;
        n *= 10l;
        // add digit to sum
    }
    return sum;
}

通常情况下,您将使用除10来移动数字,并使用模10来提取最后一个数字,从而从右向左处理数字。在从左到右处理数字时,仍然可以使用此技术。只需使用“除以100000000”提取第一个数字,然后乘以10将其左移:

0000056789
0000567890
0005678900
0056789000
0567890000
5678900000
6789000000
7890000000
8900000000
9000000000
其中一些数字超过了int的最大值。如果必须支持全范围输入,则必须将数字存储为:

static int checksum(int x) {
    long n = x;
    int sum = 0;
    while (n != 0) {
        long d = 1000000000l;
        int digit = (int) (n / d);
        n %= d;
        n *= 10l;
        // add digit to sum
    }
    return sum;
}

我首先将数字转换成一种BCD二进制编码的十进制数。我不确定是否能够找到比 JDK Integer.toString转换方法,但正如您所说,您不想使用它:

List<Byte> bcd(int i) {
    List<Byte> l = new ArrayList<Byte>(10);  // max size for an integer to avoid reallocations
    if (i == 0) {
        l.add((byte) i);
    }
    else {
        while (i != 0) {
            l.add((byte) (i % 10));
            i = i / 10;
        }
    }
    return l;
}
这或多或少是你们想要得到的第一个数字,但现在你们在一次传递中得到了所有的数字,并且可以将它们用于你们的算法


我建议使用byte,因为它已经足够了,但由于java总是转换为int来进行计算,因此直接使用列表可能更有效,即使它确实浪费内存。

我会首先将数字转换为一种BCD二进制编码的十进制数。我不确定是否能够找到比JDK Integer.toString转换方法更好的优化方法,但正如您所说,您不想使用它:

List<Byte> bcd(int i) {
    List<Byte> l = new ArrayList<Byte>(10);  // max size for an integer to avoid reallocations
    if (i == 0) {
        l.add((byte) i);
    }
    else {
        while (i != 0) {
            l.add((byte) (i % 10));
            i = i / 10;
        }
    }
    return l;
}
这或多或少是你们想要得到的第一个数字,但现在你们在一次传递中得到了所有的数字,并且可以将它们用于你们的算法

我建议使用byte,因为它已经足够了,但由于java总是转换为int来进行计算,因此直接使用列表可能更有效,即使它确实浪费内存。

使用org.apache.commons.validator.routines.checkdigit.LuhnCheckDigit。有效

Maven依赖项:

使用org.apache.commons.validator.routines.checkdigit.LuhnCheckDigit。有效

Maven依赖项:

似乎不是这样的:加倍或不加倍从最低有效数字开始。附加限制…在继续之前分别进行一次计算,读起来更流畅,因为附加限制…在继续之前分别对每个数字进行计算。-严格遵守这些限制怎么样?交替累加数字本身及其预折叠的双精度0246813579。似乎不是这样工作的:加倍或不加倍从最低有效数字开始。附加限制…在继续之前分别进行一次计算,读起来更流畅,因为附加限制…在继续之前分别对每个数字进行计算。-严格遵守这些限制怎么样?交替累加数字本身及其预折叠的双精度0246813579。在继续之前,它不会逐个进行计算。在继续之前,它不会逐个进行计算。