魔术数字不好...我完全同意。但是我发现其中一个魔术数字很难修复:


'100'是一个魔术数字。


考虑以下代码:

public double getPercent(double rate) {
    return rate * 100;
}

public double getRate(double percent) {
    return percent / 100;
}


SonarQube将引发2次违规,每次使用100次违规。我可以用一个常量变量替换100次,但是对此有什么好名字呢?那真的是个好主意吗?如果有人改变了它的价值,那将是一场灾难。我还可以在所有使用100的行中添加// NOSONAR

处理魔术数字100的最佳实践是什么?


UPDATE

从答案中,对我来说最有用的是:


实用幻数规则:如果最有意义的变量名是常量,则文字不是幻数因为它与文字的口语名称相同。


因此,按照这种逻辑,100并不是一个魔幻数字。

违规消失了,我决定用一个常数替换100:这些行可能掩盖了其他开发人员以后可能会无意添加的其他潜在问题。

不确定使用此常量是否会有任何实际好处。一个很小的可能是,当我执行// NOSONAR时,我从项目中的资源文件中看到了很多匹配项,而git grep 100只是出现了使用此代码的Java代码。

评论

我已经在愚蠢的短毛绒上给程序员写了一个咆哮。在此处添加100的命名常量将很令人困惑。但是,我觉得您不是在寻找该小片段的代码审查,而是寻求有关此类情况的最佳实践,不幸的是,这是一个基于观点的问题。

造成侮辱伤害的根本原因是:您不应该具有幻数,而应具有有意义的标识符。但这就是为什么上一行有一个有意义的标识符的原因:getPercent!

好吧,如果1的百分比发生变化,它将使您可以更轻松地进行更改...;)

您可以将其命名为PERCENT_TO_RATE_RATIO = 100

“一百”绝对没有100的用处,而且由于有人可能会忽略您的评论并对其进行更改,因此危害甚至更大。如果有任何证明,它符合“实用魔术数字规则”,并且不应为变量,无论是否为final。

#1 楼

以人类程序员的身份(即我不是Lint软件)来讲,您对那里的“ 100”的使用对我来说看起来很好。 IMO您的“ 100”与其他“可接受的”魔术数字属于同一类别。


此Wiki中描述魔术数字说了两件事。

首先,


实用幻数规则:如果文字的最有意义的变量名与文字的口语名称相同,则它不是幻数。


适用于此:您正在寻找诸如HUNDREDCENTUM之类的命名常量。

其次,它还建议从配置文件:

static final double DISCOUNT_PERCENT = getProperty( "sales.discount_percent" );
static final double DISCOUNT_FACTOR = 1 - (DISCOUNT_PERCENT / 100);

// ...

salePrice = DISCOUNT_FACTOR * regularPrice;


请注意,尽管此示例代码从配置中仔细加载了DISCOUNT_PERCENT,但是用于计算DISCOUNT_FACTOR的“ 100”是硬编码的。 />

如果您使用“ 100”代替q43 12079q,对于程序员来说更容易理解,并验证它是否正确。通过HUNDREDHUNDRED)。

评论


\ $ \ begingroup \ $
@janos则可以做回报率* 2 * 2 * 5 * 5;。因为它不包含幻数,所以容易得多。因为它已经被分解,所以也更容易阅读
\ $ \ endgroup \ $
–WernerCD
2014年3月11日17:31

\ $ \ begingroup \ $
我什至不同意您提到的“唯一好处”:搜索“一百”并不比搜索“ 100”容易。 100在这里并不是一个神奇的数字,也没有理由为了澄清某些短绒而降低清晰度。
\ $ \ endgroup \ $
–bdesham
2014年3月11日在21:34

\ $ \ begingroup \ $
@WernerCD:对不起,只有0,1和2不是魔术。 ITYM(速率<< 2)*(2 * 2 + 1)*(2 + 2 + 1)。
\ $ \ endgroup \ $
– MSalters
2014年3月12日在8:30

\ $ \ begingroup \ $
@WernerCD太复杂了! 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 。
\ $ \ endgroup \ $
– David Richerby
2014年3月12日在11:45

\ $ \ begingroup \ $
我首先想到的是,您肯定不应该在代码的比率和百分比之间进行转换,因为只有在显示给用户时才将比率用于所有计算和百分比。 Java是否没有很好的数字格式化方法来格式化双精度百分比字符串?
\ $ \ endgroup \ $
–克里斯
2014年3月12日在16:29

#2 楼

尽管100的源代码应该不错,但令我惊讶的是,没有人提供最易读的替代方法。这对于人类和皮棉代码都应该是可接受的:

定义常量PERCENT=0.01

然后,当您需要进行转换时:

rate = discount*PERCENT




discount = rate/PERCENT


这可以完全消除您的短函数(实际上是微不足道的)。您可能还有其他常量PERMILLEPPMPPB等,对于人类来说,正在发生的事情应该很明显。

评论


\ $ \ begingroup \ $
+100或者,如果您真的必须弄清常量的含义,则将其命名为PER_CENT,如“ per per一百”(百分比的定义)。
\ $ \ endgroup \ $
– David Harkness
2014年12月12日18:37

\ $ \ begingroup \ $
创建一个帐户来投票赞成。这比其他答案更好。
\ $ \ endgroup \ $
– bjb568
2014年3月13日在2:24

\ $ \ begingroup \ $
非常好,但是我相信内部表示存在一些警告...您可能需要为每种类型的数据(浮点数,双浮点数等)设置一个... 100(或常量使用100)更安全。请参阅:Java Double值= 0.01更改为0.009999999999999787或为什么不使用double或float表示货币或舍入错误
\ $ \ endgroup \ $
–奥利维尔·杜拉克(Olivier Dulac)
2014年4月3日在16:12



\ $ \ begingroup \ $
我真的不能说这更具可读性。特别是,折扣=费率/ PERCENT感觉很扭曲。如果没有非常清晰的名称,甚至没有,也很容易忘记PERCENT是0.01还是100。如果它被称为ONE_PERCENT之类的东西,我就不知道了……但是,它比它具有魔力被留下一个“魔术数字”。
\ $ \ endgroup \ $
– cHao
14-6-26在1:33



\ $ \ begingroup \ $
叹息。折扣* 0.01和比率/0.01与折扣/ 100和比率* 100不同。虽然100是正确的,但0.01不是。
\ $ \ endgroup \ $
–David Ongaro
2014年10月1日19:49



#3 楼

有些数字称为“魔术”,因为尚不清楚它们来自何处。我认为在这种特殊情况下,很明显100源自百分比的定义。但是,如果您愿意,可以定义一个常量PERCENTS_IN_UNIT_RATE=100而不是直接使用它。如果有疑问,请问其他从事同一项目的程序员,或者抛硬币然后转到下一个任务! :-)

评论


\ $ \ begingroup \ $
我不认为HUNDRED的可读性超过100。是的,它可以满足即时工具的抱怨,但是您可能会使用该工具来提高代码质量,正如我提到的那样,我认为这样做不行。 MAX_PERCENT更好,但仍然可能引发疑问。 PERCENT_MAX的声音类似于INT_MAX,但可能会稍好一些。 PERCENTS_IN_UNIT_RATE是最容易理解的,但也太长了。因此,我投票赞成保持原义100。
\ $ \ endgroup \ $
–mkalkov
2014年3月11日10:39



\ $ \ begingroup \ $
MAX_PERCENT似乎具有误导性,因为它暗示100只是可以随时更改的任意常数。在我看来,在狡猾的会计惯例之外,100几乎是不可变的:-)
\ $ \ endgroup \ $
– microtherion
2014年3月11日10:51

\ $ \ begingroup \ $
A100PERCENTS或ONE100PERCENTS或PERCENTS_100或X100PERCENTS都可以在IMO上工作。我喜欢它们,因为它们包括数字100,还包括单词百分比,使数值和上下文都显而易见。
\ $ \ endgroup \ $
–氢化物
2014年11月11日,11:13



\ $ \ begingroup \ $
如果我以1美元的价格购买山羊并以8美元的价格出售,那么我已经以其原始价格的800%出售了它。 MAX_PERCENT应该是等于DBL_MAX的常数。只需使用100,避免混乱。
\ $ \ endgroup \ $
–布伦丹
2014年3月11日17:39

\ $ \ begingroup \ $
我不知道PERCENTS_PER_UNIT_RATE中RATE的来源。因为您正在制定利率?但这绝对不会影响百分比和规模之间的转换。我建议PERCENT_PER_UNITY之类的。
\ $ \ endgroup \ $
– Ben Voigt
2014年3月11日在22:12

#4 楼

我对100是否是一个已命名的常量不满意。

我习惯性地将魔术数字命名为常量,但是并非一直如此....对于我来说,常称常量HUNDREDMILLION。我也经常将琐碎的数字用作幻数常数....

但是,在这种情况下,我特别想引起注意的是,您的值应该是浮点数,而不是整数值。

拥有常量时,常量应该采用最方便的形式供用户理解。例如,您的值100应该确实是100.0,这使它成为一个双精度值变得很明显。

评论


\ $ \ begingroup \ $
使用常数HUNDRED时,它是100还是100.0?
\ $ \ endgroup \ $
–乔纳斯·普拉卡(Joonas Pulakka)
2014年3月11日19:09

\ $ \ begingroup \ $
好的,但这只是一种可能性。仅举几例,HUNDRED也可以是BigInteger或BigDecimal或字节。使用数字文字,该类型立即显而易见。
\ $ \ endgroup \ $
–乔纳斯·普拉卡(Joonas Pulakka)
2014年12月12日7:36



\ $ \ begingroup \ $
如果您最终要处理大量的事情,我认为像MILLION这样的事情可能会派上用场,因为很容易将1000000误认为1000万,等等
\ $ \ endgroup \ $
– DLeh
2014年3月12日在20:09

\ $ \ begingroup \ $
如果在很多地方都使用HUNDRED,那么当您需要在这些地方的子集中对其进行更改并尝试更改常量时,就会感到困惑。这不会比对所有项目代码库执行sed's / 100/101 / g'更好。
\ $ \ endgroup \ $
–俄罗斯
2014年3月14日6:27



\ $ \ begingroup \ $
@DLeh 1_000_000
\ $ \ endgroup \ $
–贾斯汀
16-3-14在18:43

#5 楼

其他人已经陈述了为什么他们认为100是可接受的常数。此答案说明了如何使Sonar接受。

your-sonar-domain/profiles/下,您可以编辑质量配置文件以及其中的规则。 “魔术数字”规则是可自定义的,您可以为规则指定某些数字以使其忽略。只需将“ 100”指定为要忽略的数字即可。



#6 楼

从技术上讲,这是因为这两个100具有相同的上下文。类似于我在多个不同位置使用32作为宽度。这取决于您想要变得多么挑剔。在这种情况下,我可能会使用类似MAX_PERCENT的内容。自从我知道计算与百分比有关后,它的确也有助于提高可读性。

评论


\ $ \ begingroup \ $
如果看到使用MAX_PERCENT的代码,我会感到很开心
\ $ \ endgroup \ $
– Navin
2014年12月12日4:38在

\ $ \ begingroup \ $
我想为简洁起见不好。虽然被某事逗乐有助于记住它。
\ $ \ endgroup \ $
– 0xFADE
2014年3月12日在18:12

#7 楼

如果被迫使用符号,我可以称其为N100。这样,您就可以知道其价值。很久以前,我看到这对于常见常数是完成的。负数以“ M”为前缀。他们为什么这么做?因为计算机指令集无法在线加载数字(“立即”);它们必须从存储位置获取。汇编器使用符号来表示这些位置。

#8 楼

我认为100是一个神奇的数字。

百分比使用率很高,但也经常使用千分之一(1/1000),基点(1 / 10.000)和百分率(1 / 100.000 )已足够使用以拥有自己的名称。您可能仍想编写一个getPerPart(value, part),在这种情况下,可以使用硬编码100。

评论


\ $ \ begingroup \ $
您真的要为乘法和除法创建函数吗?为什么不让格式化程序以用户希望的方式显示数字呢?您不会在计算中使用这些函数。
\ $ \ endgroup \ $
– Navin
2014年3月15日5:55



#9 楼

任何未命名的数字仍然是魔术数字。与常用用法无关,因为常用用法是相对的。它的问题是“何时”或“何处”画一条线...一个数字何时将其状态更改为非魔术性...

2,71828 ...可能不是数学家的魔法(欧拉)

1760可能不是盎格鲁撒克逊人的魔法数字(码每英里码)

10000000可能不是南亚南部居民的魔法数字)

在乘法(中性元素)的上下文中1可能不是魔术。

相对方法将导致讨论,这将演变出局部的共识。将数字视为不可思议的结果取决于您在何时何地开始讨论。不幸的是,必须分别针对每个数字进行这种讨论。

绝对方法很简单:每个未命名的数字都是一个幻数。关于所有数字的讨论...当然,这只是一个定义。但是此定义具有内在属性,可以对其进行精确评估。

因此,如果您要讨论,请选择相对的方法。您会发现讨论永无止境。如果您认为它超出了另一个数字,那么就出现了。我按照以下定义进行第二种方法:每个未命名的数字都是魔术。即使您实际上忽略了它,该语句也保持不变。