Introduction
Recently, I ran into a practical problem: I had a list of users that I wanted to split into batches of 100. Pretty straightforward, but when I tried to calculate how many batches I needed, the result was a float. That wasn’t very helpful — I just wanted a number without any decimals. During this process, I encountered a few small challenges that I’d like to share with you in this blog post. I’ll walk you through my approach, the decisions I made, and how I eventually solved it.
[math]::round()
The easiest way to convert a float to an int is by using [math]::round()
. Let’s take a look at an example.
$UserCount = 439
$MaxBatchSize = 100
$BatchesCount = $UserCount / $MaxBatchSize
Write-Output "Batches (float): $BatchesCount"
$BatchesCountRounded = [math]::round($BatchesCount)
Write-Output "Batches (rounded): $BatchesCountRounded"
Output
Batches (float): 4.39
Batches (rounded): 4
And here we already see the first challenge. If we divide 439 users into batches of 100, we don’t get 4 batches — we get 5. The last batch may not be a full 100 users, but it’s still a batch.
So you might think: “Then I’ll just add 1 every time!” That seems logical… until you look at the following example:
$UserCount = 561
$MaxBatchSize = 100
$BatchesCount = $UserCount / $MaxBatchSize
Write-Output "Batches (float): $BatchesCount"
$BatchesCountRounded = [math]::round($BatchesCount) + 1
Write-Output "Batches (rounded): $BatchesCountRounded"
Output
Batches (float): 5.61
Batches (rounded): 7
This happens because [math]::round()
rounds up or down based on a threshold of x.5, and in the case of exactly x.5, it considers the nearest even number.
Rounding to x decimal places
We can also round to x decimal places using [math]::round()
. This is done by adding an extra argument: [math]::round($float,$x)
.
And for the jokers who try to stack it — yes, that works. Just be aware that your first rounding will result in exactly x.5, so it will be rounded to the nearest even number.
## nearest even number: 2
[math]::round($([math]::round(1.49,1)))
2
## nearest even number: 2
[math]::round($([math]::round(2.49,1)))
2
## nearest even number: 4
[math]::round($([math]::round(3.49,1)))
4
Quick explanation of what we’re doing here: first we round, for example, 1.49 to 1 decimal place, and then we round the result to 0 decimal places.
Declare rounding strategy
We can avoid this behavior by explicitly specifying the rounding strategy. This is done using a third argument called MidpointRounding
. This is an Enum
with the following possible values:
Name | Value | Description |
---|---|---|
ToEven | 0 | Rounds to the nearest number, and when halfway between two, it rounds toward the nearest even number. |
AwayFromZero | 1 | Rounds to the nearest number, and when halfway between two, it rounds away from zero. |
ToZero | 2 | Directed rounding toward zero, with the result closest to and no greater in magnitude than the infinitely precise result. |
ToNegativeInfinity | 3 | Downward-directed rounding, with the result closest to and no greater than the infinitely precise result. |
ToPositiveInfinity | 4 | Upward-directed rounding, with the result closest to and no less than the infinitely precise result. |
If we revisit the previous example and use AwayFromZero
(1) as the rounding strategy, we get the following:
[math]::round($([math]::round(1.49,1)),0,1)
2
[math]::round($([math]::round(2.49,1)),0,1)
3
[math]::round($([math]::round(3.49,1)),0,1)
4
Quick explanation: first we round, for example, 1.49 to 1 decimal place, and then we round the result to 0 decimal places, specifying that we want to use the AwayFromZero
(1) strategy.
Other rounding methods
The Math class also offers two other methods for rounding numbers: Ceiling()
and Floor()
.
[math]::Ceiling()
Ceiling()
always rounds up.
[math]::Ceiling(5.61)
6
[math]::Ceiling(4.39)
5
So 1.001 with [math]::Ceiling()
will always become 2.
[math]::Floor()
Floor()
always rounds down.
[math]::Floor(5.61)
5
[math]::Floor(4.39)
4
So 1.9999 with [math]::Floor()
will always become 1.
Conclusion
To solve my scenario, I ultimately used [math]::Ceiling()
. This allowed me to reliably determine how many batches I needed.
If I had wanted to see only the number of full batches, I could have used [math]::Floor()
. And if I wanted a more general rounding approach, I could have used [math]::Round()
. Just keep in mind that this method can sometimes give slightly different results than you might expect.
Leave a Reply