0

I'm currently reading through the MEAP book Tiny C Projects by Dan Gookin. In the opening chapter he presents a small daily greeting program which also reports the phase of the moon. The calculations in the book for this look very strange - he also states outright that he doesn't know where he first got this code from or even what it's doing; it also doesn't have any comments or links to any other explanatory information. This is my cleaned-up rendition of it:

int moonphase_from_tm(struct tm* datetime)
{
    int year  = datetime->tm_year;
    int month = datetime->tm_mon;
    int day   = datetime->tm_mday;

    if (month == 2)
    {
        day += 31;
    }
    else if (month > 2)
    {
        day += 59 + (month - 3) * 30.6 + 0.5;
    }

    int g = year % 19;
    int e = (11 * g + 29) % 30;

    if (e == 25 || e == 24)
    {
        ++e;
    }

    int phase = ((((e + day) * 6 + 5) % 177) / 22 & 7);
    
    return phase;
}

It returns an int used to index a string out of a char* array describing the current moon phase.

Can anybody figure out what this is actually doing? I looked up moon phase calculations on Google and can't find anything that bears more than a passing resemblance to this. It also isn't entirely accurate with the entire thing being calculated with ints (it's out by a day or so, checking against some moon-phase tracking websites), which makes finding something similar a little more difficult.

Below is the original old-style version as reproduced in the book; when calling it, the author adds 1900 to the date, but then this is immediately subtracted again on line 13 when assigning to g, so I just didn't bother doing either:

int moonphase_book_verbatim(int year, int month, int day)
{
    int d, g, e;

    d = day;
    if (month == 2)
    {
        d += 31;
    }
    else if (month > 2)
    {
        d += 59 + (month - 3) * 30.6 + 0.5;
    }

    g = (year - 1900) % 19;
    e = (11 * g + 29) % 30;

    if (e == 25 || e == 24)
    {
        ++e;
    }

    return ((((e + d) * 6 + 5) % 177) / 22 & 7);
}
jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Rowan
  • 351
  • 2
  • 13
  • 1
    It seems to me that this question has not much to do with programming. You might have better luck on https://astronomy.stackexchange.com/ if you first extract the math from the code, then describe it in clear, human language as well as mathematical formulas in standard notiation. – Szabolcs Dec 01 '21 at 16:19
  • 1
    It is a great example however, on the absurdity of [magic numbers](https://stackoverflow.com/questions/47882/what-is-a-magic-number-and-why-is-it-bad) – infinitezero Dec 01 '21 at 16:20
  • BTW if I were a reviewer of that book, I would give the author a hard time over such an "I don't understand this calculation but here it is anyway" example, especially since it's supposed to be an introductory example. – Szabolcs Dec 01 '21 at 16:22
  • What is it you don't understand? The C code or what it calculates? – Support Ukraine Dec 01 '21 at 16:24
  • @Szabolcs Very true - and good suggestion, thank you! I did wonder if there was some C-specific behaviour involved in it's calculation though, especially looking at the `else if` block where an `int` is multiplied by and added to two `float`s and then put back into an `int`, order of operations, etc... – Rowan Dec 01 '21 at 16:24
  • I can find some of the constants in other moon-phase calculations. For example 30.6 appears as a constant in this [moon-phase algorithm.](https://www.subsystems.us/uploads/9/8/9/4/98948044/moonphase.pdf). Taking the year mod 19 seems to be a simplification allowed by the [Metonic cycle](https://en.wikipedia.org/wiki/Metonic_cycle). – Nick ODell Dec 01 '21 at 16:25
  • @4386427 I don't understand how it calculates what it does. The output is just an `int` between 0 - 7 which refers to a moon phase. The actual code is pretty straightforward, save for a few oddities; so, it's the oddities and the calculation itself that I'm lost on. As @Szabolcs said, post is probably just not the best fit for this board. – Rowan Dec 01 '21 at 16:26
  • The only C trick is this part: `d += 59 + (month - 3) * 30.6 + 0.5;` The RHS is a floating point calculation but the result is stored in an integer. That has some special implications. The rest is very basic. – Support Ukraine Dec 01 '21 at 16:28
  • I’m voting to close this question because the question is not about programming – Support Ukraine Dec 01 '21 at 16:28
  • It looks like a very complicated way of calculating `int moonphase(time_t t) { return lround(8*(t - reference_new_moon_time)/(24*60*60*29.53059))&7; }`. – Yakov Galka Dec 01 '21 at 18:59

0 Answers0