是否有一种普遍接受的编码复杂数学的最佳方法?例如:
double someNumber = .123 + .456 * Math.Pow(Math.E, .789 * Math.Pow((homeIndex + .22), .012));
这是一个硬编码数字的点吗?或者每个数字是否都有与之相关的常数?或者还有其他方法,比如在配置中存储计算并以某种方式调用它们?
会有很多像这样的代码,我试图让它保持可维护性。
注意:上面显示的示例只是一行。这些代码行将有数十或数百行。而且不仅数字会改变,而且公式也可以改变。
答案 0 :(得分:20)
通常,有两种常量 - 对实现有意义的常量,以及对业务逻辑有意义的常量。
可以对第一类常量进行硬编码:它们对于理解算法是私有的。例如,如果您使用ternary search并且需要将间隔分为三个部分,则除以硬编码的3
是正确的方法。
另一方面,具有程序代码之外含义的常量不应该是硬编码的:赋予它们明确的名称可以让您在离开公司之后维护代码的人有非零的机会进行正确的修改不得不从头开始重写或通过电子邮件向您寻求帮助。
答案 1 :(得分:4)
“没关系”?当然。据我所知,没有一支准军事警察部队围捕那些违背编程的真正信仰的人。 (然而。)。
这是明智的吗?
嗯,有各种各样的决定方法 - 性能,可伸缩性,可扩展性,可维护性等。
在可维护性范围内,这是纯粹的邪恶。它使得可扩展性非常难;性能和可扩展性可能不是一个大问题。
如果你留下一个方法,其中包含类似于上面的大量行,你的继任者将无法维护代码。他建议改写是正确的。
如果你将其分解为
public float calculateTax(person)
float taxFreeAmount = calcTaxFreeAmount(person)
float taxableAmount = calcTaxableAmount(person, taxFreeAmount)
float taxAmount = calcTaxAmount(person, taxableAmount)
return taxAmount
end
并且每个内部方法都是几行,但是你在那里留下了一些硬编码的值 - 好吧,不是很棒,但并不可怕。
但是,如果某些硬编码值可能会随着时间的推移而变化(如税率),则将它们保留为硬编码值并不合适。太可怕了。
我能给出的最好建议是:
答案 2 :(得分:2)
我经常问自己,在编写代码六个月后,我是否可以在凌晨3点维护并修复代码。它对我有好处。看看你的公式,我不确定我能不能。
年龄前我在保险业工作过。我的一些同事的任务是将精算公式转换为代码,首先是FORTRAN和后来的C.数学和编程技能因同事而异。我学到的是以下回顾他们的代码:
也就是说,有时硬编码只是简化了事情,特别是如果在特定的上下文中很好地理解了这些值。例如,将某个值除以(或乘以)100或1000,因为您将值转换为美元。另一个是当你想要将小时数转换为秒时,将某些东西乘以3600。它们的意义往往来自更大的背景。以下内容并未详细说明幻数100:
public static double a(double b, double c)
{
return (b - c) * 100;
}
但以下内容可能会给你一个更好的提示:
public static double calculateAmountInCents(double amountDue, double amountPaid)
{
return (amountDue - amountPaid) * 100;
}
答案 3 :(得分:1)
正如上述评论所述,这远非复杂。
然而,您可以将 Magic 数字存储在常量/ app.config值中,以便下一位开发人员更容易保护您的代码。
存储此类常量时,请务必向下一位开发人员解释(1个月内自己阅读)您的想法是什么,以及需要记住的内容。
另外,ewxplain实际计算的内容和内容。
答案 4 :(得分:1)
不要像这样离线。
常量,以便您可以重复使用,轻松查找,轻松更改,并在有人第一次查看您的代码时提供更好的维护。
如果可以/应该自定义,您可以进行配置。客户改变价值的影响是什么?有时最好不要给他们这个选择。当事情不起作用时,他们可以自己改变它然后责备你。然后,也许他们比你的发布时间表更频繁地使用它。
答案 5 :(得分:0)
值得注意的是C#编译器(或它是CLR)将自动内联1行方法,因此如果您可以将某些公式提取到一个衬里中,您可以将它们作为方法提取而不会造成任何性能损失。
编辑:
常数等等或多或少取决于团队和使用量。显然,如果你不止一次使用相同的硬编码数字,那就不变了。但是,如果您正在编写一个公式,它可能只会编辑(小团队),那么硬编码值就可以了。这完全取决于您的团队对文档和维护的看法。
答案 6 :(得分:0)
如果您的行中的计算为下一个开发人员解释了一些内容,那么您可以保留它,否则最好在代码或配置文件中计算常量值。
我在生产代码中发现了一行,如:
int interval = 1 * 60 * 60 * 1000;
没有任何评论,原始开发人员在几毫秒内意味着1 hour
,而不是看到3600000
的值。
IMO可能会遗漏计算对于这样的场景更好。
答案 7 :(得分:0)
可以添加名称以用于文档目的。所需的文件数量在很大程度上取决于目的。
请考虑以下代码:
float e = m * 8.98755179e16;
与下面的对比:
const float c = 299792458;
float e = m * c * c;
即使后者中的变量名称不是非常“描述性”,您也可以更好地了解代码在第一个中执行的操作 - 可以说没有必要将c
重命名为{{ 1}},speedOfLight
到m
和mass
能量,因为名称在其域中是解释性的。
e
我认为第二个代码是最清晰的 - 特别是如果程序员可以期望在代码中找到STR(LHC模拟器或类似的东西)。总结一下 - 你需要找到一个最佳点。代码越详细,您提供的上下文越多 - 这可能有助于理解其含义( const float speedOfLight = 299792458;
float energy = mass * speedOfLight * speedOfLight;
和e
与我们对光的质量和速度做什么相比)并模糊大局(我们将c平方并乘以m与扫描整条线的需要得到方程式)。
大多数常数都有一些更深层次的修饰和/或已建立的符号所以我会考虑至少按惯例命名(c
表示光速,c
表示气体常数,R
以小时为单位)。如果表示法不明确,则应使用较长的名称(名为sPerH
的班级中的sPerH
或Date
可能正常,但不在Time
中。真正明显的常量可以是硬编码的(例如,在计算合并排序中的新数组长度时除以2)。