2012-01-15 63 views
1

Microsoft technet suggests [Math]::Floor([int]$a/[int]$b) for integer division。我相信[int][Math]::Floor($a/$b)由于少了一次投射操作,所以更具可读性和更高性能。 I have proven both methods equivalent.但是,我无法获得一致的结果。我的方法涉及重复两种方法10,000次并使用Measure-Command cmdlet测量结果。但是不能构建一个测试,其中一个测试反复执行比另一个测试更好。我的代码如下:性能测试PowerShell整数除法的两种方法

Write-Host 
$loopLength = 10000 

$runtime = Measure-Command { 
    1..$loopLength | ForEach-Object { 
     Foreach ($divisor in 2,3,5,7) { 
      [Math]::Floor([int]$_/[int]$divisor) > $null 
     } 
    } 
} 

"Double Cast: $($runtime.TotalMilliSeconds)" 

$runtime = Measure-Command { 
    1..$loopLength | ForEach-Object { 
     Foreach ($divisor in 2,3,5,7) { 
      [int][Math]::Floor($_/$divisor) > $null   
     } 
    } 
} 
"Single Cast: $($runtime.TotalMilliSeconds)" 

如何修改我的代码,所以我拿到证明一种方法比另一种更好的结果一致。

+0

我认为你缺少'[INT] [数学] ::楼($ _/$除数)> $ null'从第二个循环。 – 2012-01-15 04:14:01

+0

这些看起来在性能上如此接近,以至于系统的后台进程使差异变得可忽略不计。您可以通过停止服务,关闭窗口等来最小化背景噪音,甚至可以在Windows安全模式下启动。 (请参阅msconfig.exe)。我必须说,我不明白为什么施放操作的结果会使操作本身更快。 – 2012-01-15 04:34:06

+0

@AndyArismendiquite权利和纠正。你可以自己编辑它并留下编辑注释。 – 2012-01-15 14:47:11

回答

0

TechNet上的示例有点愚蠢,因为数字已经是System.Int32类型。看看这个例子:

PS C:\Users\andy> [math]::floor(100/26).GetType().Fullname 
System.Double 
PS C:\Users\andy> (100).GetType().FullName 
System.Int32 
PS C:\Users\andy> [int].FullName 
System.Int32 

所以这是完全没有必要把[int]地板方法参数的前面,因为他们已经是System.Int32类型。

另外,您不希望将返回的System.Double转换为Int32,因为返回值可能大于Int32可以容纳的值。例如:

PS C:\Users\andy> [int][math]::floor(([int]::MaxValue + 1)/1) 
Cannot convert value "2147483648" to type "System.Int32". Error: "Value was either too large or too small for an Int32." 

至于性能,速度的差异可以忽略不计。 PowerShell引擎在后台执行大量类型适配和强制操作,无论您是否希望这样做......它是这样设计的,因此系统管理员不必过多担心int,double,decimals等等......一个数字是一个数字吗? ;-)例如:

[Math]::Floor("123") 
# This outputs 123 as System.Double. 

这甚至不会在C#中编译。 PowerShell运行时执行必要的强制转换以符合Floor方法签名。

又如:

"2"/"1" 
# This outputs 2 as System.Int32. 

司是不可能的字符串,但PowerShell引擎做转型的背景为你做这项工作。

下面是我的机器的性能测试结果:

function Get-SingleCastTime { 
    $runtime = Measure-Command { 
     1..10000 | ForEach-Object { 
      Foreach ($divisor in 2,3,5,7) { 
       [int][Math]::Floor($_/$divisor) > $null   
      } 
     } 
    } 
    "Single Cast: $($runtime.TotalMilliSeconds)" 
} 

function Get-DoubleCastTime { 
    $runtime = Measure-Command { 
     1..10000 | ForEach-Object { 
      Foreach ($divisor in 2,3,5,7) { 
       [Math]::Floor([int]$_/[int]$divisor) > $null 
      } 
     } 
    } 

    "Double Cast: $($runtime.TotalMilliSeconds)" 
} 

Get-SingleCastTime 
#Single Cast: 614.6537 

Get-DoubleCastTime 
#Double Cast: 545.2668 

Get-DoubleCastTime 
#Double Cast: 514.2103 

Get-SingleCastTime 
#Single Cast: 526.9188 
+0

当你写了([int] :: MaxValue + 1)时,要小心@Andy Arismendi它不再是一个整数,它是你的命令行上的双重尝试([int] :: MaxValue + 1).gettype()样品是用铸造书写的。对于我而言,从数学的角度来看,n位的整数除法的结果适合于n位。 – JPBlanc 2012-01-16 08:22:40

+0

@JBBlanc这个例子是输出一个不适合Int32的值,以显示为什么不执行这个'[int] [math] :: Floor($ aNumberBiggerThanInt32MaxValue)''是因为这个异常。最好让PowerShell运行时间来处理它。 – 2012-01-16 08:28:53

1

对于我来说,这样的性能优化是不是真的很重要。 PowerShell本身比编译的langugages慢得多,所以如果你真的需要性能,使用编译语言或者用Add-Type编译你的代码。

除此之外 - 如果您测试性能,您需要最小的其他代码可以改变结果。 Foreach-Object本身增加了它自己的复杂性。这就是为什么我会建议使用foreach声明来代替。

出人意料的是,我的机器上的结果是有时相反..

[76]: $loopLength = 100000 
[77]: 
[77]: $runtime = Measure-Command { 
>>  foreach($i in 1..$loopLength) { 
>>   Foreach ($divisor in 2,3,5,7) { 
>>    [Math]::Floor([int]$i/[int]$divisor) > $null 
>>   } 
>>  } 
>> } 
>> 
[78]: "Double Cast: $($runtime.TotalMilliSeconds)" 
Double Cast: 16294.3328 
[79]: 
[79]: $runtime = Measure-Command { 
>>  foreach($i in 1..$loopLength) { 
>>   Foreach ($divisor in 2,3,5,7) { 
>>    [int][Math]::Floor($i/$divisor) > $null 
>>   } 
>>  } 
>> } 
>> "Single Cast: $($runtime.TotalMilliSeconds)" 
>> 
Single Cast: 15924.3836