[英]Same input into [math]::round returns different results
我在PowerShell中解析文件。 我有這部分代碼(帶有調試寫入)
$max_file_size = 0
$max_file_size = $value
Write-Host $max_file_size # DEBUG
$max_file_size = Convert-to-Bytes $max_file_size
Write-Host $max_file_size # DEBUG
[string]$max_file_size = [math]::round($max_file_size, 0)
Write-Host $max_file_size # DEBUG
我看到兩個不同的行具有相同的數據。 第一遍返回以下結果:
8192.00000P
9223372036854775808.00000
9223372036854775808
第二遍返回此結果:
8192.00000P
9223372036854775808.00000
9.22337203685478E+18
笏?
Function Convert-to-Bytes
{
#Pass in a value and convert to bytes.
param ($value)
If ($value -eq $Null)
{
$value = 0
}
#Convert case to upper.
[string]$value = $value.ToString().ToUpper()
#Strip off 'B' if in string.
[string]$value = $value.TrimEnd("B")
[decimal]$output = 0
If ($value.Contains("K"))
{
$value = $value.TrimEnd("K")
[decimal]$output = $value
[decimal]$output = $output * 1KB
}
If ($value.Contains("M"))
{
$value = $value.TrimEnd("M")
[decimal]$output = $value
[decimal]$output = $output * 1MB
}
If ($value.Contains("G"))
{
$value = $value.TrimEnd("G")
[decimal]$output = $value
[decimal]$output = $output * 1GB
}
If ($value.Contains("T"))
{
$value = $value.TrimEnd("T")
[decimal]$output = $value
[decimal]$output = $output * 1TB
}
If ($value.Contains("P"))
{
$value = $value.TrimEnd("P")
[decimal]$output = $value
[decimal]$output = $output * 1PB
}
If ($value.Contains("yte"))
{
$value = $value.TrimEnd("yte")
[decimal]$output = $value
[decimal]$output = $output
}
Return $output
}
聲明類型變量時,PowerShell會向其添加ArgumentTypeConverterAttribute
,因此所有對該變量的后續賦值都將轉換為該類型。
PS> $Var1=$null
PS> [string]$Var2=$null
PS> Get-Variable Var?|ft Name,Attributes -AutoSize
Name Attributes
---- ----------
Var1 {}
Var2 {System.Management.Automation.ArgumentTypeConverterAttribute}
PS> $Var1=1
PS> $Var2=1
PS> $Var1.GetType().FullName
System.Int32
PS> $Var2.GetType().FullName
System.String
在第一次傳遞結束時,您將max_file_size
聲明為string
:
[string]$max_file_size = [math]::round($max_file_size, 0)
所以在第二遍中,你分配給它的任何東西都被轉換為string
。
我在每個Write-Host
步驟中放置行,如下所示添加一些類型信息:
$max_file_size.GetType().FullName
這樣我每次都會知道這種類型。 在第一關
0 : System.Int32
8192.00000P : System.String
9223372036854775808.00000 : System.Decimal
9223372036854775808 : System.String
在同一會話的第二次傳球
0 : System.String
#^^^ String here makes sense since last it was cast to string in the previous run.
8192.00000P : System.String
9223372036854775808.00000 : System.String
#^^^ Here is does not make sense since it should be a decimal returned from the function like before
9.22337203685478E+18 : System.String
仍然可以處理,但是[math]::round($max_file_size, 0)
在第二遍被賦予了不同的數據,一個字符串而不是一個十進制。 到底是為什么。 你也可以通過這種方式看到差異
PS C:\users\Cameron\Downloads> [math]::round("9223372036854775808.00000", 0)
9.22337203685478E+18
PS C:\users\Cameron\Downloads> [math]::round([decimal]"9223372036854775808.00000", 0)
9223372036854775808
解決方法
我知道將此行添加到代碼的開頭可以解決問題。 這樣每次都執行相同的操作。
Remove-Variable max_file_size
也可以強制從函數返回小數。
[decimal]$max_file_size = Convert-to-Bytes $max_file_size
向前
這是一個問題而不是答案,但如果沒有其他人來幫忙,我可以盡我所能來解決這個問題。
肉和土豆
暫時只想將此答案分開,因為這可能只是此問題的工作空間,除非其他人沒有考慮答案。 所以我試圖使用Trace-Command
來查看我是否能弄清楚發生了什么。 有很多信息可以解析,但為了讓開始變得簡單,我做了這個。
使用您的函數創建了一個ps1腳本,並將以下代碼放置了兩次
Trace-Command -name TypeConversion -Expression {
$value = "8192.00000P"
$max_file_size = 0
$max_file_size = $value
$max_file_size = Convert-to-Bytes $max_file_size
[string]$max_file_size = [math]::round($max_file_size, 0)
} -PSHost
放一行,這樣我就知道第一遍完成的地方和第二遍的開始。 考慮從TypeConversion
開始,因為它似乎與問題相同。 我有以下發現(我將僅顯示差異。)請注意,所有代碼行都以DEBUG: TypeConversion Information
為前綴DEBUG: TypeConversion Information
但為了簡潔和可讀性,它已在此處刪除
第一遍有關於數學裝配的一些信息,只有一次才有意義
: 0 : Conversion to System.Type
: 0 : Found "System.Math" in the loaded assemblies.
在那之后不久, $max_file_size = 0
和$max_file_size = $value
出現了,我只在第二遍看到了這個
: 0 : Converting "0" to "System.String".
: 0 : Converting numeric to string.
: 0 : Converting "8192.00000P" to "System.String".
: 0 : Result type is assignable from value to convert's type
真正問題的結束是看起來像函數返回和相關的字符串賦值[string]$max_file_size = [math]::round($max_file_size, 0)
。
1.通過
: 0 : Converting "9223372036854775808.00000" to "System.Decimal".
: 0 : Result type is assignable from value to convert's type
: 0 : Converting "9223372036854775808" to "System.String".
: 0 : Converting numeric to string.
通過
: 0 : Converting "9223372036854775808.00000" to "System.Decimal".
: 0 : Result type is assignable from value to convert's type
: 0 : Converting "9223372036854775808.00000" to "System.String".
: 0 : Converting numeric to string.
: 0 : Converting to double or single.
: 0 : Converting "9.22337203685478E+18" to "System.String".
: 0 : Converting numeric to string.
看起來數據會使您的自定義函數與“9223372036854775808.00000”相同,但在第二次傳遞中返回$max_file_size
值轉換為double,因為您可以使用此代碼進行復制。
[double]"9223372036854775808.00000"
9.22337203685478E+18
我不是故意浪費任何時間,但這是這個問題臨時空間的最佳位置。
感覺Trace-Command
可能無法獲取我需要的信息,因為它無法從方法round
獲取調試信息
情節變粗
如果我將返回變量更改為類似$another_max_file_size
,然后在各個多次傳遞之后檢查$another_max_file_size
和$max_file_size
的類型,我會發現$max_file_size
像我們已經確定的那樣轉換為[System.String]
,並且$another_max_file_size
保持為一個[System.Decimal]
所以我們現在知道問題的根源是從這一行分配函數的輸出。 同樣,不要認為返回值而是賦值操作本身。
$max_file_size = Convert-to-Bytes $max_file_size
# ^ something is happening here.
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.