高效实施GTIN-13算法
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了高效实施GTIN-13算法相关的知识,希望对你有一定的参考价值。
我正在寻找一种有效的方法来实现GTIN-13 check digit algorithm。我查看了一些相关的SO帖子,如this和this,但似乎效率在任何一种情况下都不是关注的主题。
简而言之,算法采用数字字符串(例如123765)并将每隔一个数字(从右到左)乘以1或3来计算总和(所以5 * 1 + 6 * 3 + 7 * 1 + 3 * 3 + 2 * 1 + 1 * 3 = 44
),然后从等于10的最接近的倍数中减去此总和等于或大于这个总和(在这种情况下50 - 44 = 6
)得出最终校验位(这里,6)。输入预计长度为12位,但如果更短,则可以简单地用左边的零填充(所以123765
实际上预期为000000123765
),但结果仍然是相同的。
对此的简单实现如下:
gtin13 <- function(n) {
s <- as.character(n)
check.sum <- 0
for (i in 1:nchar(s)) {
digit <- substr(s, nchar(s) - i + 1, nchar(s) - i + 1)
check.sum <- check.sum + as.numeric(digit) * ifelse(i %% 2, 1, 3)
}
10 - check.sum %% 10
}
但是,由于for循环以及转换为字符串并返回到数字,这是低效的。例如:
df <- data.frame(
num <- sample(1:1000000, 100000, T)
)
system.time(cd <- vapply(df$num, gtin13, 0))
平均桌面大约需要6秒钟。
计算此check.sum的效率更高?
答案
这个版本不需要vapply因此它更快,因为我们不会循环R中可能的数字的数量。例如
gtim13_vec <- function(x) {
d <- x %% 10
for(i in 1:12) { # Input can be up to 12 digits
d <- d +(x%/% 10^i %% 10) * c(1,3)[1+i%%2]
}
d
10-(d%%10)
}
我用set.seed(7)
进行了这个实验。我知道了
system.time(r1 <- vapply(df$num, gtim13, 0))
# user system elapsed
# 3.21 0.00 3.36
system.time(r2 <- gtim13_vec(df$num))
# user system elapsed
# 0.03 0.00 0.03
all(r1==r2)
# [1] TRUE
所以速度有了很大提升。
另一答案
使用Rcpp:
#include <Rcpp.h>
using namespace Rcpp;
int gtim13_cpp(int x) {
int r, sum = 0, coeff = 1;
while (x != 0) {
r = x % 10;
sum += coeff * r;
coeff = 4 - coeff; // 3 <--> 1
x /= 10;
}
return 10 - (sum % 10);
}
// [[Rcpp::export]]
IntegerVector gtim13_all_cpp(IntegerVector x) {
int n = x.size();
IntegerVector res(n);
for (int i = 0; i < n; i++) {
res[i] = gtim13_cpp(x[i]);
}
return res;
}
/*** R
gtim13_all_cpp(123765)
gtin13 <- function(n) {
s <- as.character(n)
check.sum <- 0
for (i in 1:nchar(s)) {
digit <- substr(s, nchar(s) - i + 1, nchar(s) - i + 1)
check.sum <- check.sum + as.numeric(digit) * ifelse(i %% 2, 1, 3)
}
10 - check.sum %% 10
}
df <- data.frame(
num <- sample(1:1000000, 100000, T)
)
system.time(cd <- vapply(df$num, gtin13, 0))
system.time(cd3 <- gtim13_all_cpp(df$num))
all.equal(cd3, cd)
*/
结果:
> system.time(cd <- vapply(df$num, gtin13, 0))
user system elapsed
4.105 0.001 4.105
> system.time(cd3 <- gtim13_all_cpp(df$num))
user system elapsed
0.004 0.000 0.003
> all.equal(cd3, cd)
[1] TRUE
另一答案
我们可以做得更好。如果我们操作整数而不是字符,我们会看到效率的巨大提升:
gtim13Challenger <- function(n) {
n <- as.integer(n)
len <- as.integer(ceiling(log10(n)))
digs <- n %/% as.integer(10^(0L:(len - 1L))) %% 10L
if (len > 1L)
digs[seq.int(2L,len,2L)] <- digs[seq.int(2L,len,2L)] * 3L
10L - sum(digs) %% 10L
}
system.time(cd <- vapply(df$num, gtim13, 0))
user system elapsed
6.15 0.00 6.16
system.time(cd2 <- vapply(df$num, gtim13Challenger, 0L))
user system elapsed
0.76 0.00 0.76
all.equal(cd, cd2)
[1] TRUE
以上是关于高效实施GTIN-13算法的主要内容,如果未能解决你的问题,请参考以下文章