user3003465
user3003465

Reputation: 23

Compute cosine and sine with Linq

I maded some code to compute the sine and cosine, but, the code is not so good, I want to know if is possible to make the code to compute the values with Linq.

that is my code to compute sine

        var primes = PrimeNumbers(3, 15);

        bool SumSub = false;
        decimal seno = (decimal)(nGrau * nSeno);
        foreach (var a in primes)
        {
            if (SumSub == false)
            {
                seno -= (decimal)Math.Pow(nGrau, (double)a) / Factorial(a);
                SumSub = true;
            }
            else
            {
                seno += (decimal)Math.Pow(nGrau, (double)a) / Factorial(a);
                SumSub = false;
            }
        }
        Console.WriteLine(seno);

Is possible to make a code to compute the sine of degres using linq ?

Upvotes: 2

Views: 294

Answers (3)

Gabe
Gabe

Reputation: 86718

Here's a function that computes the adds up the first 10 terms of the Taylor series approximation of cosine:

var theta = 1.0m;   // angle in radians
Enumerable.Range(1, 10).Aggregate(
    new { term = 1.0m, accum = 0.0m },
    (state, n) => new {
             term  = -state.term * theta * theta / (2 * n - 1) / (2 * n),
             accum = state.accum + state.term},
    state => state.accum)

See how it doesn't use an if, Power, or Factorial? The alternating signs are created simply by multiplying the last term by -1. Computing the ever-larger exponents and factorials on each term is not only expensive and results in loss of precision, it is also unnecessary.

To get x^2, x^4, x^6,... all you have to do is multiply each successive term by x^2. To get 1/1!, 1/3!, 1/5!,... all you have to do is divide each successive term by the next two numbers in the series. Start with 1; to get 1/3!, divide by 2 and then 3; to get 1/5! divide by 4 and then 5, and so on.

Note that I used the m prefix to denote decimal values because I'm assuming that you're trying to do your calculations in decimal for some reason (otherwise you would use Math.Cos).

Upvotes: 1

Baldrick
Baldrick

Reputation: 11840

Something like this, perhaps:

var sineResult = listDouble.Select((item, index) => 
                                    new {i = (index%2)*2 - 1, o = item})
                           .Aggregate(seno, (result, b) => 
                                      result - b.i * ((decimal)Math.Pow(nGrau, (double)b.o) / Factorial(b.o)));

The code

i = (index%2)*2 - 1

gives you alternating 1 and -1.

The Aggregate statement sums the values, mulitplying each value by either -1 or 1.

Upvotes: 1

MarcinJuraszek
MarcinJuraszek

Reputation: 125620

You could use Aggregate:

decimal seno = PrimeNumbers(3, 15)
    .Aggregate(
        new { sub = false, sum = (decimal)(nGrau * nSeno) },
        (x, p) => new {
            sub = !x.sub,
            sum = x.sum + (x.sub ? 1 : -1) * (decimal)Math.Pow(nGrau, (double)p) / Factorial(p)
        },
        x => x.sum);

I didn't test that, but think it should work.

Btw. I don't think it's more readable or better then your solution. If I were you I would go with foreach loop, but improve it a little bit:

foreach (var a in primes)
{
    seno += (SumSub ? 1 : -1) * (decimal)Math.Pow(nGrau, (double)a) / Factorial(a);
    SumSub = !SumSub;
}

Upvotes: 1

Related Questions