Is there a feature, function, or situation in Perl where a variable is forced to be an integer and, from then on, all calculations done with that variable will yield an integer result? I'm finding that any calculations I do with one variable always yield integer results.
I'm doing some calculations for interest on a credit line. (I know that sounds like a homework assignment, but it's for investing. I have three different groups that are using the same credit line and I need to keep track of the interest for each one for what comes out of the credit line.)
The problem is, at one point, I call a routine and get a number for a result. It's stored in $gap. Then any calculations I use $gap in will, from then on, always give me an integer as a result instead of a decimal.
I got tired of this issue and tried adding this line:
Once I put that in, all calculations from then on worked fine. No more integer results or rounding.$gap = "$gap.00";
There's a lot of code that is involved (several subroutines) in producing the result for $gap. But all the functions are either substr($gap, $start, $len) or straight and simple addition or subtraction, except I do, at one point, use Time::Local::localtime() to get the ticks time value from a string formatted like yyyy-ddmm.
What can change a variable so from that point on any math done with that variable yields an integer answer? And what does the one line above do to force that to stop?
I made a test program and module to go with it. While doing this, and checking the original modules, I found this in one:use Math::BigInt; use Math::BigInt ':constant';
This seems to be the problem. I don't remember all the details, but I needed it in the module, so I can't just comment it out. I tested it by copying code from the module into the main test program and seeing what would and would not work with those two statements commented out. If they were not there, then I would get non-integer results.
I created the code below, a program (I called it testintegers) and a module (I called it IntTest). Note one line that's commented out - marked with a comment before it containing the text "Removable code #1" to make it easy to find. In this program, note the line:
$mins = tdiff($now, $then);
That's where I call the routine in the module and after that, $mins is not only an integer, but any calculations that use $mins will provide only integer results. If I uncomment the next line of code (the removeable code #1), then after that, I can use $mins and get non-integer results.
What does BigInt do to the variable that forces any future calculations with it yield non-integer answers? Is there some way I can make a change, before returning the value from tdiff (in the module that uses BigInt) to stop this issue? And if not, is there something I can do with the returned value, other than add a ".00" to the end to force it to be treated as a non-integer?
Here's the code from my test program, testintegers:
#!/usr/bin/perl use strict; use IntTest; use Time::Local; my ($mins, $days, $now, $then, $elapsed); ($now, $then) = @ARGV; if (!$now) {$now = "2013-0923";} if (!$then) {$then = "2013-1023";} $mins = tdiff($now, $then); #Removable code #1 # $mins = "$mins.00"; #Gap is the difference in minutes, so change it to days: $days = ($mins / 60) / 24; #Divide by days in a year so it can be used in interest formula $elapsed = $days/365; print "Now: $now, Then: $then, Minutes: $mins, Days: $days, Elapse +d: $elapsed\n";
And here's the module I also created for testing, IntTest:
# package IntTest; #These two lines are the culprit. Without them, it's fine use Math::BigInt; use Math::BigInt ':constant'; use Time::Local; use Exporter; use strict; BEGIN { use vars qw(@ISA); @ISA = qw(Exporter); our @EXPORT = qw(tdiff tconvert); } sub tdiff { my ($now, $then, $diff); ($now, $then) = @_; if (!$then) { $then = $now; $now = tconvert(); } $now = tconvert($now); $then = tconvert($then); $diff = int(($then - $now) / 60); return $diff; } #Take time and dates in the format yyyy-mmdd or yyyy-mmdd-hhmmss #and convert it to ticks sub tconvert { my $start = shift(@_); $start =~ s/-//g; my $year = substr($start, 0, 4); my $month = substr($start, 4, 2); my $day = substr($start, 6, 2); my $hour = substr($start, 8, 2); my $min = substr($start, 10, 2); my $sec = substr($start, 12, 2); $year = $year - 1900; $month--; my $now = timelocal($sec, $min, $hour, $day, $month, $year); return $now; } 1;
I ran these with this command line:
perl -I.. ./testintegers 2013-0923-173422 2013-0923-182819
Note that when you run it, the results printed out are integer, but when the removable line of code is uncommented, the results are non-integer. If this hack will work, I'm okay using it, but from comments here, it seems like it's not a reliable method, so I'd like to find a way to eliminate the problem of getting only integer answers from any math done with the value returned from tdiff. </p?
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |