 Think about Loose Coupling PerlMonks

### solving modulo trouble

by Aldebaran (Deacon)
 on Jun 20, 2015 at 20:40 UTC Need Help??

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 (Chancellor) 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 );
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 );

\$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 );
\$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 ) {

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 (Prior) 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.

Create A New User
Node Status?
node history
Node Type: perlquestion [id://1131293]
Approved by planetscape
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others avoiding work at the Monastery: (7)
As of 2020-08-04 22:15 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
Which rocket would you take to Mars?

Results (35 votes). Check out past polls.

Notices?