Re: Sorting Puzzle
by imp (Priest) on Feb 20, 2007 at 21:08 UTC
|
The numbers are too large for numeric comparison without using bigint | [reply] |
|
Thank you!
I am creating a numeric sorting key on start/end dates and times. I was originally wanting to convert the times to unix timestamp but could not find a fast way to do that. With the unix timestamp, this would be trivial but require the extra conversion step.
Is there a datetime to unix timestamp function?
| [reply] |
|
Datetime. It also provides sorting. It also provides intervals which sounds like what you're interested in.
Less applicable to the question but more important, imho, is that it handles all the nasty edgecases that any developer who didn't write Datetime shouldn't be bothered to know about handling dates and times. This would include the situations when a minute can have 59 seconds, 61 seconds, and even 62 seconds. (Yes, those situations do exist in really odd circumstances, but it would suck if you accidentally ran into one of them, right?)
My criteria for good software:
- Does it work?
- Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
| [reply] |
|
Time::Piece makes it fairly easy, but you would have to benchmark it against other solutions to see what works for you. How much data are you dealing with?
use Time::Piece;
use strict;
use warnings;
my $date = '20070301103000';
my $start = Time::Piece->strptime($date, "%Y%m%d%H%M%S")->epoch;
print $start, "\n";
| [reply] [d/l] |
Re: Sorting Puzzle
by jdporter (Paladin) on Feb 20, 2007 at 21:11 UTC
|
Hash keys are strings, but you're comparing them as numbers.
Ordinarily, perl would automatically convert to numbers since they're being used in numeric context, but they're too big. So you need to do both of the following:
- use bigint;
- force the strings to numbers by (e.g.) adding to zero. For example:
sort { (0+$a) <=> (0+$b) }
A word spoken in Mind will reach its own level, in the objective world, by its own weight
| [reply] [d/l] [select] |
Re: Sorting Puzzle (just sort)
by tye (Sage) on Feb 20, 2007 at 22:20 UTC
|
Your "numbers" don't appear to be variable-width so just sort w/o specifying any comparison routine and you'll get the desired order:
foreach $j ( sort keys %test ) {
Others have pointed out that your numbers are too big for accurate numeric comparisons in Perl. The notes about avoiding the quotes or hash keys being strings and having to use "0+" to force numeric interpretation make no sense to me, however. $a <=> $b already forces $a and $b to be interpretted as numbers, always.
Your numbers require about 91 bits and Perl usually uses about 53 bits of mantissa for floating point numbers so numeric comparison on these values end up comparing truncated values like 2007030110300020000000000000 instead.
| [reply] [d/l] [select] |
|
$a <=> $b already forces $a and $b to be interpretted as numbers, always.
It doesn't appear to with perl 5.8.2:
use strict;
use warnings;
my $d1 = '2007030110300020070301133000';
my $d2 = '2007030110300020070301143000';
printf "plain = %d\n", ($d1 <=> $d2);
{
use bigint;
printf "bigint = %d\n", ($d1 <=> $d2);
}
{
use bigint;
printf "bigint-0 = %d\n", (($d1 -0)<=> ($d2-0));
}
Output:
plain = 0
bigint = 0
bigint-0 = -1
| [reply] [d/l] [select] |
|
| [reply] |
|
The notes about ... having to use "0+" to force numeric interpretation make no sense to me
I'm not saying it makes sense to me, either. But the perl interpreter don't lie, if you get my drift. You have to do both things (use bigint and manually coerce the numeric conversion) for the numeric comparison to work properly. Try it yourself if you don't believe me.
This is perl, v5.8.8 built for MSWin32-x86-multi-thread
Binary build 819 [267479] provided by ActiveState
Built Aug 29 2006 12:42:41
A word spoken in Mind will reach its own level, in the objective world, by its own weight
| [reply] [d/l] |
|
Tye's statement was correct. Perl does indeed compare the two values numerically, but the magic of bigint is not triggered. The 0+ doesn't force numeric comparison in this case, it triggers bigint magic.
| [reply] |
A reply falls below the community's threshold of quality. You may see it by logging in.
|
|
But why would you recommend bigint rather than Math::BigInt in this case???
| [reply] |
|
|
Re: Sorting Puzzle
by Tanktalus (Canon) on Feb 20, 2007 at 21:10 UTC
|
Just a quick guess - but your numbers are probably too long for perl to do numerical comparisons with.
I thought bigint might help - but you'd have to remove the quotes to get that to work. Otherwise, just change the <=> to cmp to do string comparisons.
| [reply] [d/l] [select] |
Re: Sorting Puzzle
by Moron (Curate) on Feb 22, 2007 at 12:29 UTC
|
For that matter, is there any particular reason for having to use <=>, given that cmp happens do the job properly for reverse-field date data (even though it is numeric!) ?
| [reply] |
Re: Sorting Puzzle
by Anonymous Monk on Feb 21, 2007 at 15:00 UTC
|
What's troubling is that swapping $a and $b give the same results.
done without the {$a<=>$b} properly sorts the keys, as does {$a cmp $b}
I suspect the problem is that the numbers are treated as ascii, I noticed the problem that if treated as strict numbers then the numbers become floats and over-write one another in the hash, if you really need them as numbers then perhaps a conversion to hex would work.
Since looks like dates, can you avoid this and stuff them differently into the hash ? | [reply] |