0

for some reason I found myself coding some piece of software, that should be able to perfom some astronomic calculations. While most of it will be about transfering the correct formula into Java, I found an annoying Problem right at the verry beginning of my "test how to calculate big numbers".

Well... Imagine the Sun (our Sun), which has a mass of (about and rounded, for more easy explaining) 10E30 kg. Ten with 30 following Zeros. All native datatypes are just unusuable for this. To mention: I KNOW that I could use 3000 to calculate things and just add trailing zeros in the output-view, but I hoped to keep it as precise as possible. So using short numbers will be my last resort only.

Comming to the Problem. Please have a look at the code:

    BigDecimal combinedMass = new BigDecimal(1E22);
    int massDistribution = 10;
    Integer mD1 = massDistribution;
    Integer mD2 = 100 - massDistribution;
    BigDecimal starMass;
    BigDecimal systemMass;

    systemMass = combinedMass.divide(new BigDecimal("100")).multiply(new BigDecimal(mD1.toString()));
    starMass = combinedMass.divide(new BigDecimal("100")).multiply(new BigDecimal(mD2.toString()));

    System.out.println((systemMass).toEngineeringString());
    System.out.println((starMass));

It will output 1000000000000000000000 and 9000000000000000000000, whats exactly what I did expect. But look at the combineMass Field. If I raise it to 1E23, the Output will change

I get 9999999999999999161139.20 and 89999999999999992450252.80...

So I know I could use jut BigInteger, because its more reliable in this case, but for the sake of precicion, sometimes the BigWhatEver may drop to something like 50.1258 Plus, I hope to get the 10.xE30 as output, whats only possible using bigDecimals.

I want to know: Is there no way avoidng this (that error appers above 1E23 for every value I tried), while keeping the ability to calculate Floating-Points? Should I cut the After-Decimal-Separator-Values for this Field to two digets?

And for something more to wonder about:

System.out.println(combinedMass.precision());

in relation with the code above will provide 23 for that case, but En+1 for most other values (Thats was when I grow really confused)

Thanks for advise.

Confused Merlin
  • 127
  • 1
  • 8
  • Your exemple is interesting on a mathematical point of view, but *strange* on a physical one : are you sure the mass of the sun is precise at 1kg ? Double precision is generaly considered precise enough for astronomic computations . – Serge Ballesta May 29 '14 at 12:44
  • You may have a point with this... even the sources over Internet confirm, that the mass is evaluated at best. (note to myself; no Enter in Comments to add new line). But I will need smaller values than the 1E30kg for the sun, because its a superclass for ALL bodys worthwile being calculates... from a sun down to some asteroids; thats why I want to use BigDecimal: to enable every body using the same Field for its mass. – Confused Merlin May 29 '14 at 18:04

1 Answers1

3

You're using basic types without realizing it:

new BigDecimal(1E22);

Here, 1E22 is a primitive double, and you already lost precision by using it.

What you want is

new BigDecimal("10000000000000000000000");

or

new BigDecimal(10).pow(22);
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • Well, I have to agree that this is something I didn't even consider to be a cause for that problem... so 1En may do toString, than Split in two bits, placing the second one into a double... uh. Thanks for advice! One thing left... the User. I was looking forward to enable a given User entering the mass by typing in "15E4", but... well, I got an idea how to do this anyway ;) – Confused Merlin May 29 '14 at 18:11
  • You can just type `new BigDecimal("1E22")` (`1E22` being within double quotes, so it's passed-in as a string) – Erwin Bolwidt Jun 01 '14 at 10:22