简体   繁体   English

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

[英]Why does modulo operation gives different results in Java VS Perl?

I run this in Java 7 and I get: 我在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

But when I run the same operations in Perl 5.8.8 I get different results for two out of three: 但是当我在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

Why is there such a difference in the last two calculations? 为什么在最后两次计算中存在这样的差异? How can I get perl to match java results? 如何让perl匹配java结果?

The second case: 第二种情况:

  • % operates on integers and floating-point numbers in Java, %对Java中的整数和浮点数进行操作,
  • % only operates on integers in Perl. %仅对Perl中的整数进行操作。

The third case: 第三种情况:

  • Java defines the modulus operation such that the following equation is true: Java定义模数运算,使得以下等式成立:

     dividend == ((int)(dividend/divisor)) * divisor + (dividend % divisor) eg -1 = 0 * 1000 + -1 
  • Perl defines the modulus operation such that the following equation is true: Perl定义模数运算,使得以下等式成立:

     $dividend == floor($dividend/$divisor) * divisor + ($dividend % $divisor) eg -1 = -1 * 1000 + 999 

The Perl way has the advantage that the quotient ( floor($dividend/$divisor) ) will always have the same sign as the dividend. Perl方式的优点是商( floor($dividend/$divisor) )将始终与floor($dividend/$divisor)具有相同的符号。


To get the same behaviour as Java in Perl, use the POSIX::fmod function. 要在Perl中获得与Java相同的行为,请使用POSIX::fmod函数。

This is identical to the C function fmod(). 这与C函数fmod()相同。

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

It returns the remainder $r = $x - $n*$y , where $n = trunc($x/$y) . 它返回余数$r = $x - $n*$y ,其中$n = trunc($x/$y) The $r has the same sign as $x and magnitude (absolute value) less than the magnitude of $y . $r$x符号相同,幅度(绝对值)小于$y的幅度。

use POSIX 'fmod';

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

The Java modulo operator can work with floating point types and also has the property that the result will be negative if the first argument is negative. Java模运算符可以使用浮点类型,并且还具有如果第一个参数为负则结果将为负的属性。

The Perl modulo operator is for integer types only and the result is always positive. Perl模运算符仅用于整数类型,结果始终为正数。

If you want the Perl one to behave like the Java one, then scale the fractions up to integers with an appropriate multiplication, take the modulus, and then divide to get the final result. 如果你希望Perl的行为类似于Java,那么使用适当的乘法将分数缩放到整数,取模数,然后除以得到最终结果。 Compensate for the negative sign manually. 手动补偿负号。 Although you might be better off building your own version of the operator yourself. 虽然您最好自己构建自己的操作员版本。

Implemented the same in perl 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM