【问题标题】:Perl Checksum Calculation Migration to JavaPerl 校验和计算迁移到 Java
【发布时间】:2021-07-04 14:43:01
【问题描述】:

我的任务是将 Perl 程序迁移到 java。

我遇到了一些麻烦,Perl 中有一个函数可以计算校验和

sub ComputeChecksum  {
   my ($val) = @_;

   $value= 0;
   $multiplier = 1;

   $dlength=length($val);
   for($i=0; $i<$dlength; $i++) {
      $ival=ord(substr($val, $i, 1));
      $ival*=$multiplier;
      $value+=$ival/100000;
      $value+=$ival%100000;
      $multiplier%=2;
      $multiplier++;
   }
   $value%=100000;
   $value=(100000-$value)%100000;
   return ($value);
}

我将这段代码翻译成java,如下所示

private static long computeCheckSum(String id){
    long value = 0;
    long multiplier = 1;

    int dlength = id.length();

    for(int i=0; i< dlength; i++){
        int ival = id.charAt(i);
        ival *= multiplier;
        value += ival/100000;
        value += ival%100000;
        multiplier %= 2;
        multiplier++;
    }
    value %= 100000;
    value = ((100000-value)%100000);

    return value;
}

但是我在验证数据库中的旧数据时遇到了一个问题,大约 5% 的时间在 java 中计算的校验和与之前 Perl 计算的校验和不匹配,并且错过了 1。

这里有一些旧数据的例子和java中的结果

                                 Perl    Java
ff08ccfba8ad417db2857fc8933788af:96410 / 96409
ff163b2b2e3ef18265d08cc8965b864d:96533 / 96532
ff3848ff301b534b609148af93b2c9ce:96626 / 96625
ff48ec78ea190f44233c9050fd73137d:96631 / 96630
ff62234601e28e6f5d7ff89d95afbec0:96424 / 96423
ff78f4cabe5a565a1cdf11f752f13654:96495 / 96494
ff89dc6b86a535ef265727af90a9b6b3:96596 / 96595
ff98337de5eb9e60f1db51dbd14a4dd2:96366 / 96365
fff76022c6f9f7794793141a9f2a00d2:96813 / 96812

在这些集合中,第一部分是数据库中的数据,由 uid、分号和 Perl 计算的校验和组成,这就是数据在数据库中的保存方式。

为了比较,我添加了斜线和我的 java 代码使用 uid 部分计算的结果。

谁能指出我为什么会发生这种情况的正确方向? 我需要能够在 100% 的时间内计算出正确的校验和。

================================================ ========================

更新:

我更改了我的 java 代码,以浮点数而不是 int 进行所有计算,结果更有趣,差异在同一组 uid 中,但不是生成 1 的差异,而是相差2。

我正在考虑重新计算所有 UID 的校验和,并更新所有受影响的表。

【问题讨论】:

  • 我测试了你所有的字符串,并在 java 中得到了与在 perl 中相同的结果。顺便说一句,为什么不使用标准校验和函数?
  • 数据库是否包含任何非ASCII字符?在 32..126 之外是
  • 尝试通过一次删除一个字符将每个失败案例减少到显示失败的最小字符串。看看边界是否有图案
  • @TedLyngmo 我是新来的,编写此代码的人被解雇了,现在我负责将此代码重构为 java,但保持功能正常工作。并且需要校验和,所以我可以检索记录,因为我的输入只是 uid
  • @ThorbjørnRavnAndersen 无,所有字符都是 ascii

标签: java perl checksum


【解决方案1】:

ff08ccfba8ad417db2857fc8933788af 打印$ival/100000 会得到以下结果:

0.00102
0.00204
0.00048
0.00112
...

我不知道Java程序中除法是否是整数除法,但无论哪种方式都等于加零。这是不同的。

顺便说一句,我怀疑 Perl 程序有问题。我怀疑需要整数除法 (int($ival/100000)),但意外使用了浮点除法。

也就是说,对于您提供的数字,差异似乎不足以产生结果,即使用int($ival/100000) 产生与$ival/100000 相同的结果。显然还有另一个区别。


...或者有吗?添加

while (<DATA>) {
   chomp;
   say $_, ":", ComputeChecksum($_);
}

__DATA__
ff08ccfba8ad417db2857fc8933788af
ff163b2b2e3ef18265d08cc8965b864d
ff3848ff301b534b609148af93b2c9ce
ff48ec78ea190f44233c9050fd73137d
ff62234601e28e6f5d7ff89d95afbec0
ff78f4cabe5a565a1cdf11f752f13654
ff89dc6b86a535ef265727af90a9b6b3
ff98337de5eb9e60f1db51dbd14a4dd2
fff76022c6f9f7794793141a9f2a00d2

我明白你所说的是 Java 结果(即使是$ival/100000):

ff08ccfba8ad417db2857fc8933788af:96409
ff163b2b2e3ef18265d08cc8965b864d:96532
ff3848ff301b534b609148af93b2c9ce:96625
ff48ec78ea190f44233c9050fd73137d:96630
ff62234601e28e6f5d7ff89d95afbec0:96423
ff78f4cabe5a565a1cdf11f752f13654:96494
ff89dc6b86a535ef265727af90a9b6b3:96595
ff98337de5eb9e60f1db51dbd14a4dd2:96365
fff76022c6f9f7794793141a9f2a00d2:96812

【讨论】:

  • 因为两个参数在 Java 中都是 ints,所以它是整数除法。不错的收获。
  • @ThorbjørnRavnAndersen 我也很怀疑。但即使它是 FP div,结果也会被截断,因为它添加到 long。问题发生在任何一种方式
猜你喜欢
  • 2015-05-16
  • 2016-04-13
  • 2017-11-26
  • 1970-01-01
  • 2018-12-11
  • 2010-12-01
  • 2015-12-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多