1

I have a program that works with snippets of Java code that do math on doubles using the standard mathematical operators, like this:

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

For Reasons (mostly rounding errors) I would like to change all these snippets to use BigDecimal instead of double, modifying the math functions along the way, like this:

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

The snippets are mostly pretty simple, but I would prefer to avoid a fragile solution (eg, regex) if I can. Is there a relatively straightforward way to do this?

Note I want to have a program or code perform these modifications (metaprogramming). Clearly I'm capable of making the changes by hand, but life is too short.

Brian Reischl
  • 6,855
  • 1
  • 32
  • 46
  • I know no easy way to refactor / transform that code. But wouldn't it be enough to format the output so that rounding errors don't become visible like with 99% of all programs out there that work fine with `double`? – zapl Jul 06 '16 at 22:16
  • I don't think it's a good idea since your resulting code is much less readable. I'd need to hear more of your reasons. It seems better to just round correctly. – djechlin Jul 06 '16 at 22:19
  • *Much* less readable. "25.03*3-50" took four lines of code. – djechlin Jul 06 '16 at 22:21
  • http://stackoverflow.com/q/5745721/1339987 pretty much covers it... – djechlin Jul 06 '16 at 22:23
  • It's not a matter of formatting. This is part of program that's doing financial calculations, so we just can't handle the rounding errors. – Brian Reischl Jul 06 '16 at 22:25
  • On the other hand, is this performance critical? Like at all? – djechlin Jul 06 '16 at 22:26
  • The transformation code is not, because it can be done ahead of time and saved somewhere. The resulting snippets are important for performance. – Brian Reischl Jul 06 '16 at 22:27
  • If regex can cover most of the cases, and this is a one-off task, you should consider it. – xiaofeng.li Jul 06 '16 at 22:28
  • http://stackoverflow.com/a/612063/1339987 – djechlin Jul 06 '16 at 22:28
  • BigDecimal is orders of magnitude slower than double. Profile before migrating. – djechlin Jul 06 '16 at 22:32

3 Answers3

0

You could try Google's "Refaster", which, according to the paper, is "a tool that uses normal, compilable before-and-after examples of Java code to specify a Java refactoring."

The code lives under core/src/main/java/com/google/errorprone/refaster in Google's error-prone github project. (It used to live in its own github project.)

This is more of a hint than an answer, though, since I've never worked directly with Refaster and don't know how well it does on primitive expressions like the ones in your example. I also don't know how well-suited it is for toolchain use like yours, vs. one-time refactors (which is how Google tends to use it). But it's actively maintained, and I've seen it used really effectively in the past.

dbort
  • 902
  • 7
  • 13
0

We use BigDecimal for financial calculation. As per other comments, you going to have some performance degradation and the code will be very hard to read. The performance impact depends on how many operation you going to have. Usually, you facing rounding issues with doubles when your calculation chain is long. You wouldn't have many issues if you do c=a+b but will if you have c+=a+b million times. And with a thousand of operations, you will notice how bigDecimal are slower than double, so do performance testing.

Be careful when changing your code especially with the division, you will have to specify rounding mode and scale of the result, this what people usually wouldn't do and it leads to the errors.

I assume it not only about replacing calculation logic but also you'll need to change your domain model so I doubt you can come up with a script to do it in a reasonable time, so do it by hands. Good IDE will help you a lot.

No matter how you going to convert your code I suggest to firstly make sure that all your calculation logic covered by unit tests and do unit test conversion before changing the logic. I.e replace assertion of the values by wrapping them with bigDecimals. In that case, you will avoid silly typing/algorithm mistakes.

I would not answer your question how to convert from double to BigDecimal just want to share some notes regaridng to the

Mikhail Chibel
  • 1,635
  • 1
  • 17
  • 31
-2

Don't do this.

  • It's a huge readability hit. Your example turned "25.03 * 3 - 50" into 4 lines of code.
  • Financial code usually uses double, or long for cents. It's precise enough that it's just a question of proper programming to avoid rounding errors: What to do with Java BigDecimal performance?
  • It's, likely, a huge performance hit, in particular with erratic garbage collections, which is not acceptable for HFT and the like: https://stackoverflow.com/a/1378156/1339987
  • I don't know how much code you are talking about but I do expect you will have to make lots of small decisions. This reduces the chance there is an openly available tool (which I'm all but sure does not exist) and increases the amount of configuration work you would have to do should you find one.
  • This will introduce bugs for the same reason you expect it to be an improvement, unless you have extremely good test coverage.

Programmatically manipulating Java source is covered here: Automatically generating Java source code

You don't need to accept this answer but I believe my advice is correct and think other readers of this question need to see up-front the case for not making this transformation, which is my rationale for posting this somewhat nonanswer.

Community
  • 1
  • 1
djechlin
  • 54,898
  • 29
  • 144
  • 264
  • 2
    "Financial code usually uses `double`." Wrong, and wrong to do. See https://spin.atomicobject.com/2014/08/14/currency-rounding-errors/ (complete with Stackoverflow references) for why. – Lew Bloch Jul 06 '16 at 22:48
  • @LewBloch well, my source was a top 10 rep user here who "has since designed three different trading systems for different funds and used double for prices or long cents" (as I linked). You can DV but I'm leaving as is. – djechlin Jul 06 '16 at 22:50
  • @LewBloch actually, edited to note `long`, which also makes much more sense to me than BD. – djechlin Jul 06 '16 at 22:51