Issues with arithmetic-operators - powershell

my problem is that I'm trying to put a simple math formula in a PowerShell script but this "arithmetic-operators" is an issue now for me, It was used to work this way, but something changed and now doesn't matter what I put in it multiples for more numbers as if they were letters, (it's only stacking all of them together)
I even tried fixing it using
$x=[int]$xx
to fix my variables so PowerShell could understand, and it did work just not with broken numbers Ex: 7.5 or 3.1 or 9.6 No broken numbers. Can anyone help me
$pi=[math]::pi
$xx= Read-Host -prompt "X "
$yy= Read-Host -prompt "Y "
$zz= Read-Host -prompt "Z "
$x=[int]$xx
$y=[int]$yy
$z=[int]$zz
$re = $z * $y
$r = $z * $x + $y * $x + $z * $x + $y * $x
$res = 2 * ($re) + $r
echo .
echo "$r = $z * $x + $y * $x + $z * $x + $y * $x"
echo .
echo "$re = $z * $y"
echo .
echo "$res = 2 * ($re) + $r"
echo .
echo "Total = $res"
echo .
pause
if you run this and put X as 27, Y as 7.5 and Z as 17, your answer should be 1578, and you fixed it

You are getting the wrong answer because 7.5 is not an [int]. It is rounding 7.5 to 8 to cast it to an int. You need $y=[single]$yy to make this work or any other type that supports decimals. I would replace all [int] with [single] if expect decimal values. See the following:
$pi=[math]::pi
$xx= Read-Host -prompt "X "
$yy= Read-Host -prompt "Y "
$zz= Read-Host -prompt "Z "
$x=[single]$xx
$y=[single]$yy
$z=[single]$zz
$re = $z * $y
$r = $z * $x + $y * $x + $z * $x + $y * $x
$res = 2 * ($re) + $r
echo "$r = $z * $x + $y * $x + $z * $x + $y * $x"
echo "$re = $z * $y"
echo "$res = 2 * ($re) + $r"
echo "Total = $res"
Output of the variables above:
$x,$y,$z,$re,$r,$res
27
7.5
17
127.5
1323
1578
Other types that you could potentially use are [double], which is the default type of uncasted numbers with decimals, and [decimal]. You can also use the -as type operator like $y = $yy -as [double]. See About Type Operators

Related

Windows Powershell equivalent to this Linux command that calculates a number to 10000 decimal places?

I have seen this fun little command going around on social media, which outputs pi to 10000 decimal places. I'm wondering what is the Windows Powershell equivalent to this?
echo "scale=10000; 4*a(1)" | bc -l
I know I can use the Powershell Math library to do the basic math formula, but how to set the number of decimal places to 10000?
PS C:\Users\Me> [Math]::Atan(1)*4
3.14159265358979
The [Math] class only works with double so obviously you can't get more than 53 bits of precision. A few of its methods also support decimal so you'll get a little bit more digits but obviously no way near 10000 digits. There's no arbitrary precision floating point type in .NET so you're completely on your own to calculate the digits if you don't want to retrieve them from some storage space
There's BigInteger (PowerShell type accelerator name: [bigint]) though, which helps a lot since you won't need to do arbitrary precision math yourself. For example to calculate 10000 digits of π you can calculate 10000π and does the operations in integer or fixed point math
There are many algorithms to do that such as this one: How does this code calculate pi with high precision?
Fortunately Rosetta Code has a sample snippet to calculate π. After the below function has been declared just call Get-Pi 10000 to get the desired output
Function Get-Pi ( $Digits )
{
$Big = [bigint[]](0..10)
$ndigits = 0
$Output = ""
$q = $t = $k = $Big[1]
$r = $Big[0]
$l = $n = $Big[3]
# Calculate first digit
$nr = ( $Big[2] * $q + $r ) * $l
$nn = ( $q * ( $Big[7] * $k + $Big[2] ) + $r * $l ) / ( $t * $l )
$q *= $k
$t *= $l
$l += $Big[2]
$k = $k + $Big[1]
$n = $nn
$r = $nr
$Output += [string]$n + '.'
$ndigits++
$nr = $Big[10] * ( $r - $n * $t )
$n = ( ( $Big[10] * ( 3 * $q + $r ) ) / $t ) - 10 * $n
$q *= $Big[10]
$r = $nr
While ( $ndigits -lt $Digits )
{
While ( $ndigits % 100 -ne 0 -or -not $Output )
{
If ( $Big[4] * $q + $r - $t -lt $n * $t )
{
$Output += [string]$n
$ndigits++
$nr = $Big[10] * ( $r - $n * $t )
$n = ( ( $Big[10] * ( 3 * $q + $r ) ) / $t ) - 10 * $n
$q *= $Big[10]
$r = $nr
}
Else
{
$nr = ( $Big[2] * $q + $r ) * $l
$nn = ( $q * ( $Big[7] * $k + $Big[2] ) + $r * $l ) / ( $t * $l )
$q *= $k
$t *= $l
$l += $Big[2]
$k = $k + $Big[1]
$n = $nn
$r = $nr
}
}
$Output
$Output = ""
}
}

Blank result for String concatenation in foreach

There might not be the best way but what is wrong with this code. Why do i get blank result from $str in the foreach loop, whereas if it try to concatenate individual cells i get the right result.
$csv = import-csv -Path "C:\Users\abc\csv4script\TEST.csv" -Header 'IPs'
$str = ''
$x = 1
foreach ($cell in $csv.){
if ($x -le 4000){
$str = $str + ", " + $cell.IPs
if ($x -eq 4000){
$x = 1}
$str = ''
}
$x = $x + 1
}
$str
# $str = $str + $csv[1].IPs + ", " + $csv[2].IPs
$str
It doesn't have a value because you misplaced a '}' character.
$x = 1}
Move it to after $str = ''
$x = 1
$str = ''}
Also as Thomas pointed out, remove the period after $csv variable in your foreach statement, it should be like: foreach($cell in $csv)
Also if you want to increment a value,
$x++ is quicker and easier to read than $x = $x + 1
Lastly, as you have it, if your list has more than 4000 IPs the $str variable will empty out.

Different result in forloop?

I want to print like this
xxx
xxxxx
xxxxxxx
xxxxxxxxx
xxxxxxxxxxx
I achive this by following code
$s = "x";
$z = 5;
$m = 1;
$m = $m+2,
$z--,
$c = " " x $z,
$st = $s x $m,
print "$c$st\n",
for(1..5);
My doubt
when i used increment and decrement operator after the print function it gave the different result
Script is
$c = " " x $z,
$st = $s x $m,
print "$c$st\n",
$m = $m+2,
$z--,
for(1..5);
It result is
x
35 xxx
54 xxxxx
73 xxxxxxx
92 xxxxxxxxx
Here 3 5 7 9 are printed by the $m and 5 4 3 2 are printed by the $z.
But, i not directly print the $m and $z then why it gave $m and $z value? How it is work?
The code
$c = " " x $z,
$st = $s x $m,
print "$c$st\n",
$m = $m+2,
$z--,
for(1..5);
is parsed as:
$c = " " x $z,
$st = $s x $m,
print ("$c$st\n", $m = $m+2, $z--),
for(1..5);
You can force different parsing by using parentheses:
$c = " " x $z,
$st = $s x $m,
print ("$c$st\n"),
$m = $m+2,
$z--
for(1..5);
But I rather suggest the following:
for(1..5) {
$c = " " x $z;
$st = $s x $m;
print ("$c$st\n");
$m = $m+2;
$z--;
}
That way you are not relying on any operator precedence which might bite you. You will immediately see which statements are contained in the loop too. (I had to read your initial code thrice to finally get it)

Is there a string concatenation shortcut in PowerShell?

Like with numerics?
For example,
$string = "Hello"
$string =+ " there"
In Perl you can do
my $string = "hello"
$string .= " there"
It seems a bit verbose to have to do
$string = $string + " there"
or
$string = "$string there"
You actually have the operator backwards. It should be +=, not =+:
$string = "Hello"
$string += " there"
Below is a demonstration:
PS > $string = "Hello"
PS > $string
Hello
PS > $string += " there"
PS > $string
Hello there
PS >
However, that is about the quickest/shortest solution you can get to do what you want.
Avoid += for building strings
As for using the increase assignment operator (+=) to create a collection, strings are also mutual, therefore using the increase assignment operator (+=) to build a string might become pretty expensive as it will concatenate the strings and assign (copy!) it back into the variable. Instead I recommend to use the PowerShell pipeline with the -Join operator to build your string.
Apart from the fact it is faster it is actually more DRY as well:
$String = 'Hello', 'there' -Join ' ' # Assigns: 'Hello there'
Or just
-Join #('One', 'Two', 'Three') # Yields: 'OneTwoThree'
For just a few items it might not make much sense but let me give you a a more common example by creating a formatted list of numbers, something like:
[Begin]
000001
000002
000003
[End]
You could do this:
$x = 3
$String = '[Begin]' + [Environment]::NewLine
for ($i = 1; $i -le $x; $i++) { $String += '{0:000000}' -f $i + [Environment]::NewLine }
$String += '[End]' + [Environment]::NewLine
But instead, you might actually do it the PowerShell way:
$x = 3
$String = #(
'[Begin]'
for ($i = 1; $i -le $x; $i++) { '{0:000000}' -f $i }
'[End]'
) -Join [Environment]::NewLine
Performance Testing
To show the performance decrease of using the increase assignment operator (+=), let's increase $x with a factor 1000 up till 20.000:
1..20 | ForEach-Object {
$x = 1000 * $_
$Performance = #{x = $x}
$Performance.Pipeline = (Measure-Command {
$String1 = #(
'[Begin]'
for ($i = 1; $i -le $x; $i++) { '{0:000000}' -f $i }
'[End]'
) -Join [Environment]::NewLine
}).Ticks
$Performance.Increase = (Measure-Command {
$String2 = '[Begin]' + [Environment]::NewLine
for ($i = 1; $i -le $x; $i++) { $String2 += '{0:000000}' -f $i + [Environment]::NewLine }
$String2 += '[End]' + [Environment]::NewLine
}).Ticks
[pscustomobject]$Performance
} | Format-Table x, Increase, Pipeline, #{n='Factor'; e={$_.Increase / $_.Pipeline}; f='0.00'} -AutoSize
Results:
x Increase Pipeline Factor
- -------- -------- ------
1000 261337 252704 1,03
2000 163596 63225 2,59
3000 432524 127788 3,38
4000 365581 137370 2,66
5000 586370 171085 3,43
6000 1219523 248489 4,91
7000 2174218 295355 7,36
8000 3148111 323416 9,73
9000 4490204 373671 12,02
10000 6181179 414298 14,92
11000 7562741 447367 16,91
12000 9721252 486606 19,98
13000 12137321 551236 22,02
14000 14042550 598368 23,47
15000 16390805 603128 27,18
16000 18884729 636184 29,68
17000 21508541 708300 30,37
18000 24157521 893584 27,03
19000 27209069 766923 35,48
20000 29405984 814260 36,11
See also: PowerShell scripting performance considerations - String addition

How does Perl decide which order to evaluate terms in an expression?

Given the code:
my $x = 1;
$x = $x * 5 * ($x += 5);
I would expect $x to be 180:
$x = $x * 5 * ($x += 5); #$x = 1
$x = $x * 5 * 6; #$x = 6
$x = 30 * 6;
$x = 180;
180;
But instead it is 30; however, if I change the ordering of the terms:
$x = ($x += 5) * $x * 5;
I do get 180. The reason I am confused is that perldoc perlop says very plainly:
A TERM has the highest precedence in Perl. They include variables,
quote and quote-like operators, any expression in parentheses, and any
function whose arguments are parenthesized.
Since ($x += 5) is in parentheses, it should be a term, and therefore executed first, regardless of the ordering of the expression.
The act of typing out the question yielded the answer to me: terms have the highest precedence. That means that the $x in the first chunk of code is evaluated and yields 1, then 5 is evaluated and yields 5, then ($x += 5) is evaluate and yields 6 (with a side-effect of setting $x to 6):
$x = $x * 5 * ($x += 5);
address of $x = $x * 5 * ($x += 5); #evaluate $x as an lvalue
address of $x = 1 * 5 * ($x += 5); #evaluate $x as an rvalue
address of $x = 1 * 5 * ($x += 5); #evaluate 5
address of $x = 1 * 5 * 6; #evaluate ($x += 5), $x is now 6
address of $x = 1 * 5 * 6; #evaluate 1 * 5
address of $x = 5 * 6; #evaluate 1 * 5
address of $x = 30; #evaluate 5 * 6
30; #evaluate address of $x = 30
Similarly, the second example reduces like this:
$x = ($x += 5) * $x * 5;
address of $x = ($x += 5) * $x * 5; #evaluate $x as an lvalue
address of $x = 6 * $x * 5; #evaluate ($x += 5), $x is now 6
address of $x = 6 * 6 * 5; #evaluate $x as an rvalue
address of $x = 6 * 6 * 5; #evaluate 5
address of $x = 36 * 5; #evaluate 6 * 6
address of $x = 180; #evaluate 36 * 5
180; #evaluate $x = 180
Whenever I have confusion about stuff like this I first pull out perldoc perlop, and then if I'm still not sure, or want to see how a particular block of code will get executed, I use B::Deparse:
perl -MO=Deparse,-p,-q,-sC
my $x = 1;
$x = $x * 5 * ($x += 5);
^D
gives:
(my $x = 1);
($x = (($x * 5) * ($x += 5)));
- syntax OK
So substituting values at each stage gives:
($x = (($x * 5) * ($x += 5)));
($x = ((1 * 5) * ($x += 5)));
($x = ((5) * (6))); # and side-effect: $x is now 6
($x = (5 * 6));
($x = (30));
($x = 30);
$x = 30;
So the fact that $x was temporarily set to 6 doesn't really affect anything, because the earlier value (1) was already substituted into the expression, and by the end of the expression it is now 30.
$x by itself is also a TERM. Since it is encountered first (in your first example), it is evaluated first.
The associativity of the * operator is leftward, so the left most term is always evaluated before the right most term. Other operators, such as ** are right associative and would have evaluated ($x += 5) before the rest of the statement.