Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Math.Sin, Math.Cos and Math.Tan precision and way to display them correctly

I'm coding a calculator in C#.

textBoxResult is a text box where I display the number

recount is the function which takes the angle in degrees and returns in radians

I take the angle from texBoxInput

public double recount(int number)
{
    double wyjscie = 0.0;
    double Number = number;
    wyjscie = Number * (Math.PI / 180);
    return wyjscie;
}

//function which is called out when user presses the button:
textBoxResult.Text = Math.Round(Math.Tan(recount(Convert.ToInt32(texBoxInput.Text))),2).ToString();

As you can see I was trying to round this number when using Math.Tan, but still Math.Tan gives me that tan from 90 degrees is 1,63317787283838E+16 .

I have been trying to find the answer but failed. I can't figure it out how to display correct result.

like image 643
Marcin Majewski Avatar asked Sep 07 '25 04:09

Marcin Majewski


2 Answers

Basically, it looks like this is expected behavior from Math.Tan. I don't know other languages very well, so I'm not sure if this is normal for floating point Math or specific to the C# implementation. (NOTE: Afterwards, I found that Google's online calculator returns the same suggesting it expected behavior for floating point trig functions, probably related to the fact that pi is irrational and the limitations of the double precision data type)

However, working backwards from this result I am seeing that Math.Atan(// your result); and Math.Atan(double.PositiveInfinity) both return 90 degrees, suggesting this is expected?

Here's my test:

var deg = 90.0;
var rads = deg * (Math.PI / 180);
var result = Math.Tan(rads);

if (Double.IsInfinity(result))
    Console.WriteLine("Tan of 90 degrees is Infinity");
else if (Double.IsNaN(result))
    Console.WriteLine("Tan of 90 degrees is Undefined");
else
    Console.WriteLine("Tan of 90 degrees is {0}", result);

Console.WriteLine("Arc Tan of {0} is {1} degrees", double.PositiveInfinity, Math.Atan(double.PositiveInfinity) * 180 / Math.PI);
Console.WriteLine("Arc Tan of {0} is {1} degrees", result, Math.Atan(result) * 180 / Math.PI);

Which gives the output of:

Tan of 90 degrees is 1.63317787283838E+16
Arc Tan of Infinity is 90 degrees
Arc Tan of 1.63317787283838E+16 is 90 degrees

So my guess is unless someone can come in and provide a workaround, you might have to program around this as an edge case to get the correct result.

The "correct result" for any of the trig functions will be limited to the precision of double, which is 15 significant figures, so if you need more than that, you will need to find a library that supports more precise mathematics.

Since Math.Tan(Math.PI/2) seems to provide an undesirable response you could do something like this:

public double ComputeTangent(double angleRads)
{
    if (angleRads == Math.PI/2)
        return double.PositiveInfinity
    if (angleRads == - Math.PI/2)
        return double.NegativeInfinity

    return Math.Tan(angleRads);
}
like image 182
psubsee2003 Avatar answered Sep 10 '25 07:09

psubsee2003


Round is doing exactly what it says on the tin:

The maximum total number of integral and fractional digits that can be returned is 15. If the rounded value contains more than 15 digits, the 15 most significant digits are returned. If the rounded value contains 15 or fewer digits, the integral digits and as many fractional digits as the digits parameter specifies are returned.

1.63317787283838E+16 are the 15 most significant digits, and there is no fractional part.

If you want to display this as 1,63E+016 you can use:

number.ToString('E2', CultureInfo.CreateSpecificCulture("fr-FR"))

(Or any other locale that uses , as the decimal separator )

See: The Exponential ("E") Format Specifier

like image 42
verdesmarald Avatar answered Sep 10 '25 07:09

verdesmarald