为什么模运算在 Java VS Perl 中给出不同的结果?
Why does modulo operation gives different results in Java VS Perl?
我在 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 结果?
Java 模运算符可以处理浮点类型,并且还具有 属性 如果第一个参数为负数,结果将为负数。
Perl 模运算符仅适用于整数类型,结果始终为正数。
如果您希望 Perl 的行为与 Java 相似,则通过适当的乘法将分数放大为整数,取模,然后除以得到最终结果。手动补偿负号。尽管您自己构建自己的运算符版本可能会更好。
第二种情况:
%
对 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
函数。
This is identical to the C function fmod().
$r = fmod($x, $y);
It returns the remainder $r = $x - $n*$y
, where $n = trunc($x/$y)
. The $r
has the same sign as $x
and magnitude (absolute value) less than the magnitude of $y
.
use POSIX 'fmod';
$m1 = fmod(1, 1000); # 1
$m2 = fmod(0.01, 1000); # 0.01
$m3 = fmod(-1, 1000); # -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
我在 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 结果?
Java 模运算符可以处理浮点类型,并且还具有 属性 如果第一个参数为负数,结果将为负数。
Perl 模运算符仅适用于整数类型,结果始终为正数。
如果您希望 Perl 的行为与 Java 相似,则通过适当的乘法将分数放大为整数,取模,然后除以得到最终结果。手动补偿负号。尽管您自己构建自己的运算符版本可能会更好。
第二种情况:
%
对 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
函数。
This is identical to the C function fmod().
$r = fmod($x, $y);
It returns the remainder
$r = $x - $n*$y
, where$n = trunc($x/$y)
. The$r
has the same sign as$x
and magnitude (absolute value) less than the magnitude of$y
.
use POSIX 'fmod';
$m1 = fmod(1, 1000); # 1
$m2 = fmod(0.01, 1000); # 0.01
$m3 = fmod(-1, 1000); # -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