2010-09-07 24 views

回答

12

未定义。你明确地要求C# - 但这是依赖于处理器体系结构的东西,即CLR运行时编译器。

+1

我想大多数编程语言都是如此。 – Andy 2010-09-07 18:34:14

+0

...什么是更好的是由什么是更可读的上下文中使用。 – 2010-09-07 18:34:58

44

两者都不;如果速度更快或更好,它们都应该编译成相同的东西。

更重要的是,大多数程序员可能会发现> 0更具可读性,并且可读性比这样的子微优化更重要。

+7

+1用于指出可读性的重要性 – Matt 2010-09-07 18:36:02

+7

我不知道你的可读性断言;我将“= 1”读作“1或更多”,这是定义条件比“大于零”更自然的方式。但是,“超过五个”在谈话中非常有意义。我认为可读性将取决于上下文,以及开发人员将与代码并行查看的任何需求文档或用户指南的存在和措辞。它也很大程度上取决于所涉及的数学类型;正如Jesse Millikan所说,这两种比较在浮点世界中不会相同。 – KeithS 2010-09-07 18:49:10

+0

@KiethS:我将'> 0'的意图读为“正的非零整数”。阅读'> = 1'使我不得不考虑整数是否没有小数点的右边数来决定。是的,表达式是不一样的;尽管我之前没有做过大量的浮点程序。有没有'> = 1'的情况会更好?当然。但考虑到这个问题的写作方式,我假定“正的非零整数”是意图。 – 2010-09-07 18:55:11

7

两者之间的性能差异将会忽略不计(如果甚至有一个)。我正在努力证明它可能是什么(它将取决于平台,因为任何不同都可能归结为由JIT发出和执行的代码)。

请记住,虽然,性能明智这是一个极端的微观优化很可能是没有根据的。

更好的选择将会是更具可读性,并在您的代码中表达最好的意图。

1

要回答更快的问题,我不确定,但我认为它们是相同的。为了更好地回答,我认为这取决于上下文。

0

您不会注意到任何区别,除非可能在非常非常紧密的循环中对应用程序中的性能至关重要。然后你需要分析你的代码来决定哪个更好。

使用在您的应用程序中最有意义的那个。

26

更好的是最明确地表达您的意图

如果您正在测试,看是否为整数的范围是[1,6],那么你应该把它写成:

if (x >= 1 && x <= 6) { ... } 

写这会工作,但不会如此明显符合规范:

if (x > 0 && x < 7) { ... } 

我还假设你在这里谈论整数类型。如果你正在处理浮点或十进制数,那么它们是不相等的。


除非您对代码进行了剖析并发现这是瓶颈,否则您不应该担心微观优化问题。即使如此,在每种情况下检查由C#编译器生成的代码以查看它们是否编译为相同的IL也会很有趣。这可以通过使用.NET Reflector来完成。

if (x >= 1) 
{ 
    Console.WriteLine("True!"); 
} 

结果:

L_000b: ldloc.0   // Load the value of x 
L_000c: ldc.i4.1   // Load the constant 1 
L_000d: blt.s L_0019  // Branch if less than 
L_000f: ldstr "True!" 
L_0014: call void [mscorlib]System.Console::WriteLine(string) 

鉴于:

if (x > 0) 
{ 
    Console.WriteLine("True!"); 
} 

导致以下IL:

L_000b: ldloc.0   // Load the value of x 
L_000c: ldc.i4.0   // Load the constant 0 
L_000d: ble.s L_0019  // Branch if less than or equal 
L_000f: ldstr "True!" 
L_0014: call void [mscorlib]System.Console::WriteLine(string) 

在两种情况下,编译器已经反转进行比较。 “大于或等于”测试编译为“小于”指令,“大于”测试编译为“小于或等于”。通常,编译器可以自由地进行这种修改,并运行不同版本的编译器可能会产生不同的(但相同的)字节码。

鉴于它们不会编译到同一个IL中,查看哪个最快的最好方法是实际在循环中运行代码,并查看每个版本执行需要多长时间。我试过这样做,但是在编写代码的两种方式之间我没有看到任何可测量的性能差异。

+0

我同意!这是对声明的期望...> 0和> = 1确实会做2种不同的(有时是相同的)事情......你要么全部要么是其中的一部分,而不是全部! – 2010-09-07 18:50:17

+0

我喜欢你展示IL,特别是当它在字节码中切换比较时。 – Nick 2010-09-07 19:41:29

0

所以通常当我比较某些东西到> 0或> = 1时,我试图看看数组/集合是否包含任何元素。如果是这种情况,不要使用.Count > 0,请尝试使用System.Linq中的帮助器方法Enumerable.Any(),这应该快得多。

否则,我不知道:)

+0

为什么Any()会更快?我认为这会比较慢,因为'Count'只是一个属性访问器,但Any()'必须枚举序列的第一项。 – jnylen 2010-09-07 18:55:22

+0

@jnylen:取决于你使用的数量。 'Enumerable.Count()'比'Enumerable.Any()'糟糕得多。如果你的容器有一个'Count'属性(即'List')那么是的,你应该使用它。 – 2010-09-07 18:59:46

+2

我想如果集合支持该成员,我认为.Any()计算为.Count> 0。当集合不支持时,它总是比.Count()更快。不知道它编译到什么IL,所以它可能没有太大的帮助... – 2010-09-07 19:20:56

2

没有区别,因为CPU内部做两个数的减法和检查结果和溢出。任何一条指令都没有涉及额外的步骤。

说到代码,它取决于你要记录的内容。 > = 1表示1是可能的最小数字。 > 0表示不允许0。专业人士会注意到一个小的语义差异。他们会选择合适的运营商来记录他们的意图。

如果你认为> = n和> = N + 1,你错了一样的:> = int.MaxValue和>(int.MaxValue + 1)是不同的^^

3

我与同意通常不应考虑微观优化的其他反应。然而,看到两个版本中哪一个具有更小/明显更快的IL可能是有趣的。

所以:

using System; 

namespace IL_Test 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      int i = 3; 
      if (i > 0) 
      { 
       Console.Write("i is greater than zero"); 
      } 
     } 
    } 
} 

翻译成:

(调试)

.method private hidebysig static void Main(string[] args) cil managed 
{ 
    .entrypoint 
    .maxstack 2 
    .locals init (
     [0] int32 i, 
     [1] bool CS$4$0000) 
    L_0000: nop 
    L_0001: ldc.i4.3 
    L_0002: stloc.0 
    L_0003: ldloc.0 
    L_0004: ldc.i4.0 
    L_0005: cgt 
    L_0007: ldc.i4.0 
    L_0008: ceq 
    L_000a: stloc.1 
    L_000b: ldloc.1 
    L_000c: brtrue.s L_001b 
    L_000e: nop 
    L_000f: ldstr "i is greater than zero" 
    L_0014: call void [mscorlib]System.Console::Write(string) 
    L_0019: nop 
    L_001a: nop 
    L_001b: ret 
} 

(释放)

.method private hidebysig static void Main(string[] args) cil managed 
{ 
    .entrypoint 
    .maxstack 2 
    .locals init (
     [0] int32 i) 
    L_0000: ldc.i4.3 
    L_0001: stloc.0 
    L_0002: ldloc.0 
    L_0003: ldc.i4.0 
    L_0004: ble.s L_0010 
    L_0006: ldstr "i is greater than zero" 
    L_000b: call void [mscorlib]System.Console::Write(string) 
    L_0010: ret 
} 

using System; 

namespace IL_Test 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      int i = 3; 
      if (i >= 1) 
      { 
       Console.Write("i is greater than zero"); 
      } 
     } 
    } 
} 

(DEBUG)

.method private hidebysig static void Main(string[] args) cil managed 
{ 
    .entrypoint 
    .maxstack 2 
    .locals init (
     [0] int32 i, 
     [1] bool CS$4$0000) 
    L_0000: nop 
    L_0001: ldc.i4.3 
    L_0002: stloc.0 
    L_0003: ldloc.0 
    L_0004: ldc.i4.1 
    L_0005: clt 
    L_0007: stloc.1 
    L_0008: ldloc.1 
    L_0009: brtrue.s L_0018 
    L_000b: nop 
    L_000c: ldstr "i is greater than zero" 
    L_0011: call void [mscorlib]System.Console::Write(string) 
    L_0016: nop 
    L_0017: nop 
    L_0018: ret 
} 

(RELEASE)

.method private hidebysig static void Main(string[] args) cil managed 
{ 
    .entrypoint 
    .maxstack 2 
    .locals init (
     [0] int32 i) 
    L_0000: ldc.i4.3 
    L_0001: stloc.0 
    L_0002: ldloc.0 
    L_0003: ldc.i4.1 
    L_0004: blt.s L_0010 
    L_0006: ldstr "i is greater than zero" 
    L_000b: call void [mscorlib]System.Console::Write(string) 
    L_0010: ret 
} 

据我可以看到第i> = 1是略微快于I> 0 IN调试模式

在释放模式下l不同点在于抵消0004一个BLE vs一个BLT。我想这两个IL操作转化为CPU消耗本机操作系统..

+0

那些交换或我错过了什么? – 2010-09-07 19:41:56

+2

你说一个稍微快一点 - 你为什么没有发布你的基准测试结果?你测试过什么机器?优化?优化是由JIT完成的,而不是由C#编译器完成的,因此查看生成的IL对性能没有太多的了解。 – Niki 2010-09-07 19:42:43

+2

@Caspar:第一个做的是:if(i> 0)== false,然后返回(不要console.write)。第二个是做:'if(i <1)== true',然后返回。安德烈测试所产生的IL似乎比马克·拜尔斯发现的冗长得多。他人指出:运行它,基准测试,问是否真的慢?这里的代码可能是DEBUG编译的,或者是另一个版本的编译器..我们不知道。是的,JIT可能会优化或不优化。基准它.. – maxwellb 2010-09-07 20:18:39

4

当然,它取决于您的程序将运行在CPU架构。在x86上,与此处相关的jgejg指令采用相同数量的周期IIRC。在测试大于0的特定情况下,如果使用无符号整数,则可能(我真的不知道)使用test指令代替cmp会更快,因为对于无符号整数,> 0等于!= 0其他体系结构可能不同。关键是,这是如此低级的,即使在极少数情况下值得优化,也没有硬件无关的方法来优化它。编辑:忘了提及:任何编译器或值得它的盐的虚拟机应该能够找出测试> = 1相当于测试> 0,并且如果它甚至在汇编语言上有所作为,那么执行如此微不足道的优化水平。

0

如果两者之间会有差异,那么我会说这是一个微型优化,它不应该影响应用程序的整体性能。此外,当人们真正弄清楚他是否必须使用> 0或者> = 1时,那么我认为计算出哪一个更快的成本并不会超过(最小的)性能收益。

因此,我还要说你应该使用最能表达意图的选项。

相关问题