Trigo en asm 68k
15 sujets de 1 à 15 (sur un total de 16)
- 1
- 2
-
Bonjour,
Une petite question aux connaisseurs…
Comment faire pour calculer un sinus ou un cosinus en asm ?
Je sais qu’il existe des outils pour générer des tables précalculées, mais j’aimerais précalculer ma table moi même au lancement de mon programme…(Je suis sur un Amiga 1200 émulé avec WinUAE)
Tu travailles en flottant ou en point fixe ? Tu veux la valeur plutôt exacte de sin/cos ou une approximation suffira ?
Samuel.
Amiga A500 + GVP530 (8Mo/fpu/mmu/scsi) - en panne 🙁
A500 (+ 1Mo PPS), A1200 (Blizzard-IV/fpu/64Mo)
A500 Vampire V2+ ^8^ 🙂
(mais aussi TO8, TO8D, TO9. Groupe PULS.)Salut Sam,
On va dire que j’aimerais générer une table de 1024 valeurs de sinus dont les valeurs vont de 0 à 65535 (une table de word donc)
Flottant ou point fixe, peu importe….une approximation devrait suffire pour un sine scroller…
Je viens de tomber là dessus justement : https://amycoders.org/sources/sinegensource.html
Donc du point fixe 16.16.
Une approximation de sin(x) entre -pi et pi est y=4*(x/pi)*(1-abs(x/pi)). Elle est précise à 6% près.
Ta table fait 1024 entrées pour 0..2PI, donc pi (en x) vaut: 512, et 1 en y est 65536.
Donc la formule à mettre dans la table est: 65536*4*(x/512)*(1-abs(x)/512) ce qui se simplifie en: tab[x] = x*(512-abs(x)).
Vérification: sin(0) -> tab[0]=0, sin(pi/2) -> tab[256] = 256*256 = 65536 -> 1, sin(pi) -> tab[512] = 0. sin(3pi/2) = sin(3pi/2-2pi) = sin(-pi/2) –> -256*(512-abs(-256)) = -256*256 = -65536 -> -1. Ca colle!
L’abs va nous ennuyer, mais on peut au départ calculer tab[x] avec x>0 (ce qui nous permet d’utiliser une multiplication non signée), puis pour les x<0, il suffit se savoir que sin(-x) = -sin(x) cad tab[x] = -tab[-x].
Allons y pour l’asm (sans bouées):
[code]
calc sin_tab:
lea sin_tab,a0
; calcul de tab[0..511] correspondant aux valeurs de x>0
moveq #0,d0
.1
move.w #512,d1
sub.w d0,d1
beq.b .2 ; donc quand on sort, d0 vaut 512. Idéal pour décompter.
mulu.w d0,d1
addq.w #1,d0
move.l d1,(a0)+
bra.b .1
; calcul de tab[512..1023] correspondante aux valeurs de x<0
; on ne fait que recopier la table de la partie 1 en inversant
; le signe.
.2
move.l -512*4(a0),d1
neg.l d1
move.l d1,(a0)+
subq.w #1,d0
bne.b .2
; fini
rts
; tableau de 4ko
sin_tab:
ds.l 1024
[/code]
Ca devrait être +/- correct, mais j’ai pas testé. En tout cas le principe est là.(Désolé pour la mise en page, mais le forum ne respecte pas les blancs dans le code 🙁 Une version correctement formatée est visible >>là<<.)
Samuel.
Amiga A500 + GVP530 (8Mo/fpu/mmu/scsi) - en panne 🙁
A500 (+ 1Mo PPS), A1200 (Blizzard-IV/fpu/64Mo)
A500 Vampire V2+ ^8^ 🙂
(mais aussi TO8, TO8D, TO9. Groupe PULS.)Wow impressionnant 🙂
Bon je vais devoir digérer tout ca alors…
Merci beaucoup
Pour info j’ai touvé ca aussi, c’est intéressant : https://amycoders.org/tutorials/sintables.html
je remplace pi par 512 parce que ta table a 1024 entrées et que 1024 représente la fin de la sinusoide, cad 2pi.
Donc si 2pi=1024, il vient pi=512. L’entrée 512 de la table correspond à sin(pi), celle en 256 correspond à sin(pi/2). Ben oui pi/2 c’est 256 quand pi=512. Tu vois le truc? On mappe un x réel entre 0 et 2pi vers un x’ entier entre 0 et 1024.
Samuel.
Amiga A500 + GVP530 (8Mo/fpu/mmu/scsi) - en panne 🙁
A500 (+ 1Mo PPS), A1200 (Blizzard-IV/fpu/64Mo)
A500 Vampire V2+ ^8^ 🙂
(mais aussi TO8, TO8D, TO9. Groupe PULS.)Bah, c’est pas des maths, juste du calcul… un chouille laborieux là parce que j’ai essayé de détailler toutes les étapes élémentaires
65536*4*(x/512) * (1-abs(x)/512)
= (65536*4)*(x/512) * (1-abs(x)/512)
= 262144*(x/512) * (1-abs(x)/512)
= (262144*x/512) * (1-abs(x)/512)
= ((262144/512)*x) * (1-abs(x)/512)
= (512*x) * (1-abs(x)/512)
= (512*x) * (1-abs(x)/512)*1
= (512*x) * (1-abs(x)/512)*(512/512)
= (512*x) * (((1-abs(x)/512)*512)/512)
= (512*x) * ((512 – abs(x))/512
= 512*x * (512 – abs(x))/512
= x * (512 – abs(x)) * 512/512
= x * (512 – abs(x)) * 1
= x * (512 – abs(x))
CQFD 😉Samuel.
Amiga A500 + GVP530 (8Mo/fpu/mmu/scsi) - en panne 🙁
A500 (+ 1Mo PPS), A1200 (Blizzard-IV/fpu/64Mo)
A500 Vampire V2+ ^8^ 🙂
(mais aussi TO8, TO8D, TO9. Groupe PULS.)Efficace et bien expliqué, même si je sens déjà poindre une légère migraine ;-), ça sent les automatismes et l’amour du travail bien fait.
PowerMac - G5 2.0 GHz - 1.7 Go RAM - Radeon 9600P 128 Mo - MorphOs 3.13 et Peg2 - G4 RIP
Mac mini - G4 1.42 GHz - 1 Go RAM - Radeon 9200 32 Mo - MorphOs 3.9
WinUAE sur HP Core2 Quad 8200
Epave de Mist FPGA remplacé par un Sidi
A1200 malade 😉 et A500 512+512Ko RAM Kickstart 1.3Pour ceux qui veulent s’amuser avec l’approximation de sin(x) entre -pi et pi par 4x(1-|x|/pi)/pi, j’ai posé la question à wolfram alpha. Il dit que le max d’erreur est obtenu pour x = +/-0.471972 ou x = +/-2.66962 et vaut 0.0560096. [REVISION BAC-S by sam 😛 ]
On est donc juste un peu « au dessus » du sinus au max de 5.6% (par rapport à 1). Mais c’est tout à fait acceptable en pratique car le calcul est rapide. Voyez comment les courbes sont proches.
(clickez l’image pour voir sur Wolfram Alpha)Samuel.
Amiga A500 + GVP530 (8Mo/fpu/mmu/scsi) - en panne 🙁
A500 (+ 1Mo PPS), A1200 (Blizzard-IV/fpu/64Mo)
A500 Vampire V2+ ^8^ 🙂
(mais aussi TO8, TO8D, TO9. Groupe PULS.)Salut,
Je remonte ce thread, déjà pour dire que ton algo fonctionne très bien (compile du premier coup avec AsmOne), c’est très rapide (quasi instantané), mais aussi pour poser une question.
Je suis tombé sur une routine de Photon de Scoopex pour faire la même chose.;Bhaskara sine approx by Photon/SCX ;note that this is better than std parabolic so no 2% deviation \o/ ;sin x=4x(180-x)/(40500-x(180-x)) ;changed from 180 to 126 steps for 180 degs steps2 =126 ;orig 180 ampl =-1 ;orig 40500 => $1bd0 ampl, -1 => $1080 ampl, 11909=$7ff7 ampl B: lea Sin(PC),a1 moveq #steps2-1,d0 .l: bsr.s BSine move.w d1,(a1)+ neg.w d1 move.w d1,steps2*2-2(a1) DBF d0,.l RTS BSine: ;d0.w=x (0..steps2=0..179 degs) moveq #steps2,d1 sub.w d0,d1 mulu d0,d1 ;x(180-x) moveq #-1,d2 ;fine-stretch amplitude with this. sub.w d1,d2 swap d1 ;*4*16384ampl/2, lsl.l #8,d1 => 4*64ampl ; clr.w d1 ;@only nec at high amplitudes AND high coord/scr rez. divu d2,d1 ;check if rest works as autorandomvalues. ;) RTS Sin: blk.w steps2*2,0 E:
Visiblement la formule de base est différente, méthode Bhaskara : sin x=4x(180-x)/(40500-x(180-x))
Je n’arrive pas à comprendre pourquoi ces deux lignes :
– Pourquoi il met -1 dans d2 ? il est pas sensé mettre 40500 ??
moveq #-1,d2 ;fine-stretch amplitude with this.– Pourquoi ce swap ? De plus je ne comprend le commentaire…
swap d1 ;*4*16384ampl/2, lsl.l #8,d1 => 4*64amplLe registre d1 est utilisé pour faire une division, pourquoi est t-il d’abord swappé ? J’aurai compris qu’il fasse un lsr à la place du swap, mais là avec le swap, il va y avoir des trucs dans la partie haute de d1 ce qui risque de faire du caca avec le divu….pourtant ca fonctionne
Bon,
Pour le swap, je vient de comprendre…
Il fait un swap pour ne pas avoir à faire deux lsl de suite :
lsl.l #8,d1
lsl.l #8,d1après le swap, la partie basse de d1 n’est pas significative pour le divu (d’où le clr.w en commentaire)
Par contre je ne pige toujours pas pourquoi il met -1 dans d2 à la place du 40500
15 sujets de 1 à 15 (sur un total de 16)
- 1
- 2
- Vous devez être connecté pour répondre à ce sujet.
› Forums › AmigaOS, MorphOS et AROS › Développement › Trigo en asm 68k