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

22,659

Solution 1

Given a = qd + r, there is an ambiguity when calculating the remainder for negative values of d.

E.g.:

The expression −42 ÷ −5, can be expressed as either as: −42 = 9×(−5) + 3 or −42 = 8×(−5) + (−2).

So the remainder is then either 3 or −2.

For more info: Wikipedia:Remainder "Inequality satisfied by the remainder"

Also, the output in case of negative numbers in mod / div is implementation dependent in software languages. See Wikipedia: Modulo operation (look at the table on right)

Solution 2

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
Share:
22,659
bugmagnet
Author by

bugmagnet

Software Engineer. Over 20 years experience in user-support and programming. Working full-time as Software Engineer for Daisy Digital. Research assistant / librarian for, and contributor to, the History of Programming Languages (HOPL).

Updated on July 05, 2022

Comments

  • bugmagnet
    bugmagnet almost 2 years

    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?

  • bugmagnet
    bugmagnet about 15 years
    fmod, eh? I stand corrected. Thanks very much for pointing that out.
  • Flimm
    Flimm almost 10 years
    Does anyone know of an alternative such that fmod(-23, 10) returns 7 instead of -3?
  • ysth
    ysth almost 10 years
    just add 10 if it's less than 0?
  • Flimm
    Flimm almost 10 years
    @ysth: that's what I ended up doing, but it would be nice if there was a module somewhere that did this already so I didn't have to include too many helper functions in my code.
  • mctylr
    mctylr almost 10 years
    For the mathematical background, see modular arithmetic and/or abstract (or elementary) algebra.