CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Beginner:
Do Until condition issue

 



amyth
New User

Jun 16, 2016, 7:17 PM

Post #1 of 11 (6584 views)
Do Until condition issue Can't Post

I'm new to Perl and have written a small utility. The purpose of the code is to repeatedly execute the gettimeofday function until I get a second offset by 0.5. So I would like 10.5 not 10.3 or 10.7. For some reason this code simply runs forever.


Code
use Time::HiRes qw(gettimeofday); 

my $t = sprintf('%d.%06d',gettimeofday());

print $t+0, "\n";
my $tint=1000;


do{
my $t = sprintf('%d.%06d',gettimeofday());
my $tint = int(($t-int($t))*10)+0;
print ($tint, "\n");
} until ($tint == 5 );

print $t, "\n";



Laurent_R
Veteran / Moderator

Jun 17, 2016, 12:31 AM

Post #2 of 11 (6580 views)
Re: [amyth] Do Until condition issue [In reply to] Can't Post

$tint is probably never equal to 5. What does the

Code
print ($tint, "\n");

code line print?
Try it with this change:

Code
} until ($tint >= 5 );

(even if that's not what you want in the end, at least it should help you debugging the code).


BillKSmith
Veteran

Jun 17, 2016, 6:53 AM

Post #3 of 11 (6574 views)
Re: [amyth] Do Until condition issue [In reply to] Can't Post

Your problem is with the accuracy of floating point arithmetic (Ref: perldoc -q "long decimal"). Laurent's solution addresses this problem, but fails if the very first value is much greater than 5. You can avoid the problem completely by working with the integer number of microseconds.


Code
use strict; 
use warnings;
use Time::HiRes qw(gettimeofday);

my ($sec, $microsec);
do{
($sec, $microsec) = gettimeofday;
} until $microsec == 500000;
printf "%d.%06d\n", $sec, $microsec;


Depending on your operating system, it may be necessary to use:

Code
} until $microsec >= 500000  and $microsec  < (500000 + $delta);

The value of $delta depends on your requirements. (I think you want to use 100000.
Good Luck,
Bill


amyth
New User

Jun 17, 2016, 3:32 PM

Post #4 of 11 (6565 views)
Re: [Laurent_R] Do Until condition issue [In reply to] Can't Post

The print command prints just the number. no decimals.

I tried >=5. The code now exits even if $tint prints as 4. or 2.

Somehow I think the issue is with the way the condition is being evaluated.


Quote
ts4200:~# ./test.pl
1466202575.66781
6
1466202575.667813
ts4200:~# ./test.pl
1466202578.70864
7
1466202578.708642
ts4200:~# ./test.pl
1466202580.74874
7
1466202580.748745
ts4200:~# ./test.pl
1466202582.41626
4
1466202582.416257
ts4200:~# ./test.pl
1466202584.25627
2
1466202584.256273



amyth
New User

Jun 17, 2016, 3:38 PM

Post #5 of 11 (6565 views)
Re: [BillKSmith] Do Until condition issue [In reply to] Can't Post

This code works. That means that there is some sort of data type issue when I'm running the condition. Any ideas? I'm stumped!


BillKSmith
Veteran

Jun 17, 2016, 9:13 PM

Post #6 of 11 (6560 views)
Re: [amyth] Do Until condition issue [In reply to] Can't Post

Your problem is the precision of floating point numbers. The FAQ that I referred you to may not seem applicable, but read it carefully. It refers you to the definitive article on the subject. (Although it does not require advanced math skills, It is definitely not easy reading)

Perl does not have data types (at least not in the sense of most other languages). All arithmetic is done in floating point. The exact floating point format depends primarily on your hardware.

In general, decimal numbers cannot be represented exactly in floating point. Because of this, it is almost never right to test for equality. (Ok, I did it in my code, but I gave you an alternative if it did not work on your system.) The reason my code does work is that "small" integers values can be represented exactly. The number of microseconds is always an integer less than 10^6.
Good Luck,
Bill


Chris Charley
User

Jun 18, 2016, 9:39 AM

Post #7 of 11 (6545 views)
Re: [amyth] Do Until condition issue [In reply to] Can't Post

One problem I see is you create a new variable $tint within the scope of the loop but the until condition tests against the $tint variable (defined as 1000) created before the loop. The loop condition cannot see the the $tint variable created within the scope of the loop.

Change

my $tint = int(($t-int($t))*10)+0;

to

$tint = int(($t-int($t))*10)+0;

Also, change

my $t = sprintf('%d.%06d',gettimeofday());

to

$t = sprintf('%d.%06d',gettimeofday());

(within the loop)

When I made that change, the loop exited when it equaled 5.


(This post was edited by Chris Charley on Jun 18, 2016, 10:16 AM)


Laurent_R
Veteran / Moderator

Jun 19, 2016, 1:46 AM

Post #8 of 11 (6529 views)
Re: [Chris Charley] Do Until condition issue [In reply to] Can't Post

Very well spotted, Chris. I'm feeling embarrassed that I did not see such a basic mistake.


Chris Charley
User

Jun 19, 2016, 7:19 AM

Post #9 of 11 (6525 views)
Re: [Laurent_R] Do Until condition issue [In reply to] Can't Post

I did not see this at first Laurent. Yes, it was a simple error.


BillKSmith
Veteran

Jun 19, 2016, 4:16 PM

Post #10 of 11 (6511 views)
Re: [Chris Charley] Do Until condition issue [In reply to] Can't Post

Chris, I too am embarrassed by this one. However, the floating point issue has validity. There are marginally enough bits in double precision, but testing for an exact match is risky. Your solution exits at the proper phase, but it could take several seconds to find the match.
Good Luck,
Bill


amyth
New User

Jun 20, 2016, 4:42 PM

Post #11 of 11 (6504 views)
Re: [Chris Charley] Do Until condition issue [In reply to] Can't Post

Thanks Chris. That explains it very clearly!

 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives