简体   繁体   中英

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 ?

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;
}

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.

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 ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM