1

I'm writing a class which should calculate angles (in degrees), after long trying I don't get it to work.

When r = 45 & h = 0 sum should be around 77,14°

but it returns NaN - Why? I know it must be something with the Math.Atan-Method and a not valid value.

My code:

    private int r = 0, h = 0;
    public Schutzwinkelberechnung(int r, int h)
    {
        this.r = r;
        this.h = h;
    }
    public double getSchutzwinkel()
    {
        double sum = 0;

        sum = 180 / Math.PI * Math.Atan((Math.Sqrt(2 * h * r - (h * h)) - r * Math.Sin(Math.Asin((Math.Sqrt(2 * h * r)) / (2 * r)))) / (h - r + r * (Math.Cos(Math.Asin(Math.Sqrt(2 * h * r) / (2 * r))))));

        return sum;
    }

Does someone see my mistake? I got the formula from an excel sheet.

EDIT: Okay, my problem was that I had a parsing error while creating the object or getting the user input, apparently solved it by accident. Ofc I have to add a simple exception, as Nick Dechiara said. Thank you very much for the fast reply, I appreciate it.

EDIT2: The exception in my excel sheet is:

if(h < 2) {h = 2}

so that's explaining everything and I wasn't paying attention at all. Thanks again for all answers.

int r = 45, h = 2;
sum = 77.14°
maddy
  • 13
  • 4
  • 2
    You should break it down into smaller steps and follow the logic with a debugger. That is literally what any of us would do, so you might as well start practicing debugging – maccettura Dec 14 '18 at 21:49
  • What is the type of `h` and `r`? Can you provide the full example of calling it? – nemanja228 Dec 14 '18 at 21:50
  • @nemanja228 I would assume `h` and `r` are `int` 's given their values. `sum` would be a double implicitly (its returning `double.NaN`), but OP _could_ have declared it as something else – maccettura Dec 14 '18 at 21:51
  • 3
    You're dividing by 0 (this `h - r + r * (Math.Cos(Math.Asin(Math.Sqrt(2 * h * r) / (2 * r))))` resolves to 0) – MikeH Dec 14 '18 at 21:51
  • 1
    @BurnsBA barely made it! – MikeH Dec 14 '18 at 21:53
  • 2
    To follow along with what @maccettura said, if you break it down into smaller steps and assign intermediary variables, it will become much more readable (which means *you* can see errors with less effort, and debugging is much easier). But, it does mean "more variables" and more typing. Most people thing that "more variables" means more (and slower) code. However, when you do this in release mode, the optimizer will throw those variables away and glue everything back together. You get readability with no loss of speed – Flydog57 Dec 14 '18 at 21:55
  • 2
    You have repeating expressions, like `Math.Asin((Math.Sqrt(2 * h * r)) / (2 * r))`. Definitely break it up to intermediate values and use those instead of repeating the same expression many times. – John Alexiou Dec 14 '18 at 21:56
  • Your problem does not really have anything to do with `r` and `h` being `double` though... – maccettura Dec 14 '18 at 22:03
  • Excel has a `ATAN2()` function also, so try it to see if you get identical results, and if you do, remove the exceptions and just use `Math.Atan2()` in your code. This will make your code more maintainable as you can remove the `if` statement and also make it easier to consider cases when `h=1.99999999999997` which falls on one side of the exception, although it should fall on the other side. – John Alexiou Dec 14 '18 at 22:45

2 Answers2

6

A good approach to debugging these kinds of issues is to break the equation into smaller pieces, so it is easier to debug.

double r = 45;
double h = 0;

double sqrt2hr = Math.Sqrt(2 * h * r);
double asinsqrt2hr = Math.Asin((sqrt2hr) / (2 * r));

double a = (Math.Sqrt(2 * h * r - (h * h)) - r * Math.Sin(asinsqrt2hr));
double b = (h - r + r * (Math.Cos(asinsqrt2hr)));

double sum = 180 / Math.PI * Math.Atan(a / b);

Now if we put a breakpoint at sum and let the code run, we see that both a and b are equal to zero. This gives us a / b = 0 / 0 = NaN in the final line.

Now we can ask, why is this happening? Well in the case of b you have h - r + r which is 0 - 45 + 45, evaluates to 0, so b becomes 0. You probably have an error in your math there.

In the case of a, we have 2 * h * r - h * h, which also evaluates to 0.

You probably either A) have an error in your equation, or B) need to include a special case for when h = 0, as that is breaking your math here.

N.D.C.
  • 1,601
  • 10
  • 13
  • The limit of `sum` as h→0 is 90. Since this is not the value the OP was expecting, I assume that the formula is wrong. – dan04 Dec 14 '18 at 22:03
  • Or use the `Atan2(y,x)` function which exists for _exactly_ such cases. See my answer. – John Alexiou Dec 14 '18 at 22:05
0

Definitely break up the expression something like

var a = Asin(Sqrt(2 * h * r) / (2 * r));
var b = Sqrt(2 * h * r - h * h) - r * Sin(a);
var c = h - r + r * Cos(a);
var sum = 180 / PI * Atan(b / c);

and you will find b=0 and c=0. You might consider changing the last expression into

var sum = 180 / PI * Atan2(b , c);

which will return a value when b=0 and c=0.

PS. Also, use using static System.Math; in the beginning of the code to shorten such math expressions.

John Alexiou
  • 28,472
  • 11
  • 77
  • 133
  • Thanks for the answer. I will use it, thanks for the tip :-) – maddy Dec 14 '18 at 22:09
  • 1
    The `Atan(y/x)` function only returns angles in the range of `-π/2` to `+π/2`, and only when `x<>0`, whereas `Atan2(y,x)` returns the full circle of `-π` to `+π` and even for cases when `x=0`. – John Alexiou Dec 14 '18 at 22:37