Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Powershell - Round down to nearest whole number

Tags:

powershell

What's the best way to round down to nearest whole number in PowerShell?

I am trying [math]::truncate but its not giving me predictable results.

Example:

$bla = 17.2/0.1
[math]::truncate($bla) 

outputs 171 instead of the expected 172!

$bla = 172
[math]::truncate($bla) 

outputs 172

I just need something that works.... and must always round down (i.e round($myNum + 0.5) won't work due to baker's rounding which may round up if the number has a 0.5 component).

like image 789
ted Avatar asked May 03 '11 00:05

ted


4 Answers

Ah, I see. Looks like the datatype needs to be decimal:

[decimal] $de = 17.2/.1
[double] $db = 17.2/.1

[math]::floor($de)
172
[math]::floor($db)
171

http://msdn.microsoft.com/en-us/library/system.math.floor(v=vs.85).aspx

like image 57
Louis Waweru Avatar answered Nov 14 '22 08:11

Louis Waweru


The Math::Floor function combined with [decimal] declaration should give you the results you want.

[Math]::Floor([decimal](17.27975/0.1))

returns = 172

like image 39
Tom Hazel Avatar answered Nov 14 '22 06:11

Tom Hazel


The issue you are encountering with the original 17.2/0.1 division example is due to inaccuracy in the floating-point representation of the given decimal values (as mentioned in Joey's comment on another answer). You can see this in PowerShell by examining the round-trip representation of the final value:

PS> $bla = 17.2/0.1
PS> $bla.GetType().FullName
System.Double
PS> $bla.ToString()
172
PS> $bla.ToString('r')
171.99999999999997

A simple way to get around this is to declare the result as int, as PowerShell will automatically round to the the result to the nearest integer value:

PS> [int]$bli = 17.2/0.1
PS> $bli.GetType().FullName
System.Int32
PS> $bli.ToString()
172

Note that this uses the default .NET method of MidpointRounding.ToEven (also known as banker's rounding). This has nice statistical properties when tabulating large numbers of numeric values, but can also be changed to the simpler away-from-zero method:

function round( $value, [MidpointRounding]$mode = 'AwayFromZero' ) {
  [Math]::Round( $value, $mode )
}

PS> [int]3.5
4
PS> [int]4.5
4
PS> round 3.5
4
PS> round 4.5
5

Another option is to use a more accurate representation for the original values, which will avoid the issue entirely:

PS> $bld = [decimal]17.2/0.1
PS> $bld.GetType().FullName
System.Decimal
PS> $bld.ToString()
172
like image 9
Emperor XLII Avatar answered Nov 14 '22 06:11

Emperor XLII


[Math]::floor($x) is the built-in way to do it.

Just be aware of how it will behave with negative numbers. [Math]::floor(5.5) returns 5, but [Math]::floor(-5.5) returns -6.

If you need the function to return the value closest to zero, you'll need:

If ($x -ge 0) {
    [Math]::Floor($x)
} Else {
    [Math]::Ceiling($x)
}
like image 6
Bacon Bits Avatar answered Nov 14 '22 07:11

Bacon Bits