为什么模运算在Java VS Perl中会产生不同的结果?

时间:2016-11-03 14:28:33

标签: java perl modulo

我在Java 7中运行它,然后得到:

double remainder1 = 1 % 1000;
double remainder2 = 0.01 % 1000;
double remainder3 = -1 % 1000;

System.out.println("START: "+remainder1+" | "+remainder2+" | "+remainder3);
>>>START: 1.0 | 0.01 | -1.0

但是当我在Perl 5.8.8中运行相同的操作时,我得到了三分之二的不同结果:

my $remainder1 = 1 % 1000;
my $remainder2 = 0.01 % 1000;
my $remainder3 = -1 % 1000;
print "START: $remainder1 | $remainder2 | $remainder3";
>>>START: 1 | 0 | 999

为什么在最后两次计算中存在这样的差异? 如何获得perl以匹配java结果?

3 个答案:

答案 0 :(得分:10)

第二种情况:

  • %在Java中对整数和浮点数进行操作,
  • %仅对Perl中的整数进行操作。

第三种情况:

  • Java定义模数运算,使得以下等式成立:

    dividend == ((int)(dividend/divisor)) * divisor + (dividend % divisor)
    
    e.g. -1 = 0 * 1000 + -1
    
  • Perl定义模数运算,使得以下等式成立:

    $dividend == floor($dividend/$divisor) * divisor + ($dividend % $divisor)
    
    e.g. -1 = -1 * 1000 + 999
    

Perl方式的优势在于商(floor($dividend/$divisor))将始终与被除数具有相同的符号。

要在Perl中获得与Java相同的行为,请使用POSIX::fmod函数。

  

这与C函数fmod()相同。

$r = fmod($x, $y);
  

返回余下的$r = $x - $n*$y,其中$n = trunc($x/$y)$r$x具有相同的符号,并且幅度(绝对值)小于$y的幅度。

use POSIX 'fmod';

$m1 = fmod(1, 1000);     # 1
$m2 = fmod(0.01, 1000);  # 0.01
$m3 = fmod(-1, 1000);    # -1

答案 1 :(得分:6)

Java模运算符可以使用浮点类型,并且还具有如果第一个参数为负则结果为负的属性。

Perl模运算符仅适用于整数类型,结果始终为正。

如果你希望Perl的行为类似于Java,那么使用适当的乘法将分数缩放到整数,取模数,然后除以得到最终结果。手动补偿负号。虽然您最好自己构建自己的操作版本。

答案 2 :(得分:1)

perl

中实现了相同的内容
sub modulo($$) {
        our $num1   = shift;
        our $num2   = shift;
        our $flip   = ( $num1 < 0 ? -1 : 1 ) * ( $num2 < 0 ? -1 : 1 );
        our $power1 = length substr $num1, index $num1, ".";
        our $power2 = length substr $num2, index $num2, ".";
        our $power  = $power1 > $power2 ? $power1 : $power2;
        ( ( abs($num1) * ( 10 ** $power ) ) % ( abs($num2) * ( 10 ** $power ) ) ) * $flip / ( 10 ** $power );
    }

print modulo( 1,    1000 ); # 1
print modulo( 0.01, 1000 ); # 0.01
print modulo( -1,   1000 ); # -1