簡體   English   中英

對[math] :: round的相同輸入將返回不同的結果

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM