在C#中, >0和>=1哪个更快、更好?
这两者是一样的,如果其中一个更快或更好,它们都应该编译成相同的东西。
更重要的是,大多数程序员可能会认为 > 0
更易读,而可读性比这种微小的优化更重要。
>0
的意思是“正非零整数”。而读取>=1
则需要我考虑整数没有小数点右边的数字来决定。是的,这两个表达式并不相同;尽管我以前没有做过大量的浮点数程序。是否有>=1
更好的情况?当然有。但考虑到问题的写法,我认为“正非零整数”是意图。 - Billy ONeal>= 0
和 > -1
呢?前者表示“至少为零”,后者表示“非负数”。 - Aaron Franke更好的那一个是最能清晰地表达您的意图的那一个。
如果你要测试一个整数是否在区间[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)
无论哪种情况,编译器都反转了比较条件。"大于或等于"测试被编译为"小于"指令,而"大于"测试被编译为"小于或等于"指令。通常编译器可以自由地进行这样的修改,如果使用不同版本的编译器可能会产生不同但等效的字节码。未定义。您明确要求C# - 但这取决于处理器架构,即CLR运行时编译器。
我同意其他回答中的观点,通常不应考虑微观优化。但是,了解哪个版本具有更小/明显更快的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
}
while
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");
}
}
}
}
进入
(调试)
.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
}
(发布)
.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
}
这两种方式的性能差异可以忽略不计(如果有的话)。我正在努力证明它可能是什么(因为任何差异可能归结于JIT发出和执行的代码,所以这将依赖于平台)。
但请记住,从性能上来说,这是一种极端微观优化,很可能是没有必要的。
更好的选择是在你的代码中选择哪种更易读并传达你的意图。
jge
和jg
指令需要相同数量的周期(如果我没记错的话)。 在测试>0的特定情况下,如果您使用的是无符号整数,则使用test
指令而不是cmp
可能会更快,因为对于无符号整数,>0等同于!= 0(我真的不知道)。 其他架构可能会有所不同。 关键是这是如此低级别的优化,即使在很少数情况下值得优化,也没有硬件独立的方式来优化它。由于 CPU 内部执行两个数字的减法并检查结果和溢出,因此这两个指令没有任何区别。对于任一指令,都不需要额外的步骤。
当涉及到代码时,取决于您要记录的内容。>= 1 表示 1 是最低可能的数字。> 0 表示不允许为 0。这有一个小的语义差异,专业人士会注意选择正确的操作符来记录他们的意图。
如果您认为 >= n 和 >= n + 1 是相同的,那么您是错误的:>= int.MaxValue 和 > (int.MaxValue + 1) 是不同的^^
除非在应用程序中非常紧密的循环中,否则您不会注意到任何差异,这可能会影响性能。然后,您需要对代码进行分析以决定哪个更好。
在您的应用程序中使用最合适的那一个。
.Count > 0
,请尝试在System.Linq
中使用帮助程序方法Enumerable.Any()
,这应该会更快。
否则,我不知道 :)
Any()
会更快?我认为它会更慢,因为 Count
只是一个属性访问器,而 Any()
必须枚举序列的第一个项。 - We Are All MonicaEnumerable.Count()
比Enumerable.Any()
要慢得多。如果你的容器有一个Count
属性(例如List
),那么是的,你应该使用它。 - Billy ONeal
>0
更快是因为它少输入了一个字符。 - D'Arcy Rittichcmp eax, ebx
后跟jg <label>
或jge <label>
。据我所知,以前 jge(如果大于或等于则跳转)操作在汇编中的开销要比 jg(如果大于则跳转)更大,但是(1)我认为现在已经不是这样了,而且(2)编译器应该能够进行优化。尽管如此,我认为这个问题很有价值,因为它涉及到底层的工作原理。 - CtrlDot