1

Completely new to programming, i come from only excel experience so any help appreciated. The expressions calculate the altitude and bearing of the sun given your latitude, the hour of the day t and day of the year day.

The altitude calculation works fine, however the bearing calculation has sporadic nonsence negative values in the output.

These values which are stored in their respective arrays will be later used for other claculations.

Here's my block of code:

#include <iostream>
#include <cmath>
using namespace std;   

float degrees(float radians) { // gets degrees
return (radians * (180 / 3.14));
}

float radians(float degrees) { //gets radians
return (degrees * (3.14 / 180));
}

int main()
{

float latitude = 54;
// cout << "Enter latitude (in degrees): ";
// cin >> latitude;

float const sin_thi = sin(radians(latitude));
float const cos_thi = cos(radians(latitude));

// cout << "sin_thi: " << sin_thi << endl;
// cout << "cos_thi: " << cos_thi << endl;

float cos_omega[24];

// required for later calculation

for (int t = 0; t <= 23; t++)
{
    cos_omega[t] = cos(radians((15 * (t - 12))));
    // cout << cos_omega[t] << endl;
}

// gathering sun altitude and bearing data, storing into heap multidimentional arrays "alt_sun[][]" and "bearing_sun[][]".

auto alt_sun = new int [365][24];
auto bearing_sun = new int [365][24];

for (int day = 0; day <= 364; day++)
{
    for (int t = 0; t <= 23; t++)
    {
        alt_sun[day][t] = degrees(asin(((0.4 * cos(radians(0.99 * (day - 173)))) * sin_thi) + ((sin(((0.4 * cos(radians(0.99 * (day - 173)))) - 1.57)))) * (cos_omega[t] * cos_thi)));

        if (cos_omega[t] > 0)
            bearing_sun[day][t] = 360 - degrees(acos((((0.4 * cos(radians(0.99 * (day - 173)))) * cos_thi) - ((sin(((0.4 * cos(radians(0.99 * (day - 173)))) - 1.57))) * (cos_omega[t] * sin_thi))) / (cos(radians(alt_sun[day][t])))));

        else
            bearing_sun[day][t] = degrees(acos((((0.4 * cos(radians(0.99 * (day - 173)))) * cos_thi) - ((sin(((0.4 * cos(radians(0.99 * (day - 173)))) - 1.57))) * (cos_omega[t] * sin_thi))) / (cos(radians(alt_sun[day][t])))));         
    }
}

for (int day = 0; day <= 364; day++) // to test calculation
{
    cout << "Day " << day << ":   " << bearing_sun[day][12] << endl;
}
}

Is there something fundamentally wrong with what im doing?

Expected results for the printed bearing values are to range from about 350 - 360 (roughly due to rounding on my previously made excel calculation). For example the first value should be about 355.

The code should run without user input and the problem should be explicit now.

My first thought was that the bad results were only happening when the else statement was used in the loop. But my limited amateur testing, like just running the single expression outside of the for loop and if statement, produced the same results. Which in my mind leaves only the expression itself, or the array as a possible cause.

An example screenshot of some of the output to the console, all the positive values are correct, all the negative values are wrong

Thanks

  • 1
    Have you tried running your code line-by-line in a debugger while monitoring the values of all variables, in order to determine in which line your program stops behaving as intended? If you did not try this, then you may want to read this: [What is a debugger and how can it help me diagnose problems?](https://stackoverflow.com/q/25385173/12149471) You may also want to read this: [How to debug small programs?](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/) – Andreas Wenzel Oct 09 '22 at 12:11
  • Updated the post to include #inlcudes and expected results, thanks for the advice. I will look into the debugger next. I will say i have manually ran my code almost line by line (as i'm yet to learn all the features of Visual Studio), and everything seems to check out, at least in terms of the values they produce. I'm still learning about memory management, allocation etc. – Toby Tanfield Oct 09 '22 at 14:03
  • Welcome to Stack Overflow. "This was previously two seperate for loops, one for the altitude and one for the bearing, then i realised i could maybe put them together" Well, **did it work before**? After changing the code, **exactly what is different** in the output? Do you notice any pattern to **where** the wrong values are, or **how** they are wrong? – Karl Knechtel Oct 09 '22 at 14:19
  • "Expected results for a latitude of 54 and any day and for t = 12 are values ranging from about 350 - 360 (roughly due to rounding on my previously made excel calculation)." Does this mean the expected altitude values, or the expected bearing values? What are the expected results for the other array? What results do you get instead? – Karl Knechtel Oct 09 '22 at 14:21
  • 1
    Please read [mre] and make sure (by *trying it yourself* before posting) that someone else can **copy and paste** the code in the question, compile and run it, and *directly* see the *exact* problem you describe. Unless it's *necessary* to demonstrate the problem, the code should hard-code input values rather than asking for input, and should not do any work outside of what is relevant to the problem being described. The code in the question clearly does not meet this standard; for example, it's missing braces for the `main` function. – Karl Knechtel Oct 09 '22 at 14:24
  • Sorry, all fixed now, the code will run as intended without the need for any edits. And i removed the needless statement about the previous work, it also didn't work. – Toby Tanfield Oct 09 '22 at 14:35
  • When I run your program with [UndefinedBehaviorSanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html) active, I get a run-time error message in line 48 and 51 that you are converting a [NaN](https://en.wikipedia.org/wiki/NaN) to an integer, which invokes undefined behavior. It seems that your calculations are producing a NaN. The error on line 51 already happens on Day 0. – Andreas Wenzel Oct 09 '22 at 14:53
  • Okay so probably the expression is the issue. I have checked it countless times, and it is precisely what it should be. Although, in excel it was as simple as refering to another cell. The difference here is this, i'm using the `alt_sun[day][t]` value inside the `for` loop to calculate `bearing_sun[day][t]` . In regards to programming, is what im doing inside the loop okay? Or do variables for expressions (In this case `alt_sun[day][t]`) in loops have to be previously defined? – Toby Tanfield Oct 09 '22 at 15:11
  • @TobyTanfield: All variables must be defined before use, but it is sufficient to define them before the loop. They don't have to be defined inside the loop. – Andreas Wenzel Oct 09 '22 at 17:46

2 Answers2

1

When I run your program with UndefinedBehaviorSanitizer active, I get a run-time error message in line 48 and 51 that you are converting a NaN to an integer, which invokes undefined behavior. This means that your calculatings are producing a NaN.

When I run your program line by line in a debugger, I notice that when line 51, which is

bearing_sun[day][t] = degrees(acos((((0.4 * cos(radians(0.99 * (day - 173)))) * cos_thi) - ((sin(((0.4 * cos(radians(0.99 * (day - 173)))) - 1.57))) * (cos_omega[t] * sin_thi))) / (cos(radians(alt_sun[day][t])))));

is executed for the first time, it writes the value

-2147483648

into bearing_sun[0][0], which does not seem to be the intended value.

Since this line is a very long line, I modified it to several lines, so that I can examine the intermediate results more easily:

else
{
    auto intermediate_result_1 = (0.4 * cos(radians(0.99 * (day - 173)))) * cos_thi;
    auto intermediate_result_2 = sin(((0.4 * cos(radians(0.99 * (day - 173)))) - 1.57));
    auto intermediate_result_3 = cos_omega[t] * sin_thi;
    auto intermediate_result_4 = cos(radians(alt_sun[day][t]));
    auto intermediate_result_5 = intermediate_result_2 * intermediate_result_3;
    auto intermediate_result_6 = intermediate_result_1 - intermediate_result_5;
    auto intermediate_result_7 = intermediate_result_6 / intermediate_result_4;
    auto intermediate_result_8 = acos( intermediate_result_7 );
    auto intermediate_result_9 = degrees( intermediate_result_8 );

    bearing_sun[day][t] = intermediate_result_9;
}

This code is much easier to inspect when running the code line by line in a debugger, because you can see the intermediate results.

When I reach the line

auto intermediate_result_8 = acos( intermediate_result_7 );

I can see in the debugger that intermediate_result_7 has the value -1.0009622545441585. Since this is invalid input for the function acos, it will correctly return NaN, so that the final result also is NaN, which is converted to an int, which invokes undefined behavior. This explains the "nonsense negative values" that you mentioned in the question.

Therefore, there appears to be something wrong with the formula that you are using. In order to find the problem, you will have to run the program line by line in a debugger, checking the values of all of the intermediate results.

Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39
0

A rouding error that only affected the calculation when the value was close to the limits of what acos() can accept (between -1 and 1), returning a NaN, invoking undefined behaviour once converted to an int.