Perl function for negative integers using the 2's complement
I am trying to convert AD maxpwdAge
(a 64-bit integer) into a number of days.
According to Microsoft:
Uses the IADs interface's
Get
method to retrieve the value of the domain'smaxPwdAge
attribute (line 5).Notice we use the
Set
keyword in VBScript to initialize the variable namedobjMaxPwdAge
—the variable used to store the value returned byGet
. Why is that?When you fetch a 64-bit large integer, ADSI does not return one giant scalar value. Instead, ADSI automatically returns an
IADsLargeInteger
object. You use theIADsLargeInteger
interface'sHighPart
andLowPart
properties to calculate the large integer's value. As you may have guessed,HighPart
gets the high order 32 bits, andLowPart
gets the low order 32 bits. You use the following formula to convertHighPart
andLowPart
to the large integer's value.
The existing code in VBScript from the same page:
Const ONE_HUNDRED_NANOSECOND = .000000100 ' .000000100 is equal to 10^-7 Const SECONDS_IN_DAY = 86400 Set objDomain = GetObject("LDAP://DC=fabrikam,DC=c开发者_Go百科om") ' LINE 4 Set objMaxPwdAge = objDomain.Get("maxPwdAge") ' LINE 5 If objMaxPwdAge.LowPart = 0 Then WScript.Echo "The Maximum Password Age is set to 0 in the " & _ "domain. Therefore, the password does not expire." WScript.Quit Else dblMaxPwdNano = Abs(objMaxPwdAge.HighPart * 2^32 + objMaxPwdAge.LowPart) dblMaxPwdSecs = dblMaxPwdNano * ONE_HUNDRED_NANOSECOND ' LINE 13 dblMaxPwdDays = Int(dblMaxPwdSecs / SECONDS_IN_DAY) ' LINE 14 WScript.Echo "Maximum password age: " & dblMaxPwdDays & " days" End If
How can I do this in Perl?
Endianness may come into this, but you may be able to say
#!/usr/bin/perl
use strict;
use warnings;
my $num = -37_108_517_437_440;
my $binary = sprintf "%064b", $num;
my ($high, $low) = $binary =~ /(.{32})(.{32})/;
$high = oct "0b$high";
$low = oct "0b$low";
my $together = unpack "q", pack "LL", $low, $high;
print "num $num, low $low, high $high, together $together\n";
Am I missing something? As far as I can tell from your question, your problem has nothing at all to do with 2’s complement. As far as I can tell, all you need/want to do is
use Math::BigInt;
use constant MAXPWDAGE_UNIT_PER_SEC => (
1000 # milliseconds
* 1000 # microseconds
* 10 # 100 nanoseconds
);
use constant SECS_PER_DAY => (
24 # hours
* 60 # minutes
* 60 # seconds
);
my $maxpwdage_full = ( Math::BigInt->new( $maxpwdage_highpart ) << 32 ) + $maxpwdage_lowpart;
my $days = $maxpwdage_full / MAXPWDAGE_UNIT_PER_SEC / SECS_PER_DAY;
Note that I deliberately use 2 separate constants, and I divide by them in sequence, because that keeps the divisors smaller than the range of a 32-bit integer. If you want to write this another way and you want it to work correctly on 32-bit perls, you’ll have to keep all the precision issues in mind.
精彩评论