6

I'm trying to convert strings such as 5.7303333333e+02 to the decimal type. I've tried using [decimal]::TryParse but the return value is false.

Is there a method similar to [datetime]::parseexact, or any clean way to convert these strings? Or am I going to have to parse out the e+02 and do that math separately?

phuclv
  • 37,963
  • 15
  • 156
  • 475
rtf
  • 724
  • 3
  • 15
  • 27

2 Answers2

9

What about :

[int]"5.7303333333e+02"
[decimal]"5.7303333333e+02"
JPBlanc
  • 70,406
  • 17
  • 130
  • 175
  • 1
    +1 it works. But I wonder what casting mechanism is used in the background, if it is not `[decimal]::TryParse("5,7303333333e+02", [ref] $dec)`. The problem is the unsupported scientific notation because `[decimal]::TryParse("5,7303333333", [ref] $dec)` does work... See here: http://msdn.microsoft.com/en-us/library/9zbda557.aspx – Davor Josipovic Jun 06 '13 at 16:26
  • I'm surprised that worked but `[decimal]::TryParse` doesn't. Much cleaner looking than using TryParse anyway. – rtf Jun 06 '13 at 16:31
  • 4
    @davor: Using `Trace-Command TypeConversion { [decimal]'5.7303333333e+02' } -PSHost `, you can see that PowerShell catches the format exception and re-tries the conversion by parsing with `[double]` and then converting to `[decimal]`. – Emperor XLII Jun 20 '13 at 23:43
  • this doesn't work. `[decimal]'5.730333333333333333333333333e+02'` will return an incorrect value – phuclv Aug 21 '20 at 03:26
0

TL;DR:

You need to specify NumberStyles.Float when using Parse or TryParse

PS C:\> $s = '5.7303333333333333333333333e+02'
PS C:\> $style = [Globalization.NumberStyles]::Float
PS C:\> $culture = [cultureinfo]::GetCultureInfo('en-US')
PS C:\> [decimal]::Parse($s, $style)
573.03333333333333333333333
PS C:\> [decimal]$dec = 0
PS C:\> [decimal]::TryParse($s, $style, $culture, [ref] $dec)
True
PS C:\> $dec
573.03333333333333333333333

or append the d suffix directly

PS C:\> Invoke-Expression ($s + 'd')
573.0333333333333333333333333

As Emperor XLII commented above, [decimal]"5.7303333333e+02" does not actually work because it'll convert to decimal through double. Try adding more digits and you'll immediately realized that the output isn't correct anymore:

PS C:\> Trace-Command TypeConversion { [decimal]'5.7303333333e+02' } -PSHost
DEBUG: TypeConversion Information: 0 : Converting to decimal.
DEBUG: TypeConversion Information: 0 : Exception converting to decimal: "Input string was not in a correct format.". Converting to decimal passing through double.
DEBUG: TypeConversion Information: 0 : Numeric Conversion through System.Double.
573.03333333
PS C:\> [decimal]'5.7303333333e+02'
573.03333333
PS C:\> [decimal]'5.730333333333333333333333333e+02' # doesn't work
573.033333333333
PS C:\> 5.730333333333333333333333333e+02d           # correct value
573.0333333333333333333333333

As you can see if we use the d suffix for decimal we'll get the correct high-precision value, so one simple trick is just spawning a new shell to normalize the value although that'll be obviously slow, or use Invoke-Expression

PS C:\> $d = '5.730333333333333333333333333e+02'
PS C:\> [decimal]$(powershell -com ($d + 'd'))
573.0333333333333333333333333
PS C:\> Invoke-Expression ($d + 'd'))
573.0333333333333333333333333

But why doesn't TryParse work? The reason is because the default style used by Decimal.Parse and Decimal.TryParse is like this

[ws][sign][digits,]digits[.fractional-digits][ws]

which doesn't allow the exponent. If you read Parse's documentation you'll see that the full number format is

[ws][$][sign][digits,]digits[.fractional-digits][e[sign]digits][ws]

Where [e] is

  • The 'e' or 'E' character, which indicates that the value is represented in exponential notation. The s parameter can represent a number in exponential notation if style includes the NumberStyles.AllowExponent flag.

That means you need to use NumberStyles.Float (which includes NumberStyles.AllowExponent) as above to make it work

phuclv
  • 37,963
  • 15
  • 156
  • 475
  • In the first piece of code I'm getting an error `[ref] cannot be applied to a variable that does not exist`. `$dec = [decimal]::Parse($s, $style)` is the fix. – Ste Apr 07 '21 at 19:01
  • @Ste no, `Parse` and `TryParse` are different things. The correct fix is to declare the variable before using: `[decimal]$dec = 0` – phuclv Apr 08 '21 at 11:18