零为常数?


15

我最近遇到了这个编程习惯用法:

const float Zero = 0.0;

然后用于比较:

if (x > Zero) {..}

任何人都可以解释一下,这实际上是否比以下方法更有效,可读性或可维护性:

if (x > 0.0) {..}

注意:我可以想到定义此常量的其他原因,我只是想知道它在上下文中的使用。


31
开发人员正在计划将代码移植到数学定律不同的宇宙中吗?
vaughandroid

6
认真地说,我想不出一个很好的理由。我能提出的唯一解释是过分热心的编码标准,或者某些听说过“魔术数字不好”但不明白为什么(或什么会构成魔术数字)的开发人员……
vaughandroid

@Baqueta-另一个宇宙?我想他们已经住在那里!至于魔术数字,我同意,但是我使用经验法则,将0和1 以外的所有内容都设为常数。
NWS 2012年

1
如果x具有type float,则x > 0.0强制提升为double,这可能效率较低。这不是使用一个命名常量虽然一个很好的理由,只为确保您的常数具有正确的类型(例如0ffloat(0)decltype(x)(0))。
Mike Seymour 2012年

1
@JoSo:是公平的类型,13.37是不是float,它的double。因此,如果您想要一个,float那么可以想象您的导师是正确的。在某些情况下(例如,对浮点数的赋值)13.37将隐式转换为float所需的,而在其他情况下(例如,模板类型推导)则不会,而static const float总是以您想要的类型开始。因此,更安全。提醒你,会的13.37f!但是,还有其他避免使用宏的原因,而不是“类型安全性”,因此,导师给您一个糟糕的论证的可能性就很大。
史蒂夫·杰索普

Answers:


29

可能的原因是缓存,命名或强制类型

缓存(不适用)

您希望避免在比较过程中创建对象的成本。在Java中,一个例子是

BigDecimal zero = new BigDecimal ("0.0");

这涉及到相当繁重的创建过程,最好使用提供的静态方法来解决:

BigDecimal zero = BigDecimal.ZERO;

这允许进行比较而不会产生重复的创建成本,因为BigDecimal是在初始化期间由JVM预先缓存的。

就您所描述的而言,原语正在执行相同的工作。就缓存和性能而言,这在很大程度上是多余的。

命名(不太可能)

原始开发人员试图为整个系统中的通用值提供统一的命名约定。这有一些优点,特别是对于不常见的值,但是只有在较早的缓存情况下才值得像零这样的基本值。

强制类型(最有可能)

原始开发人员正试图强制使用特定的原始类型,以确保将比较强制转换为正确的类型,并可能转换为特定的比例(小数位数)。可以,但是对于此用例,简单名称“零”可能不够详细,因为ZERO_1DP是更合适的意图表达。


2
+1强制类型。我将在像C ++这样的语言中添加该语言,该语言允许操作符重载,定义一个常量并使用typedef会将变量的类型精确地保留在一个位置,并且无需更改代码即可进行更改。
Blrfl 2012年

3
强制类型很可能不是他们想要的,但这是为什么可以强制执行的最好解释!
NWS 2012年

7
对于强制类型,我可能更愿意使用0.0f
Svish 2012年

强制类型有时在vb.net中很有用,在其中对字节执行按位运算符会产生字节结果。说byteVar1 = byteVar2 Or CB128似乎比做得好byteVar1 = byteVar2 Or CByte(128)。当然,为字节设置适当的数字后缀会更好。由于C#int会将按位操作数提升为运算符,即使保证结果适合a时byte,该问题也不是那么重要。
2012年

我不确定将'0'的常量名称设置为零,但有时它有助于提高代码的可读性。例如,将此常量设置为零-“ ROOT_TYPE_ID = 0”将有助于编写类似if(id!= ROOT_TYPE_ID){..}的语句
Tech Junkie

6

这是因为“工具Na”

我在这里未列出的可能原因是因为许多质量工具标记了幻数的使用。将幻数丢入算法中而又不使它们清晰可见以便以后更改通常是一种不好的做法,尤其是当它们在代码中的多个位置重复时。

因此,尽管这些工具在标记此类问题上是正确的,但对于这些值无害且最有可能是静态值或仅仅是初始化值的情况,它们通常会产生误报

当发生这种情况时,有时您会面临以下选择:

  • 如果工具允许,则将其标记为误报(通常带有特殊格式的注释,这对于不使用该工具的人来说很烦人)
  • 或将这些值提取为常量,无论是否重要。

关于性能

这取决于我猜想的语言,但这在Java中相当普遍,并且对性能没有影响,因为如果值是实常数,则在编译时将其内联static final。如果将它们声明为常量甚至声明为预处理器宏,则对C或C ++不会产生影响。


5

这可能是有道理的,因为它明确定义Zero为type float

至少在C和C ++中,值0.0是类型double,而等效值float0.0f。因此,假设x您与之进行比较也是float一句话

x > 0.0

而实际上xdouble进行推广以匹配0.0可能导致问题的类型(尤其是使用平等测试)。没有转换的比较当然是

x > 0.0f

与...相同

float Zero = 0.0; // double 0.0 converted to float  
x > Zero

尽管如此,我认为在编译器中启用转换警告而不是让用户编写笨拙的代码会更加有用。


1

首先,这里零定义为float,而不是int。当然,这对比较没有任何影响,但是在其他情况下,使用此常数可能会有所不同。

我看不出有其他原因为何Zero在这里声明为常量。这只是某种编码样式,如果在该特定程序的其他地方都使用该样式,则最好遵循该样式。


1

几乎可以肯定,它在执行期间的效率完全一样(除非您的编译器非常原始),而在编译期间的效率则略低。

关于这是否比x > 0... 更具可读性...请记住,有些人诚实,真诚地认为COBOL是一个好主意,并且很高兴与之合作—然后有些人对C的看法完全相同。甚至存在一些对C ++持相同观点的程序员!)换句话说,您在这一点上不会得到普遍的同意,这可能不值得为之奋斗。


0

[是]实际上,它比以下任何一种方法都更加有效,可读或可维护:

if (x > 0.0) {..}

如果您正在编写通用(即非特定于类型的)代码,那么很有可能。甲zero()函数可以适用于任何类型的代数,或者任何类型的是一组WRT加成。它可以是整数,也可以是浮点值,如果变量本身就是某个线性空间内的函数,则它甚至可以是一个函数(例如x是z-> a_x形式的线性函数* z + b_x),然后zero()为函数提供a和b均为zero()基础类型。

因此,您可能希望使用C ++(尽管zero()不是很常见的AFAIK),Julia和其他语言编写这样的代码。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.