8
votes

Calculer le cosinus d'une séquence

Je dois calculer ce qui suit:

float2 y = CONSTANT;
for (int i = 0; i < totalN; i++)
   h[i] = cos(y*i);


3 commentaires

Y * I en radians ou à degrés? Si degrés, vous pouvez utiliser: COS A = -1 * COS (A - 180). Si les radians, utilisez: COS A = -1 * COS (A - PI). Y a-t-il une belle constante qui se prêterait à ne pas calculer que quelques itérations (c'est-à-dire moins que des cosinus différents différents devaient être calculés)?


Y * I est dans les radians; Le problème est que je dois savoir si je peux utiliser les propriétés périodiques des cosinules. Je pense que je devrais devoir vérifier si cet intervalle Y * [1, totalnn] est à l'intérieur de [0, PI] ou s'il est plus grand, et s'il est plus grand, je devrais savoir quels points sont répétés en raison de propriétés périodiques. .


Sauf si y est une fraction de PI (comme PI / 10), la périodicité de COS ne vous aidera probablement pas.


9 Réponses :


0
votes

Vous pouvez le faire en utilisant des nombres complexes.

Si vous définissez x = péché (y) + i cos (y), cos (y * i) sera la partie réelle de x ^ i.

Vous pouvez calculer pour tout ce que j'ai itéoté. Multiplier complexe est 2 multiplie plus deux ajouts.


2 commentaires

Mais l'informatique n exponentielles ne sera pas plus rapide que l'informatique N cosineux. Au moins, il n'y a pas de vraie raison pour laquelle cela devrait.


@AB: J'ai ajouté que vous pouvez les calculer itérativement, multiplier le courant de x. C'est un multiple complexe par entrée requis.



0
votes

Connaissant COS (N) n'aide pas - votre bibliothèque de mathématiques fait déjà ce genre de choses triviales pour vous.

sachant que COS ((i + 1) y) = COS (i y + y) = cos (i y) cos (y) -sin (je Y) SIN (Y) peut aider, si vous précalciez COS (Y) et SIN (Y), et gardez une trace des deux cos (i y) et péché (i * y) en cours de route. Cela peut entraîner une perte de précision, cependant, vous devrez vérifier.


0 commentaires

3
votes

Voici une méthode, mais elle utilise un peu de mémoire pour le péché. Il utilise les identités de triglé: xxx

voici le code: xxx

si je n'ai pas fait d'erreurs, alors cela devrait le faire alors que cela devrait le faire. . Bien sûr, il pourrait y avoir des problèmes arrondis, alors soyez au courant de cela. J'ai mis en place cela dans Python et il est assez précis.


0 commentaires

6
votes

Utilisation de l'une des plus belles formules de mathématiques, Formule d'Euler

exp (i * x) = cos (x) + i * sin (x) code>,

substituant x: = n * phi code>: p>

cos (n * phi) = re (exp (i * n * phi)) code>
sin (n * phi) = im (exp (i * n * phi)) code> p>

exp (i * n * phi) = exp (i * phi) ^ n code> p>

alléaire ^ n code> est n code> multiplications répétées. Par conséquent, vous pouvez calculer cos (n * phi) code> et simultanément sin (n * phi) code> par multiplication complexe répétée par exp (i * phi) code> Commençant par (1 + i * 0) code>. p>

Exemples de code: P>

Python: P>

#include <stdio.h>
#include <math.h>

// numer of values to calculate:
#define N 10

// conversion factor degrees --> radians:
#define DEG2RAD (3.14159265/180.0)

// e.g. constant is 10 degrees:
#define PHI (10*DEG2RAD)

typedef struct
{
  double re,im;
} complex_t;


int main(int argc, char **argv)
{
  complex_t c;
  complex_t h[N];
  int index;

  c.re=cos(PHI);
  c.im=sin(PHI);

  h[0].re=1.0;   
  h[0].im=0.0;
  for(index=1; index<N; index++)
  {
    // complex multiplication h[index] = h[index-1] * c;
    h[index].re=h[index-1].re*c.re - h[index-1].im*c.im; 
    h[index].im=h[index-1].re*c.im + h[index-1].im*c.re; 
    printf("%d: %8.3f\n",index,h[index].re);
  }
} 


2 commentaires

Belle solution mais qu'en est-il des erreurs de points flottantes après un grand nombre d'itérations? Ils sont inévitables ici.


@Kirk Broadhurst: Essayez-la: Utiliser l'exemple Python J'ai constaté que même pour un grand nombre d'itérations (par exemple plusieurs 10 000), la différence pour les valeurs calculées par la fonction COS intégrée reste dans la plage 1E-10.



6
votes

Je ne suis pas sûr de quel type de précision vs performance vous êtes prêt à faire, mais il existe de nombreuses discussions sur diverses techniques d'approximation sinusoïdales sur ces liens:

amusement avec des sinusoïdes - http://www.audiomulch.com/~rossb/ Code / sinusoïdes /
Sine / Cosine rapide et précis - http://www.devaster.net/forums /ShowTthread.php?t=5784

Modifier (je pense que c'est le lien "Don Cross" qui est cassé sur la page "Fun avec des sinusoïdes"):

Optimisation des calculs trigzes - http://groovit.disjunkt.com/analog /time-Domain/fasttrig.html


1 commentaires

La méthode dans la dernière section du dernier lien ici semble être plus rapide que toute autre réponse ici à mon avis.



0
votes

Quelle précision avez-vous besoin du COS résultant? Si vous pouvez vivre avec certains, vous pouvez créer une table de recherche, échantillonnant le cercle de l'unité à des intervalles de 2 * PI / N, puis interpolez-les entre deux points adjacents. N serait choisi d'atteindre un niveau de précision souhaité.

Ce que je ne sais pas, c'est si une interpolation est réellement moins coûteuse que de calculer un cosinus. Depuis que c'est généralement fait dans le microcode dans les processeurs modernes, ce n'est peut-être pas.


2 commentaires

La dernière fois que j'ai vérifié, FCOS (ASM) a pris environ 35 cycles, l'accès à la mémoire incached a pris plusieurs centaines. Temps à la fois et voyez si c'est plus rapide (table mise en cache ou non)


@Arthur: Si vous regardez le code de l'OP, il souhaite calculer le COS, puis mettre à jour un tableau H [i] et le garder peut-être ultérieurement. Donc, le vrai problème est très susceptible d'être une interpolation contre la calcul, comme des mentions Larry et si une interpolation peut être évitée (en choisissant un plus grand nombre de n), cela pourrait bien être ce que la personne recherche. Cette solution présente également l'avantage de ne pas avoir d'erreurs d'accumulation de points flottants.



4
votes

Peut-être que la formule la plus simple est

COS (N + Y) = 2COS (N) COS (Y) - COS (N-Y).

Si vous précalciez la constante 2 * COS (Y), chaque valeur COS (N + Y) peut être calculée à partir des 2 valeurs précédentes avec une seule multiplication et une soustraction. I.e., en pseudocode xxx


4 commentaires

C'est une belle solution très belle, +1


+1 Pour une solution très belle, mais il y a des erreurs de point flottant qui vont rapidement composer après les itérations; surtout si Totaln est grand.


@Kirk Broadhurst: Yup, vous soulevez certainement un point important ici. J'ai fait un petit test avant de poster l'algorithme ci-dessus. Il semble que les erreurs n'accumulent que linéairement. (E.G. Après un million d'itérations, l'erreur est d'environ 10 ^ {- 11} lors de l'utilisation du double). Une meilleure analyse de l'erreur serait nécessaire. Il serait également logique de calculer une paire correcte des cosinés après un nombre donné d'itérations.


Pour une erreur liée, calculez simplement le cosinus à partir de zéro chaque 1000 itérations.



1
votes

Il y a de bonnes réponses ici, mais elles sont toutes récursives. Le calcul récursif ne fonctionnera pas pour la fonction de cosinus lors de l'utilisation de l'arithmétique de point flottant; Vous obtiendrez invariablement des erreurs d'arrondi qui sont complètes rapidement.

Considérons le calcul Y = 45 degrés, totaln 10 000. Vous ne finirez pas avec 1 comme résultat final.


1 commentaires

+1 Vous avez un bon point ici. Cependant, en utilisant y = 45 donne une mauvaise référence. Au moins dans un petit test, que j'ai fait des erreurs d'arrondies s'annulent. C'est-à-dire avec Y = 45, je reçois une erreur de 10 ^ -15 tandis que les valeurs de Y donnent une erreur plus grande d'environ 10 ^ -13.



1
votes

Adresser les préoccupations de Kirk: toutes les solutions basées sur la récurrence de COS et de péché à ébullition à l'informatique

x (k) = r x (k - 1),

où R est la matrice qui tourne à la rotation par Y et X (0) est le vecteur d'unité (1, 0). Si le résultat réel pour K - 1 est X '(K - 1) et le résultat réel pour K est X' (K), l'erreur va de E (K - 1) = x (K - 1) - x ' (K - 1) à E (k) = R x (k-1) - R x '(K - 1) = R E (K - 1) par linéarité. Étant donné que R est ce qu'on appelle une matrice orthogonale , R e (k-1) a la même norme que E (K - 1), et l'erreur se développe très lentement. (La raison pour laquelle il pousse du tout est due à un arrondi; la représentation de l'ordinateur de R est en général presque, mais pas assez orthogonale, il sera donc nécessaire de redémarrer la récurrence en utilisant les opérations de la trigité de temps en temps en fonction de la précision. requis. Ceci est encore beaucoup, beaucoup plus rapide que d'utiliser le trigopes pour calculer chaque valeur.)


0 commentaires