2

I am trying to render a fractal called the "Lorenz Attractor" with Java. Because double does not work (values out of range), I decided to choose BigDecimals. After 38 iterations my code crashes, it gets me an ArithmeticException (Underflow). Heres some of the code:

BigDecimal xnew = this.x.add(this.hBig.multiply(BigDecimal.TEN).multiply(this.x.add(this.y.negate())));

//This is the line that crashes
BigDecimal ynew = this.y.add(this.hBig.multiply(this.x.negate().multiply(this.z)).add(ZWENTYEIGHT.multiply(this.x.add(this.y.negate()))));

BigDecimal znew = this.z.add(this.hBig.multiply(this.x.multiply(this.y).add(FRAC.multiply(this.z).negate())));

this.x = xnew;
this.y = ynew;
this.z = znew;
System.out.println("X="+this.x);
System.out.println("Y="+this.y);
System.out.println("Z="+this.z);
System.out.println("----------");

This is the output I get. Can I do anything against that? Sorry if the code doesn't look very good. I can also provide some pseudocode on how it should be done, tell me if you need that.

EDIT: This is the second line split up:

BigDecimal temp = ZWENTYEIGHT.multiply(this.x.add(this.y.negate()));
BigDecimal temp2 = this.x.negate().multiply(this.z);
BigDecimal temp3 = this.hBig.multiply(temp2); //This crashes.
BigDecimal temp4 = temp3.add(temp);
BigDecimal ynew = this.y.add(temp4);

EDIT2: This is some pseudocode:

do 4000 times
    xnew=x+h*10*(x-y)
    ynew=y+h*((-x*z)+28*x-y)
    znew=z+h*(x*y-8/3*z)
    x=xnew
    y=ynew
    z=znew
Distjubo
  • 959
  • 6
  • 21
  • This line is doing a lot of work. It could be crashing at many points. Try breaking this line into smaller pieces. – Brett Walker Apr 30 '15 at 12:58
  • Okay, done. Though I don't think it will really help, the underflow occurs anyways. – Distjubo Apr 30 '15 at 13:05
  • And which part of the line does it crash on now? – Evan Knowles Apr 30 '15 at 13:07
  • It did do something helpful. We now know that when hBig and temp2 are multiplied together an underflow may occur. Could you print out the value of hBig and temp2 when the underflow does occur? – Brett Walker Apr 30 '15 at 13:08
  • It seems pretty simple: the number you're ending up with is too small for your `BigDecimal` (configured through `MathContext`). Before your code crashes you've got an absurdly small number: `Z=0E-1502973310`. You'll need to scale your values so they're not so small. – Paul Apr 30 '15 at 13:10
  • temp2 has the value of 0E-1502973303, and hBig is a constant with the value of 0.1 – Distjubo Apr 30 '15 at 13:11
  • @Paul, I have no idea how to scale my values, could you please provide some code? – Distjubo Apr 30 '15 at 13:12
  • What I mean by scale is either multiply the values by a constant or start with larger numbers. You'll have to do that anyway if you're going to render values like `Y=0E-1502973304`, unless you've got a monitor the size of the Pacific Ocean :) – Paul Apr 30 '15 at 13:16
  • I use AffineTransform to scale/translate those lines on my screen, but I don't think I can use that for those BigDecimals. Another reason I chose BigDecimal was that I thought it was very accurate, I would like to keep that accuracy :) – Distjubo Apr 30 '15 at 13:18
  • Doesn't BigDecimal provide somethink like that out-of-the-box? – Distjubo Apr 30 '15 at 13:20
  • 1
    Since your numbers rapidly approach 0 I suggest checking your algorithm. I did a quick search and your p-code seems similar to (including values of constants) but not the same as the code here: http://www.algosome.com/articles/lorenz-attractor-programming-code.html – Paul Apr 30 '15 at 13:25
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/76649/discussion-between-distjubo-and-paul). – Distjubo Apr 30 '15 at 13:32
  • 2
    For others who may read this, I pasted the code from the website here: http://pastebin.com/8FeJXrLu – Paul Apr 30 '15 at 13:40
  • For all who read this: My algorithm is broken and the numbers keep dropping even though they should not. Look at Pauls last comment for further information :) – Distjubo Apr 30 '15 at 13:57

1 Answers1

3

While BigDecimal is much more powerful and flexible than double it does still have limits; namely its scale is an int:

A BigDecimal consists of an arbitrary precision integer unscaled value and a 32-bit integer scale.

This means that you cannot represent numbers larger or smaller than are scaled by a factor of more than 2^31. This is a massive (or minuscule) number (10^2^31 being the largest possible multiplier), and for almost any possible use case it's an impractical edge case to run into. By comparison there are "only" approximately 4×10^80 atoms in the universe.

So what does it mean if you're running into Overflow or Underflow errors? The scale of the numbers you're working with are so ludicrously large or small that BigDecimal can't support them. This all-but-certainly means you've made a logic error of some sort, and are aren't doing the operations you intended to - double-check your math.

Occasionally the problem is the order of operations - e.g. your result might be a reasonably sized number, but the intermediary steps are unworkable. Computing the binomial coefficient is an example of this. In such cases you need to experiment with other orders of operation that avoid such unreasonable numbers.

dimo414
  • 47,227
  • 18
  • 148
  • 244
  • Thank you for your extensive answer. My issue has been resolved over a year ago. Might be helpful for others though. – Distjubo Nov 11 '16 at 21:02