2

I need to convert the following python code to Java and remember from the past that handling decimal values must be done carefully otherwise the results will not be accurate. My question is, can I use doubles for all non-interger values given doubles are more accurate that floats?

Here is my start of the conversion:

Python code

def degrees(rads):
    return (rads/pi)*180


def radians(degrees):
return (degrees/180 * pi)


def fnday(y, m, d, h):
a = 367 * y - 7 * (y + (m + 9) // 12) // 4 + 275 * m // 9
a += d - 730530 + h / 24
return a

Java conversion

public double degress(double rads)
{
    return (rads/PI)*180;
}

public double radians(double degrees)
{
    return (degrees/180 * PI);
}

public double fnday(int y, int m, int d, int h)
{
    double a = 367 * y - 7 * (y + (m + 9) / 12) / 4 + 275 * m / 9;
    a += d - 730530 + h / 24;
    return a;
}

I know it may be a simple answer but I need to know the postion of the moon and sun for the app and do not want to rely on an api for this data. I simple want to put in the latitude and longitdue and get the sun and moon rise and set times.

Chiheb Nexus
  • 9,104
  • 4
  • 30
  • 43
timv
  • 3,346
  • 4
  • 34
  • 43
  • 1
    Using an API like mine ([Time4J](http://time4j.net/javadoc-en/net/time4j/calendar/astro/package-summary.html)) would be much easier and enables good precision (fine agreement with official USNO-data) and offers easy transformation of results to `java.time`-types. On Android, you can use [Time4A](https://github.com/MenoData/Time4A). – Meno Hochschild Jan 29 '18 at 12:53

2 Answers2

3

Using a double for each variable would suffice; however, you have an issue that results from integer division:

double a = 367 * y - 7 * (y + (m + 9) / 12) / 4 + 275 * m / 9;

If I were you, I'd change y, m, d, and h to all be doubles, so you retain the decimal places when dividing:

public double fnday(double y, double m, double d, double h) {
    double a = 367 * y - 7 * (y + (m + 9) / 12) / 4 + 275 * m / 9;

    a += d - 730530 + h / 24;

    return a;
}
Jacob G.
  • 28,856
  • 5
  • 62
  • 116
0

If you need a really big precision, the best way is use, java.lang.BigDecimal, that extends from java.math.Number.

You can even use your existing doubles if you need:

double d = 67.67;
BigDecimal bd = new BigDecimal(d);

But you will need to use the methods from the class like this:

public BigDecimal degress(BigDecimal rads)
{
    BigDecimal pi = new BigDecimal(PI);
    return (rads.divide(pi))*180;
}
developer_hatch
  • 15,898
  • 3
  • 42
  • 75
  • Given I only need accuracy to within 5 minutes do you think I should use BigDecimal instead of double as I am at the start of the conversion process? – timv May 30 '17 at 01:10
  • 1
    @timv It's sure to be much more accurate, I can't figure out how much precision do you need, but if I were you, and I'm looking for more precision, I would use that. Be careful be cause if you initialize BigDecimal with doubles you drag with it the precision, look it also https://stackoverflow.com/questions/9795364/java-bigdecimal-precision-problems – developer_hatch May 30 '17 at 01:14
  • 1
    Funny to suggest to use BigDecimal to then use it with its deprecated double constructor. – GhostCat May 30 '17 at 01:22
  • Maybe I can keep them as doubles during the conversion, run some tests with a few locations (lats, lngs) and then test again replacing the doubles with BigDecimals. I will then answer my question with my findings. – timv May 30 '17 at 01:26
  • Fantastic! @timv Let me know how it worked for you :D – developer_hatch May 30 '17 at 01:28
  • Big precision is not achieved by using `BigDecimal` instead of `double` but rather by choosing a suitable astronomical algorithm! – Meno Hochschild Jan 29 '18 at 12:57