到“如果,如果,如果”或“if、else if、else if、else”

发布于 2024-12-04 15:43:39 字数 751 浏览 0 评论 0原文

我正在编写一些用于数据分析的代码,并且必须根据某些标准排除样本。在实践中,我最终编写了如下代码:

bool Test(SampleType sample)
{
  if( ! SubTest1(sample) )
    return false;
  if( ! SubTest2(sample) )
    return false;
  if( ! SubTest3(sample) )
    return false;

  return true;
}

以下内容对我来说似乎是等价的:

bool Test(SampleType sample)
{
  if( ! SubTest1(sample) )
    return false;
  else if( ! SubTest2(sample) )
    return false;
  else if( ! SubTest3(sample) )
    return false;
  else 
    return true;
}

计算成本方面有区别吗?在可扩展性/可维护性、美观性等方面是否存在有争议的优先权?

我知道这可能是一个无关紧要的问题,但一旦我的脑海中浮现出这些问题,我就需要找到答案。

PS:如果有人关心的话,我截至 15/09 的实际代码可以在以下位置找到: http://folk.uio.no/henrikq/conf.tgz

I am writing some code for data analysis, and have to exclude samples based on some criteria. In practice I end up writing code such as:

bool Test(SampleType sample)
{
  if( ! SubTest1(sample) )
    return false;
  if( ! SubTest2(sample) )
    return false;
  if( ! SubTest3(sample) )
    return false;

  return true;
}

The following seems equivalent to me:

bool Test(SampleType sample)
{
  if( ! SubTest1(sample) )
    return false;
  else if( ! SubTest2(sample) )
    return false;
  else if( ! SubTest3(sample) )
    return false;
  else 
    return true;
}

Is there a difference in terms of computing cost? Is there a arguable preferential one in terms of extendibility/maintainability, aesthetics, etc...?

I know this is probably an inconsequential issue, but once I get these questions stuck in my head I NEED to find the answer.

PS: in case anyone cares, my actual code as of 15/09 can be found at the following:
http://folk.uio.no/henrikq/conf.tgz

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

谜兔 2024-12-11 15:43:40

编译器为两个版本生成相同的代码。但如果仅与第二个版本进行比较,第一个版本在可维护性方面更好。

当遇到return语句时代码退出;因此,在即将到来的 if 中保留 else 是没有用的。它使开发人员更好地理解代码。

另外,如果这是文字代码,那么您仍然可以缩小为,

bool Test(SampleType sample)
{
  return (SubTest1(sample) && SubTest2(sample) && SubTest3(sample));
}

Compiler generates the same code for both the versions. But the 1st version is better in maintainability aspect if you compare just with the 2nd version.

The code exits when the return statement is encountered; so there is no use of keeping else in the upcoming if. It makes the developer understand the code better.

Also, if this is the literal code then you can still shrink as,

bool Test(SampleType sample)
{
  return (SubTest1(sample) && SubTest2(sample) && SubTest3(sample));
}
南风几经秋 2024-12-11 15:43:40

我会这样做:

return SubTest1(sample) && SubTest2(sample) && SubTest3(sample);

这不会提高性能,但该函数的作用可能(或可能不会)更明显。

I would do this:

return SubTest1(sample) && SubTest2(sample) && SubTest3(sample);

This won't improve performance, but what the function do may (or may not) be more obvious.

数理化全能战士 2024-12-11 15:43:40

两者在行为方面完全等效,编译器可能会为两者生成相同的机器代码。

它们在可读性方面甚至没有太大区别 - 两者都有相同数量的嵌套。将此与没有早期返回导致深度嵌套的情况进行比较。

Both are completely equivalent in terms of behavior and compilers will likely emit identical machine code for both.

They don't even differ that much in terms of readability - both have the same amount of nesting. Compare this to case where no early return leads to deep nesting.

忆梦 2024-12-11 15:43:40

就可读性而言,

bool Test( SampleType sample )
{
    return SubTest1( sample )
        && SubTest2( sample )
        && SubTest3( sample );
}

比您的任何一个选项都清晰得多。不然你绝对
希望 else 明确表示一旦满足其中一个条件
满足后,其他的都不会被测试。

In terms of readability,

bool Test( SampleType sample )
{
    return SubTest1( sample )
        && SubTest2( sample )
        && SubTest3( sample );
}

is far clearer than either of your options. Otherwise, you definitely
want the else to make it clear that once one of the conditions has
been met, none of the others will be tested.

似狗非友 2024-12-11 15:43:40

两者是相同的。编译器可能会弄清楚如何优化它们,以便发出相同的机器代码。我会推荐第一个代码,因为它更容易阅读。

Both are identical. The compiler is likely to figure out how to optimize them so that identical machine code is emitted. I would prump for the 1st code as it is easier to read.

怀中猫帐中妖 2024-12-11 15:43:40

我无法想象这会对性能产生任何影响。

如果它们是独立测试,我会使用第一个,并且您只想在其中一个测试成功后退出,而如果在一组逻辑替代方案之间进行选择,则使用第二个测试。

I can't imagine it will make any difference in performance.

I would use the first one if they were independent tests, and you just want to drop out after one them suceeds and the second one if it's choosing between a set of logical alternatives.

迷荒 2024-12-11 15:43:40

据我所知,结果机器代码没有区别。除此之外,谁在乎呢?这段代码有性能问题吗?性能是一个困难的主题,通常应该留到项目结束时,只有当存在性能问题时,才应该在它们实际存在的地方发现并修复它们,而不是您提前认为它们可能存在的地方。

As far as I know, there's no difference in the resulted machine code. Besides that, who cares? Do you have a performance problem with this code? Performance is a difficult subject that usually should be left to the end of the project and only if there are performance problems they should be found and fixed WHERE THEY ACTUALLY EXIST and not where you think in advance they might be.

阿楠 2024-12-11 15:43:40

这主要取决于编译器如何优化生成的代码。

if(.) 通常使用compare_to_zero 指令进行转换,后跟条件跳转。

在您的情况下,这将是

CMP(c1)
RETZ
CMP(c2)
RETZ
CMP(c3)
RETZ

or (使用 else-s)

   CMP(c1)
   JNZ(a1)
   RET
a1:CMP(c2)
   JNZ(a2)
   RET
a2:CMP(c3)
   JNZ(a3)
   RET
a3:RET

优化器的第二遍将看到跳转链,反转 then/else (和 Z/NZ)跳过跳转,位于“跳到下一个”,给出了前面的代码。

It mostly depends on how the compiler optimize the resulting code.

the if(.) is typically translated with a compare_to_zero instruction, followed by a conditional jump.

In your case, this will be

CMP(c1)
RETZ
CMP(c2)
RETZ
CMP(c3)
RETZ

or (with the else-s)

   CMP(c1)
   JNZ(a1)
   RET
a1:CMP(c2)
   JNZ(a2)
   RET
a2:CMP(c3)
   JNZ(a3)
   RET
a3:RET

A second pass of the optimizer will see the chain of jumps, invert the then/else (and Z/NZ) skip off the jumps, being at the point a "jump to next", giving exactly the previous code.

徒留西风 2024-12-11 15:43:40

这取决于语言和周围的 API

第一个解决方案是典型的命令式方法,重点是检查某些内容的行为:如果 a 则中止,如果 b 则中止,如果 c 则中止,成功。

第二种解决方案是一种更实用的方法,可以将其理解为数学定义中的大括号(如: fac(n) = { n <= 1: 1, n > 1: n * fac( n-1))。

应选择与环境相匹配的解决方案。在 Java、Python 等中这将是第一个。在红宝石中,第二个可能没问题。

It depends on the language and the surrounding APIs

The first solution is an typical imperative approach, the focus is on the act of checking something: abort if a, abort if b, abort if c, success.

The second solution is a more functional aproach, one could read it as the curly brace in mathematical definitions (as in: fac(n) = { n <= 1: 1, n > 1: n * fac(n-1)).

The solution should be chosen to match the environment. In Java, Python, etc it would be the first. In ruby the second could be fine.

忆伤 2024-12-11 15:43:40

有一个好的做法叫做“一点入口,一点出口”。这意味着函数中最好只有一个返回

目前,您的函数很简单,但将来它可能会增长、变得更加复杂、分配必须释放的临时变量等。

所以最好到处使用良好的实践。这被称为“防御性编程”,防御人为错误(我和我的同事的错误)。

我会这样写:

bool Test(SampleType sample)
{
  bool bRet = true; // by default, set it to the most "defensive" value which will cause the less harm or make the problem evident

  // in the future, you may have inits and allocations here

  if ( !SubTest1(sample) )
    bRet = false; // don't match
  else if ( !SubTest2(sample) )
    bRet = false; // don't match
  else if ( !SubTest3(sample) )
    bRet = false; // don't match
  else
    ; // bRet stays true

  // thanks to the single point of exit, you can do things like that
  if (bRet)
     log("... match");
  else
     log("...no match")

  // here you clean temporary resources...

  return bRet;
}

如果您想提高性能,最好的方法是将 SubTestX 函数按最佳顺序放置,以便最不匹配的函数位于第一个,因此较少需要进行测试才能发现它不匹配。

there is a good practice that is called "one point of entry, one point of exit". It means that it's better to have only one return in a function.

For now, your function is simple, but in the future, it may grow, become more complicated, allocate temporary variables which have to be freed, etc.

So it's better to use good practices everywhere. It's called "defensive programming", defense against human failures (mine and my colleagues').

I would write it this way :

bool Test(SampleType sample)
{
  bool bRet = true; // by default, set it to the most "defensive" value which will cause the less harm or make the problem evident

  // in the future, you may have inits and allocations here

  if ( !SubTest1(sample) )
    bRet = false; // don't match
  else if ( !SubTest2(sample) )
    bRet = false; // don't match
  else if ( !SubTest3(sample) )
    bRet = false; // don't match
  else
    ; // bRet stays true

  // thanks to the single point of exit, you can do things like that
  if (bRet)
     log("... match");
  else
     log("...no match")

  // here you clean temporary resources...

  return bRet;
}

If you want to improve performance, the best way is to put the SubTestX functions in the best order so that the one that doesn't match most often is first, so less tests are needed to find that it doesn't match.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文