Bin to dec fractional part in perl - perl

Is there any internal function in Perl to convert binary number with fractional part into decimal? I know how to convert integer numbers but what about numbers with a decimal point?
e.g. 1010.1012 = 10.62510

No, there's no builtin that does this.
However, it's easy to calculate. 1010.1012 is simply 10101012 / 23, so
Remove the ".".
Convert the resulting integer.
Divide by 2**$decimal_places.
Or you could do the conversion yourself. 1010.1012 is
1 * 2**3
0 * 2**2
1 * 2**1
0 * 2**0
.
1 * 2**(-1)
0 * 2**(-2)
+ 1 * 2**(-3)
--------------
10.625

Related

Swift scientific notation in base 16

I'm new in Swift language and playing with it. I know in most languages 1.5e3 means 1.5 * 10 ^3 and this is true in Swift. However, when it comes base 16, I have difficulty in understanding it. Below are 2 examples, hope someone can explain what they are:
println(0x12e3)
println(0x12p3)
The results are:
4835
144.0
The first example is not using scientific notation - because e is a valid digit in hexadecimal, this is the number 12E3, which is 4835 in decimal.
(1 * 4096) + (2 * 256) + (14 * 16) + (3 * 1) = 4835
The second example is the hex number 12 (18 in decimal) multiplied by a binary exponent (2 ^ 3), i.e. 8.
8 x 18 = 144
This notation is described in the Swift language documentation.

Maximum integer in Perl

Set $i=0 and do ++$i while it increases. Which number we would reach?
Note that it may be not the same as maximum integer in Perl (as asked in the title), because there may be gaps between adjacent integers which are greater than 1.
"Integer" can refer to a family of data types (int16_t, uint32_t, etc). There's no gap in the numbers these can represent.
"Integer" can also refer to numbers without a fractional component, regardless of the type of the variable used to store it. ++ will seamlessly transition between data types, so this is what's relevant to this question.
Floating point numbers can store integers in this sense, and it's possible to store very large numbers as floats without being able to add one to them. The reason for this is that floating pointer numbers are stored using the following form:
[+/-]1._____..._____ * 2**____
For example, let's say the mantissa of your floats can store 52 bits after the decimal, and you want to add 1 to 2**53.
__52 bits__
/ \
1.00000...00000 * 2**53 Large power of two
+ 1.00000...00000 * 2**0 1
--------------------------
1.00000...00000 * 2**53
+ 0.00000...000001 * 2**53 Normalized exponents
--------------------------
1.00000...00000 * 2**53
+ 0.00000...00000 * 2**53 What we really get due to limited number of bits
--------------------------
1.00000...00000 * 2**53 Original large power of two
So it is possible to hit a gap when using floating point numbers. However, you started with a number stored as signed integer.
$ perl -MB=svref_2object,SVf_IVisUV,SVf_NOK -e'
$i = 0;
$sv = svref_2object(\$i);
print $sv->FLAGS & SVf_NOK ? "NV\n" # Float
: $sv->FLAGS & SVf_IVisUV ? "UV\n" # Unsigned int
: "IV\n"; # Signed int
'
IV
++$i will leave the number as a signed integer value ("IV") until it cannot anymore. At that point, it will start using an unsigned integer values ("UV").
$ perl -MConfig -MB=svref_2object,SVf_IVisUV,SVf_NOK -e'
$i = hex("7F".("FF"x($Config{ivsize}-2))."FD");
$sv = svref_2object(\$i);
for (1..4) {
++$i;
printf $sv->FLAGS & SVf_NOK ? "NV %.0f\n"
: $sv->FLAGS & SVf_IVisUV ? "UV %u\n"
: "IV %d\n", $i;
}
'
IV 2147483646
IV 2147483647 <-- 2**31 - 1 Largest IV
UV 2147483648
UV 2147483649
or
IV 9223372036854775806
IV 9223372036854775807 <-- 2**63 - 1 Largest IV
UV 9223372036854775808
UV 9223372036854775809
Still no gap because no floating point numbers have been used yet. But Perl will eventually use floating point numbers ("NV") because they have a far larger range than integers. ++$i will switch to using a floating point number when it runs out of unsigned integers.
When that happens depends on your build of Perl. Not all builds of Perl have the same integer and floating point number sizes.
On one machine:
$ perl -V:[in]vsize
ivsize='4'; # 32-bit integers
nvsize='8'; # 64-bit floats
On another:
$ perl -V:[in]vsize
ivsize='8'; # 64-bit integers
nvsize='8'; # 64-bit floats
On a system where nvsize is larger than ivsize
On these systems, the first gap will happen above the largest unsigned integer. If your system uses IEEE double-precision floats, your floats have 53-bit of precision. They can represent without loss all integers from -253 to 253 (inclusive). ++ will fail to increment beyond that.
$ perl -MConfig -MB=svref_2object,SVf_IVisUV,SVf_NOK -e'
$i = eval($Config{nv_overflows_integers_at}) - 3;
$sv = svref_2object(\$i);
for (1..4) {
++$i;
printf $sv->FLAGS & SVf_NOK ? "NV %.0f\n"
: $sv->FLAGS & SVf_IVisUV ? "UV %u\n"
: "IV %d\n", $i;
}
'
NV 9007199254740990
NV 9007199254740991
NV 9007199254740992 <-- 2**53 Requires 1 bit of precision as a float
NV 9007199254740992 <-- 2**53 + 1 Requires 54 bits of precision as a float
but only 53 are available.
On a system where nvsize is no larger than ivsize
On these systems, the first gap will happen before the largest unsigned integer. Switching to floating pointer numbers will allow you to go one further (a large power of two), but that's it. ++ will fail to increment beyond the largest unsigned integer + 1.
$ perl -MConfig -MB=svref_2object,SVf_IVisUV,SVf_NOK -e'
$i = hex(("FF"x($Config{ivsize}-1))."FD");
$sv = svref_2object(\$i);
for (1..4) {
++$i;
printf $sv->FLAGS & SVf_NOK ? "NV %.0f\n"
: $sv->FLAGS & SVf_IVisUV ? "UV %u\n"
: "IV %d\n", $i;
}
'
UV 18446744073709551614
UV 18446744073709551615 <-- 2**64 - 1 Largest UV
NV 18446744073709551616 <-- 2**64 Requires 1 bit of precision as a float
NV 18446744073709551616 <-- 2**64 + 1 Requires 65 bits of precision as a float
but only 53 are available.
This is on 32-bit perl,
perl -e "$x=2**53-5; printf qq{%.f\n}, ++$x for 1..10"
9007199254740988
9007199254740989
9007199254740990
9007199254740991
9007199254740992
9007199254740992
9007199254740992
9007199254740992
9007199254740992
9007199254740992
Well, on my 64-bit machine it's 18446744073709551615 (much easier as ~0), after which it increases once more time to 1.84467440737096e+19 and stops incrementing.

PowerShell formating numbers by variables

I have integer values: 3 60 150 1500 and float values 1.23354, 1.234, 1.234567...
I calculate the number of digits of the biggest integer:
$nInt = [System.Math]::Ceiling([math]::log10($maxInt))
# nInt = 4
and in another way the biggest number of dec. behind the decimal point of the float-variable: $nDec = 6
How can I format a print out that all integer do have the same string-length with leading spaces?
|1500
| 500
| 60
| 3
And all float with the same string-length as well?
1.234567|
1.23354 |
1.234 |
The | is just to mark my 'point of measure'.
Of course I have to choose a character-set where all characters do have the same pixex-size.
I am thinking of formatting by "{0:n}" or $int.ToString(""), but I can't see how to use this.
Try PadLeft or PadRight. For example, for your integers:
$maxInt.ToString().PadLeft($nInt.ToString().Length, ' ')

Multiple 'nth' weekday of month in a single quartz cron expression

I'm trying to write a cron expression for quartz that runs hourly everyday except every second Saturday of the month.
So, by using the '#' notation, I was trying to write the expression like:
0 0 * ? * SUN-FRI,SAT#1,SAT#3,SAT#4,SAT#5
This expression is not working properly. Also, quartz is not complaining about the cron format (quartz usually complains about cron expressions when they are wrong).
So I did some other experiments today. So, today is the third Thursday of the month, I was playing around with THU#N notation, and that's what I've found so far (I changed my expression to minute to make it easier for experimenting):
0 * * ? * SUN-FRI,SAT#1,SAT#3,SAT#4,SAT#5: not triggered
0 * * ? * THU#3: triggered
0 * * ? * THU#3,THU#4: not triggered
0 * * ? * THU#2,THU#3: triggered
I know I can simply split this into 4 additional expression but in my real scenario I have tons of expressions to change and this would increase my expression list to something 5 times longer.
In a brief: Does anyone knows how to condense these:
0 0 * ? * SUN-FRI / 0 0 * ? * SAT#1 / 0 0 * ? * SAT#3 / 0 0 * ? * SAT#4 / 0 0 * ? * SAT#5
...into a single cron expression?
Note: I'm using quartz scheduler 1.5 (I know, I know... pretty outdated)

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's maxPwdAge attribute (line 5).
Notice we use the Set keyword in VBScript to initialize the variable named objMaxPwdAge—the variable used to store the value returned by Get. 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 the IADsLargeInteger interface's HighPart and LowPart properties to calculate the large integer's value. As you may have guessed, HighPart gets the high order 32 bits, and LowPart gets the low order 32 bits. You use the following formula to convert HighPart and LowPart 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=com") ' 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.