Reputation: 1243
I run this in Java 7 and I get:
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:
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?
Upvotes: 8
Views: 575
Reputation: 118605
The second case:
%
operates on integers and floating-point numbers in Java,%
only operates on integers in Perl.The third case:
Java defines the modulus operation such that the following equation is true:
dividend == ((int)(dividend/divisor)) * divisor + (dividend % divisor)
e.g. -1 = 0 * 1000 + -1
Perl defines the modulus operation such that the following equation is true:
$dividend == floor($dividend/$divisor) * divisor + ($dividend % $divisor)
e.g. -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.
To get the same behaviour as Java in Perl, use the POSIX::fmod
function.
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
Upvotes: 11
Reputation: 12817
Implemented the same in 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
Upvotes: 1
Reputation: 234715
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.
The Perl modulo operator is for integer types only and the result is always positive.
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. Compensate for the negative sign manually. Although you might be better off building your own version of the operator yourself.
Upvotes: 6