用BigDecimal等效替换Java数学运算符

时间:2016-07-06 22:09:43

标签: java metaprogramming

我有一个程序可以使用标准数学运算符在doubles上进行数学运算的Java代码片段,如下所示:

double someVal = 25.03;
return (someVal * 3) - 50;

对于原因(主要是舍入错误),我想更改所有这些片段以使用BigDecimal而不是double,修改数学函数,如下所示:

MathContext mc = MathContext.DECIMAL32;
BigDecimal someVal = new BigDecimal("25.03", mc);
return someVal.multiply(BigDecimal.valueOf(3), mc).subtract(BigDecimal.valueOf(50), mc);

这些片段大多非常简单,但如果可以,我宁愿避免使用脆弱的解决方案(例如正则表达式)。是否有相对简单的方法来做到这一点?

注意我想让程序或代码执行这些修改(元编程)。很明显,我能够手工改变,但生命太短暂。

3 个答案:

答案 0 :(得分:0)

你可以试试Google的“Refaster”,根据the paper,它是“使用普通的,可编译的前后Java代码示例来指定Java重构的工具。”

代码位于Google core/src/main/java/com/google/errorprone/refastererror-prone github project下。 (它曾经生活在自己的github project。)

这更像是一个提示,而不是一个答案,因为我从未直接使用过Refaster,也不知道它对原始表达式的效果如何,就像你的例子中那样。我也不知道像你这样的工具链使用它有多适合,而不是一次性重构(Google倾向于使用它)。但是它得到了积极的维护,而且我看到它在过去使用得非常有效。

答案 1 :(得分:0)

我们使用BigDecimal进行财务计算。根据其他评论,您将会有一些性能下降,代码将很难阅读。性能影响取决于您将拥有多少操作。通常,当计算链很长时,您会面临双打的舍入问题。如果您执行c=a+b,则不会有很多问题,但如果您有c+=a+b百万次,则会遇到很多问题。通过一千次操作,您会注意到bigDecimal的速度比double慢,因此性能测试也是如此。

在更改代码时要小心,特别是在划分时,您必须指定舍入模式和结果的比例,这是人们通常不会做的,并且会导致错误。

我认为不仅要更换计算逻辑,而且还需要更改域模型,所以我怀疑你能否在合理的时间内完成一个脚本,所以请亲自动手。好的IDE会对你有所帮助。

无论您如何转换代码,我建议首先确保所有计算逻辑都包含在单元测试中,并在更改逻辑之前进行单元测试转换。即通过用bigDecimals包装来替换值的断言。在这种情况下,您将避免愚蠢的输入/算法错误。

我不会回答你的问题如何从double转换为BigDecimal只想分享一些注释到

答案 2 :(得分:-2)

不要这样做。

  • 这是一个巨大的可读性。您的示例将“25.03 * 3 - 50”变为4行代码。
  • 财务代码通常使用doublelong作为分数。它足够精确,只是一个正确编程的问题,以避免舍入错误:What to do with Java BigDecimal performance?
  • 这可能是一个巨大的性能损失,特别是垃圾收集不稳定,这对于HFT等是不可接受的:https://stackoverflow.com/a/1378156/1339987
  • 我不知道你说的代码有多少,但我确实希望你做出很多小的决定。这减少了有一个公开可用工具的机会(我几乎肯定不存在),并增加了配置工作量,如果你找到它,你将不得不这样做。
  • 除非您有非常好的测试覆盖率,否则这会引入错误,原因与您希望它有所改进相同。

此处介绍了以编程方式操作Java源代码:Automatically generating Java source code

你不需要接受这个答案,但我相信我的建议是正确的,并认为这个问题的其他读者需要预先看到进行这种转换的情况,这是我的发布这个有点非慷慨的理由。