Summary: Microsoft Scripting Guy, Ed Wilson, talks about using strings to format the display of decimal places in Windows PowerShell.
Hey, Scripting Guy! One of the things I have a problem with is when I get numbers that have a lot of decimal places. I mean, how do I really get rid of them—at least properly? I have done things like convert them to integers, but that loses me all of the decimal places. I have also tried using Trim or other string techniques with mixed success. I would love to see how a real pro does it. Can you help me?
—PA
Hello PA,
Microsoft Scripting Guy, Ed Wilson, is here. Like a lot of people, I like to work with a plan. I need to know what I am going to be doing a week from now, a month from now, and even a year from now. But when I have a plan in place, I do not give it a lot of extra thought. I mean, that is what the planning stage is for, right? To plan?
Well, PA, a similar thing happens when I am working with Windows PowerShell. I like to know where I am going, but then I hold off until just when I need to do something before I actually do it. What am I talking about?
Well numbers, for one thing.
Using a custom format string to control decimal places
When I use a custom format string to control the number of decimal places, I change the underlying type from a number type to a string. In the following example, I convert from a Double to a String:
PS C:\> $d = 1.11
PS C:\> $d.GetType()
IsPublic IsSerial Name BaseType
——– ——– —- ——–
True True Double System.ValueType
PS C:\> $s = (1.11).tostring("#.#")
PS C:\> $s.GetType()
IsPublic IsSerial Name BaseType
——– ——– —- ——–
True True String System.Object
This change might be OK if I am sending the output to its final destination—for example, displaying it to the Windows PowerShell console or printing it on a printer. But if I am storing the data, perhaps in a database, it is probably best to store the actual number. This is because I can easily create a report from the database that displays only one decimal place, but I have no idea what the second decimal place might be.
Additionally, I could run into other problems trying to perform math operations on strings instead of numbers. So as a best practice, put it off and make these types of conversions the last thing you do to your data.
However, when I am trying to read data, I have a problem keeping track of more than two or three decimal places. The numbers begin to run together. So if I am trying to gain a quick impression, I like to easily change to one or two decimal places. To do this, I use a custom number format string.
The ToString method is everywhere in Windows PowerShell—even number types contain a ToString method. The great thing is that I can easily override the method with my own custom format string. Here is an example of changing a number that has two decimal places to a number that contains a single decimal place:
PS C:\> (1.11).tostring("#.#")
1.1
All I need to do is use the pound sing ( # ) where I want a digit to appear. So in the example, I had two decimal places, but I only wanted one.
If I have numbers on the right side of the decimal, I need only a single pound sign. On the left side of the decimal, everything becomes rounded up if there are additional numbers, or nothing happens if there are no numbers. The following example illustrates how I limit my output to two decimal places:
PS C:\> $a = 1.1, 2.22, 3.333, 4.4444, 5.55555
PS C:\> $a | % {$_.ToString("#.##")}
1.1
2.22
3.33
4.44
5.56
In the previous output, 5.55555 rounds up to 5.56, but 4.4444 rounds down to 4.44. The number 1.1 displays as 1.1, even though my format string of “#.##” contains two pound signs.
If I am working with output from a Windows PowerShell cmdlet, I can use the same technique by using a customized property. I can do this with Select-Object, Format-Table, or Format-List (and even with Out-GridView).
In the following image, I see the CPU time of several process reports as 0.03, and 0.02.
As shown here, if I format the output so that it only displays a single decimal place, I lose much of the CPU output:
Get-Process |
Where CPU |
Sort CPU -Descending |
Select-Object ProcessName,
@{l='cpu';e={($_.cpu).tostring("#.#")}}
The script and its associated output are shown here:
PA, that is all there is to using custom format strings to control the display of decimal places in Windows PowerShell. Numbers Week will continue tomorrow when I will talk about more cool stuff.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy
That example is actually pretty lame because it doesn’t always produce two decimal places. If the value is 1.00 and you want to write 1.00 that solution will right 1 with no decimal places.
If you want trailing zeros, you can use ToString(“N2”). See more details of formatting options here: https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-numeric-format-strings