January 28th, 2015

Formatting PowerShell Decimal Places

Doctor Scripto
Scripter

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using strings to format the display of decimal places in Windows PowerShell.

Hey, Scripting Guy! Question 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

Hey, Scripting Guy! Answer 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.

Image of command output

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:

Image of command output

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 

Author

The "Scripting Guys" is a historical title passed from scripter to scripter. The current revision has morphed into our good friend Doctor Scripto who has been with us since the very beginning.

2 comments

Discussion is closed. Login to edit/delete existing comments.

  • Thomas Boomer

    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.