How do you calculate div and mod of floating point numbers?

bugmagnet picture bugmagnet · Jan 30, 2009 · Viewed 22.1k times · Source

In Perl, the % operator seems to assume integers. For instance:

sub foo {
    my $n1 = shift;
    my $n2 = shift;
    print "perl's mod=" . $n1 % $n2, "\n";
    my $res = $n1 / $n2;
    my $t = int($res);
    print "my div=$t", "\n";
    $res = $res - $t;
    $res = $res * $n2;
    print "my mod=" . $res . "\n\n";
}   

foo( 3044.952963, 7.1 );
foo( 3044.952963, -7.1 );
foo( -3044.952963, 7.1 );
foo( -3044.952963, -7.1 );

gives

perl's mod=6
my div=428
my mod=6.15296300000033

perl's mod=-1
my div=-428
my mod=6.15296300000033

perl's mod=1
my div=-428
my mod=-6.15296300000033

perl's mod=-6
my div=428
my mod=-6.15296300000033

Now as you can see, I've come up with a "solution" already for calculating div and mod. However, what I don't understand is what effect the sign of each argument should have on the result. Wouldn't the div always be positive, being the number of times n2 fits into n1? How's the arithmetic supposed to work in this situation?

Answer

ysth picture ysth · Feb 1, 2009

The title asks one question, the body another. To answer the title question, just as in C, the % operator is an integer modulus, but there's a library routine "fmod" that's a floating point modulus.

use POSIX "fmod";

sub foo {
    my $n1 = shift;
    my $n2 = shift;
    print "perl's fmod=" . fmod($n1,$n2), "\n";
    my $res = $n1 / $n2;
    my $t = int($res);
    print "my div=$t", "\n";
    $res = $res - $t;
    $res = $res * $n2;
    print "my mod=" . $res . "\n\n";
}

foo( 3044.952963, 7.1 );
foo( 3044.952963, -7.1 );
foo( -3044.952963, 7.1 );
foo( -3044.952963, -7.1 );

gives

perl's fmod=6.15296300000033
my div=428
my mod=6.15296300000033

perl's fmod=6.15296300000033
my div=-428
my mod=6.15296300000033

perl's fmod=-6.15296300000033
my div=-428
my mod=-6.15296300000033

perl's fmod=-6.15296300000033
my div=428
my mod=-6.15296300000033