http://www.perlmonks.org?node_id=1131293

Aldebaran has asked for the wisdom of the Perl Monks concerning the following question:

Hello Monks,

I'm working out the details on my latest script and have hit a snag with results I don't understand from the modulo operator. I could work around it with ordinary division and truncation, but I'm stubborn:

sub second_to_string{ use warnings; use strict; use 5.010; my $seconds = shift; say "seconds are $seconds"; my $hours = $seconds % 3600; say "hours are $hours"; my $remainder = $seconds - $hours *3600; say "remainder is $remainder"; my $return = join('', $hours, 'h '); return $return; }

Output:

seconds are 34640 hours are 2240 remainder is -8029360 equal_ra is 2240h

The correct answer for hours is 9, and the remainder should not be negative. Thanks for your comment.

Replies are listed 'Best First'.
Re: solving modulo trouble
by aaron_baugher (Curate) on Jun 20, 2015 at 21:57 UTC

    In math terms, when you do a division problem, dividing gives you the quotient and taking the modulo gives you the remainder. Here, dividing a number of seconds by 3600 and dropping the decimal gives you the hours. Taking the modulo gives you the remainder of seconds:

    my $s = 7209; # 2 hours and 9 seconds my $hours = int $s/3600; my $seconds = $s % 3600;

    Aaron B.
    Available for small or large Perl jobs and *nix system administration; see my home node.

Re: solving modulo trouble
by hippo (Bishop) on Jun 20, 2015 at 22:03 UTC

    modulo returns the remainder. Try this:

    use warnings; use strict; use 5.010; print 'result is ' . second_to_string (9000) . "\n"; sub second_to_string{ my $seconds = shift; say "seconds are $seconds"; my $hours = int ($seconds / 3600); say "hours are $hours"; my $remainder = $seconds % 3600; say "remainder is $remainder"; my $return = join('', $hours, 'h '); return $return; }

      Thanks, hippo, I knew I got it backwards 60 seconds after I posted. With your help, my script for determining when jupiter and venus conjoin is shaping up:

      #! /usr/bin/perl use warnings; use strict; use 5.010; use WWW::Mechanize::GZip; use HTML::TableExtract qw(tree); use open ':std', OUT => ':utf8'; use Prompt::Timeout; use constant TIMEOUT => 3; use constant MAXTRIES => 8; my $site = 'http://www.fourmilab.ch/yoursky/cities.html'; my $mech = 'WWW::Mechanize::GZip'->new; $mech->get($site); $mech->follow_link( text => 'Portland OR' ); my $lub = 2457204.63659; #least upper bound my $glb = 2457207.63659; #greatest lower bound $mech->set_fields(qw'date 2'); my $guess = median( $lub, $glb ); say "guess is $guess"; $mech->set_fields( jd => $guess ); $mech->click_button( value => "Update" ); my $te = 'HTML::TableExtract'->new; $te->parse( $mech->content ); my $table = ( $te->tables )[3]; my $table_tree = $table->tree; my $venus = $table_tree->cell( 4, 1 )->as_text; say "say venus is *$venus*"; my $jupiter = $table_tree->cell( 7, 1 )->as_text; $te->delete; say "say jupiter is *$jupiter*"; my $vstr = string_to_second($venus); my $jstr = string_to_second($jupiter); say "vstr is $vstr"; say "jstr is $jstr"; my $upper = $lub; my $lower = $glb; my $equal; my $equal_sec; my $now_string = localtime; my $filename = 'planet1.txt'; open( my $jh, '>>', $filename ) or warn "Could not open file '$filenam +e' $!"; say $jh " venus jupiter jd $now_string"; my $attempts = 1; while ( ( abs( $jstr - $vstr ) gt 0 ) ) { #wait 5 secs my $default = (($attempts ge MAXTRIES)) ? 'N' : 'Y'; my $answer = prompt( "Make query number $attempts?", $default, TIMEO +UT ); exit if $answer =~ /^N/i; $guess = median( $upper, $lower ); say "guess is $guess"; $mech->set_fields( jd => $guess ); $mech->click_button( value => "Update" ); #say $mech->dump_forms; $te = 'HTML::TableExtract'->new; $te->parse( $mech->content ); $table = ( $te->tables )[3]; $table_tree = $table->tree; $venus = $table_tree->cell( 4, 1 )->as_text; say "say venus is *$venus*"; $jupiter = $table_tree->cell( 7, 1 )->as_text; say "say jupiter is *$jupiter*"; $vstr = string_to_second($venus); say "vstr is $vstr"; $jstr = string_to_second($jupiter); say "jstr is $jstr"; say $jh " $vstr $jstr $guess "; if ( $jstr gt $vstr ) { $upper = $guess; } elsif ( $vstr gt $jstr ) { $lower = $guess; } else { $equal = $guess; say "equal, while condition should fail $equal"; $equal_sec = $vstr; } $te->delete; $attempts++; } my $equal_ra = second_to_string($equal_sec); say "equal_ra is $equal_ra"; say $jh "equal seconds is $equal_sec and equal ra is $equal_ra"; sub median { my ( $upper, $lower ) = @_; my $return = ( $upper + $lower ) / 2.0; return $return; } sub string_to_second { my $string = shift; my $return = 9000; if ( my $success = $string =~ /^(\d*)h\s+(\d*)m\s+(\d*)s$/ ) { #say "success is $success"; say " $1 $2 $3"; $return = 3600 * $1 + 60 * $2 + $3; } else { say "string was misformed"; } return $return; } sub second_to_string { my $seconds = shift; say "seconds are $seconds"; my $hours = int( $seconds / 3600 ); say "hours are $hours"; my $remainder = $seconds % 3600; say "remainder is $remainder"; my $minutes = int( $remainder / 60 ); say "minutes are $minutes"; my $sec = $remainder % 60; my $return = join( '', $hours, 'h ', $minutes, 'm ', $sec, 's' ); return $return; }

      Output to planet1.txt:

      venus jupiter jd Sat Jun 20 17:16:37 2015 34790 34686 2457206.13659 34682 34653 2457205.38659 34628 34636 2457205.01159 34655 34644 2457205.19909 34641 34640 2457205.10534 34634 34638 2457205.058465 34638 34639 2457205.0819025 34640 34640 2457205.09362125 equal seconds is 34640 and equal ra is 9h 37m 20s

      Always fishing for criticism on form and style.

        Hello Datz_cozee75,

        Always fishing for criticism on form and style.

        I notice that in 4 places you use a stringwise relational (i.e., comparison) operator (gt or ge) to compare numeric (actually, integer) values. It’s better to use the numeric relational operators for this:

        • while ( ( abs( $jstr - $vstr ) > 0 ) ) {
        • my $default = (($attempts >= MAXTRIES)) ? 'N' : 'Y';
        • if ( $jstr > $vstr ) {
        • elsif ( $vstr > $jstr ) {

        See perlop#Relational-Operators.

        Hope that helps,

        Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

        Hi Datz_cozee75,

        in these code lines:

        open( my $jh, '>>', $filename ) or warn "Could not open file '$filenam +e' $!"; say $jh " venus jupiter jd $now_string";
        you only warn if the file could be opened, and, immediately after (and in some other places as well), you try to print to that file handle. I would suggest that a failure to open a file where you want to write is probably a severe enough error for you to want the program to die rather than simply warn.

        Only my two cents...

Re: solving modulo trouble
by pme (Monsignor) on Jun 20, 2015 at 20:50 UTC
    In according to perlop:
    Binary "%" is the modulo operator, which computes the division remaind +er of its first argument with respect to its second argument.
Re: solving modulo trouble
by aartist (Pilgrim) on Jun 20, 2015 at 21:57 UTC
    Look at perldoc perlop. Binary "/" divides two numbers.