CoolCPLX

Oletko tehnyt jotain, mistä muut voisivat hyötyä. Postita vinkit tänne.
Post Reply
SPuntte
Tech Developer
Tech Developer
Posts: 650
Joined: Mon Aug 27, 2007 9:51 pm
Location: Helsinki, Finland
Contact:

CoolCPLX

Post by SPuntte »

Olipahan vaan ihan pakko taas keksiä uusi Cool-etuliitteellä varustettu nimi, pahoitteluni sitä inhoaville.

Nimen takaa paljastuu niinkin tylsä asia kuin kompleksilukumatematiikkakirjasto, jonka löysin koneeni syövereistä sattumalta. Ajattelin, että siitä voisi olla jollekin hyötyä, joten lähetänpä sen tänne. Tein tällä kokeeksi mm. mandelbrotin fraktaaleja, mikä tosin osoittautui erittäin hitaaksi verrattuna ilman varsinaista kompleksilukutietotyyppiä toteutettuun versioon, joten suurin hyöty kirjastosta lienee kompleksilukulaskennan opettelussa. Lisäksi CB:n 32-bittiset liukuluvut ovat niin epätarkkoja, että pyöristysvirheet näkyvät hyvin yksinkertaisillakin laskutoimituksilla.

Mikä ihmeen kompleksiluku?
Kompleksiluvut on "suurin" (ehkä paremminkin monimutkaisin :P) lukujoukko, jolle on mahdollista määritellä reaalilukujen kanssa analogiset (yhtenevät) laskulait. Kompleksiluvut muistuttavat hieman vektoreita, sillä ne ovat kaksikomponenttisia. Kuitenkin kompleksiluvut toimivat sellaisenaan vain tasossa eli kahdessa ulottuvuudessa (neliulotteisia kompleksilukuja kutsutaan kvaternioiksi ja kahdeksanulotteisia oktonioiksi, mutta reaalilukujen laskulait eivät niille päde) - toisin kuin vektorit, jotka voivat käsittää kuinka monta ulottuvuutta tahansa. Toisekseen vektorien keskinäinen tulo (ristitulo) on antikommutatiivinen, kun kompleksilukujen tulo taas on kommutatiivinen, kuten reaalilukujenkin. Lisäinformaatiota saa mm. Wikipediasta

Kommenteista pitäisi irrota kaikki tarvittava tieto kirjaston käyttämiseksi. En muista, olenko ihan jokaista funktiota edes käyttänyt, joten mahdollisista virheistä saa ilmoitella.

Kirjasto:

Code: Select all

//Kompleksilukukirjasto CoolCPLX by Pontus "SPuntte" Lundström

Const e   = 2.71828182845904523536
Const pi_ = 3.14159265358979323846

//Luo kompleksiluvun ja palauttaa sen kahvan
//a#	Reaaliosa
//b#	Imaginaariosa
Function CPLX_New(a#=0, b#=0)
	Dim c% As Integer
	c = MakeMEMBlock(8)
	PokeFloat c, 0, a
	PokeFloat c, 4, b
	Return c
EndFunction

//Sijoittaa olemassa olevaan kompleksilukuun annetun reaali- ja imaginaariosan
//a#	Reaaliosa
//b#	Imaginaariosa
Function CPLX_Assign(c%, a#, b#)
	PokeFloat c, 0, a
	PokeFloat c, 4, b
EndFunction

//Sijoittaa olemassa olevaan instanssiin annetun reaaliosan
//a#	Reaaliosa
Function CPLX_AssignRe(c%, a#)
	PokeFloat c, 0, a
EndFunction

//Sijoittaa olemassa olevaan instanssiin annetun imaginaariosan
//b#	Imaginaariosa
Function CPLX_AssignIm(c%, b#)
	PokeFloat c, 4, b
EndFunction

//Palauttaa 1, jos annetut kompleksiluvut ovat yhtä suuria
//c1%	ensimmäisen kompleksilukuinstanssin kahva
//c2%	toisen kompleksilukuinstanssin kahva
Function CPLX_Equals(c1%, c2%, threshold#=0.00001)
	If Abs(PeekFloat(c1, 0) - PeekFloat(c2, 0)) <= threshold And Abs(PeekFloat(c1, 4) - PeekFloat(c2, 4)) <= threshold Then
		Return True
	Else
		Return False
	EndIf
EndFunction

//Palauttaa kompleksiluvun reaaliosan
//c%	kompleksilukuinstanssin kahva
Function CPLX_Re(c%)
	Return PeekFloat(c, 0)
EndFunction

//Palauttaa kompleksiluvun 
//c%	kompleksilukuinstanssin kahva
Function CPLX_Im(c%)
	Return PeekFloat(c, 4)
EndFunction

//Laskee kompleksiluvun kompleksikonjugaatin eli liittoluvun ja sijoittaa sen annettuun kompleksilukuinstanssiin tai palauttaa uuden kompleksiluvun kahvan
//c%	kompleksilukuinstanssin kahva
//ret%	kahva kompleksilukuinstanssiin, johon tulos sijoitetaan; arvolla -1 luodaan uusi instanssi ja palautetaan sen kahva
Function CPLX_Conjugate(c%, ret%=-1)
	Dim z% As Integer
	If ret = -1 Then
		z = MakeMEMBlock(8)
		PokeFloat z, 0, PeekFloat(c, 0)
		PokeFloat z, 4, -PeekFloat(c, 4)
		Return z
	Else
		PokeFloat ret, 0, PeekFloat(c, 0)
		PokeFloat ret, 4, -PeekFloat(c, 4)
	EndIf
EndFunction

//Laskee kompleksiluvun negaation (vastaluku) ja sijoittaa sen annettuun kompleksilukuinstanssiin tai palauttaa uuden kompleksiluvun kahvan
//c%	kompleksilukuinstanssin kahva
//ret%	kahva kompleksilukuinstanssiin, johon tulos sijoitetaan; arvolla -1 luodaan uusi instanssi ja palautetaan sen kahva
Function CPLX_Inverse(c%, ret=-1)
	Dim z% As Integer
	Dim a#, b#, sqs# As Float
	a = PeekFloat(c, 0)
	b = PeekFloat(c, 4)
	sqs = a*a + b*b
	If ret = -1 Then
		z = MakeMEMBlock(8)
		PokeFloat z, 0, a/sqs
		PokeFloat z, 4, -b/sqs
		Return z
	Else
		PokeFloat ret, 0, a/sqs
		PokeFloat ret, 4, -b/sqs
	EndIf
EndFunction

//Palauttaa kompleksiluvun modulin eli itseisarvon
//c%	kompleksilukuinstanssin kahva
Function CPLX_Modulus(c%)
	Return Distance(0, 0, PeekFloat(c, 0), PeekFloat(c, 4))
EndFunction

//Palauttaa kompleksiluvun argumentin eli vaihekulman
//c%	kompleksilukuinstanssin kahva
//rad	arvolla TOSI kulmayksikkönä on radiaani, muuten aste
Function CPLX_Argument(c%, rad=1)
	Dim a# As Float
	a = GetAngle(0, 0, PeekFloat(c, 0), -PeekFloat(c, 4))
	a = a - (a > 180.0)*360.0
	If rad Then Return a*pi_/180
	Return a
EndFunction

//Laskee kahden kompleksiluvun summan ja sijoittaa sen annettuun kompleksilukuinstanssiin tai palauttaa uuden kompleksiluvun kahvan
//c1%	ensimmäisen kompleksilukuinstanssin kahva
//c2%	toisen kompleksilukuinstanssin kahva
//ret%	kahva kompleksilukuinstanssiin, johon tulos sijoitetaan; arvolla -1 luodaan uusi instanssi ja palautetaan sen kahva
Function CPLX_Add(c1%, c2%, ret=-1)
	Dim z% As Integer
	Dim a1#, a2#, b1#, b2# As Float
	a1 = PeekFloat(c1, 0)
	b1 = PeekFloat(c1, 4)
	a2 = PeekFloat(c2, 0)
	b2 = PeekFloat(c2, 4)
	If ret = -1 Then
		z = MakeMEMBlock(8)
		PokeFloat z, 0, a1 + a2
		PokeFloat z, 4, b1 + b2
		Return z
	Else
		PokeFloat ret, 0, a1 + a2
		PokeFloat ret, 4, b1 + b2
	EndIf
EndFunction

//Laskee kahden kompleksiluvun erotuksen ja sijoittaa sen annettuun kompleksilukuinstanssiin tai palauttaa uuden kompleksiluvun kahvan
//c1%	ensimmäisen kompleksilukuinstanssin kahva
//c2%	toisen kompleksilukuinstanssin kahva
//ret%	kahva kompleksilukuinstanssiin, johon tulos sijoitetaan; arvolla -1 luodaan uusi instanssi ja palautetaan sen kahva
Function CPLX_Subtract(c1%, c2%, ret=-1)
	Dim z% As Integer
	Dim a1#, a2#, b1#, b2# As Float
	a1 = PeekFloat(c1, 0)
	b1 = PeekFloat(c1, 4)
	a2 = PeekFloat(c2, 0)
	b2 = PeekFloat(c2, 4)
	If ret = -1 Then
		z = MakeMEMBlock(8)
		PokeFloat z, 0, a1 - a2
		PokeFloat z, 4, b1 - b2
		Return z
	Else
		PokeFloat ret, 0, a1 - a2
		PokeFloat ret, 4, b1 - b2
	EndIf
EndFunction

//Kertoo kompleksiluvun reaaliluvulla eli "skaalaa" sen
//r#	reaaliluku
//c%	kompleksilukuinstanssin kahva
Function CPLX_RealMultiply(r#, c%)
	PokeFloat c, 0, r*PeekFloat(c, 0)
	PokeFloat c, 4, r*PeekFloat(c, 4)
EndFunction

//Laskee kahden kompleksiluvun tulon ja sijoittaa sen annettuun kompleksilukuinstanssiin tai palauttaa uuden kompleksiluvun kahvan
//c1%	ensimmäisen kompleksilukuinstanssin kahva
//c2%	toisen kompleksilukuinstanssin kahva
//ret%	kahva kompleksilukuinstanssiin, johon tulos sijoitetaan; arvolla -1 luodaan uusi instanssi ja palautetaan sen kahva
Function CPLX_Multiply(c1%, c2%, ret%=-1)
	Dim z% As Integer
	Dim a1#, a2#, b1#, b2# As Float
	a1 = PeekFloat(c1, 0)
	b1 = PeekFloat(c1, 4)
	a2 = PeekFloat(c2, 0)
	b2 = PeekFloat(c2, 4)
	If ret = -1 Then
		z = MakeMEMBlock(8)
		PokeFloat z, 0, (a1*a2-b1*b2)
		PokeFloat z, 4, (a1*b2+a2*b1)
		Return z
	Else
		PokeFloat ret, 0, (a1*a2-b1*b2)
		PokeFloat ret, 4, (a1*b2+a2*b1)
	EndIf
EndFunction

//Laskee kahden kompleksiluvun osamäärän ja sijoittaa sen annettuun kompleksilukuinstanssiin tai palauttaa uuden kompleksiluvun kahvan
//c1%	ensimmäisen kompleksilukuinstanssin kahva
//c2%	toisen kompleksilukuinstanssin kahva
//ret%	kahva kompleksilukuinstanssiin, johon tulos sijoitetaan; arvolla -1 luodaan uusi instanssi ja palautetaan sen kahva
Function CPLX_Divide(c1%, c2%, ret%=-1)
	Dim z% As Integer
	Dim a1#, a2#, b1#, b2#, sqs# As Float
	a1 = PeekFloat(c1, 0)
	b1 = PeekFloat(c1, 4)
	a2 = PeekFloat(c2, 0)
	b2 = PeekFloat(c2, 4)
	sqs# = a2*a2 + b2*b2
	If ret = -1 Then
		z = MakeMEMBlock(8)
		PokeFloat z, 0, (a1*a2+b1*b2)/sqs
		PokeFloat z, 4, (b1*a2-a1*b2)/sqs
		Return z
	Else
		PokeFloat ret, 0, (a1*a2+b1*b2)/sqs
		PokeFloat ret, 4, (b1*a2-a1*b2)/sqs
	EndIf
EndFunction

//Laskee arvon potenssilausekkeelle, jossa kantaluku on reaalinen ja eksponentti kompleksinen ja sijoittaa sen annettuun kompleksilukuinstanssiin tai palauttaa uuden kompleksiluvun kahvan
//base#	kantaluku
//exp%	eksponentin kahva
//ret%	kahva kompleksilukuinstanssiin, johon tulos sijoitetaan; arvolla -1 luodaan uusi instanssi ja palautetaan sen kahva
Function CPLX_PowRC(base#, exp%, ret%=-1)
	Dim z% As Integer
	z = MakeMEMBlock(8)
	MemCopy exp, 0, z, 0, 8
	CPLX_RealMultiply(Log(base#), z)
	If ret = -1 Then
		CPLX_Exp(z, z)
		Return z
	Else
		CPLX_Exp(z, ret)
		DeleteMEMBlock z
	EndIf
EndFunction

//Laskee arvon potenssilausekkeelle, jossa kantaluku on kompleksinen ja eksponentti reaalinen ja sijoittaa sen annettuun kompleksilukuinstanssiin tai palauttaa uuden kompleksiluvun kahvan
//base%	kantaluvun kahva
//exp#	eksponentti
//ret%	kahva kompleksilukuinstanssiin, johon tulos sijoitetaan; arvolla -1 luodaan uusi instanssi ja palautetaan sen kahva
Function CPLX_PowCR(base%, exp#, ret%=-1)
	Dim z, i As Integer
	If RoundUp(exp) = RoundDown(exp) Then
		z = CPLX_New(1, 0)
		If ret = -1 Then
			For i = 1 To exp
				CPLX_Multiply(z, base, z)
			Next i
			Return z
		Else
			For i = 1 To exp - 1
				CPLX_Multiply(z, base, z)
			Next i
			CPLX_Multiply(z, base, ret)
			DeleteMEMBlock z
		EndIf
	Else
		z = CPLX_Log(base)
		CPLX_RealMultiply(exp, z)
		If ret = -1 Then
			CPLX_Exp(z, z)
			Return z
		Else
			CPLX_Exp(z, ret)
			DeleteMEMBlock z
		EndIf
	EndIf
EndFunction

//Laskee arvon potenssilausekkeelle, jossa sekä kantaluku että eksponentti ovat kompleksilukuja ja sijoittaa sen annettuun kompleksilukuinstanssiin tai palauttaa uuden kompleksiluvun kahvan
//base%	kantaluvun kahva
//exp%	eksponentin kahva
//ret%	kahva kompleksilukuinstanssiin, johon tulos sijoitetaan; arvolla -1 luodaan uusi instanssi ja palautetaan sen kahva
Function CPLX_PowCC(base%, exp%, ret%=-1)
	Dim z As Integer
	z = CPLX_Log(base)
	CPLX_Multiply(exp, z, z)
	If ret = -1 Then
		CPLX_Exp(z, z)
		Return z
	Else
		CPLX_Exp(z, ret)
		DeleteMEMBlock z
	EndIf
EndFunction

//Korottaa Neeperin luvun (e) annetun kompleksiluvun osoittamaan potenssiin ja sijoittaa tuloksen annettuun kompleksilukuinstanssiin tai palauttaa uuden kompleksiluvun kahvan
//c%	kompleksilukuinstanssin kahva
//ret%	kahva kompleksilukuinstanssiin, johon tulos sijoitetaan; arvolla -1 luodaan uusi instanssi ja palautetaan sen kahva
Function CPLX_Exp(c%, ret%=-1)
	Dim z% As Integer
	Dim x#, y#, etox# As Float
	x = PeekFloat(c, 0)
	y = (PeekFloat(c, 4) * 180.0) / pi_
	etox = e^x
	If ret = -1 Then
		z = MakeMEMBlock(8)
		PokeFloat z, 0, Cos(y)*etox
		PokeFloat z, 4, Sin(y)*etox
		Return z
	Else
		PokeFloat ret, 0, etox*Cos(y)
		PokeFloat ret, 4, etox*Sin(y)
	EndIf
EndFunction

//Laskee kompleksisen logaritmin annetulle kompleksiluvulle ja sijoittaa tuloksen annettuun kompleksilukuinstanssiin tai palauttaa uuden kompleksiluvun kahvan
//c%	kompleksilukuinstanssin kahva
//ret%	kahva kompleksilukuinstanssiin, johon tulos sijoitetaan; arvolla -1 luodaan uusi instanssi ja palautetaan sen kahva
Function CPLX_Log(c%, ret%=-1)
	Dim z% As Integer
	Dim x#, y#, arg# As Float
	x = PeekFloat(c, 0)
	y = PeekFloat(c, 4)
	arg = CPLX_Argument(c)
	If ret = -1 Then
		z = MakeMEMBlock(8)
		PokeFloat z, 0, 0.5 * Log(x*x + y*y)
		PokeFloat z, 4, arg
		Return z
	Else
		PokeFloat ret, 0, 0.5 * Log(x*x + y*y)
		PokeFloat ret, 4, arg
	EndIf
EndFunction
Yksinkertainen esimerkki:

Code: Select all

//Calculate: i^i
z = CPLX_New(0, 1)
CPLX_PowCC(z, z, z)

//Prove that e^(i * pi) + 1 = 0
w = CPLX_New(0, 1)
realOne = CPLX_New(1, 0) //number 1 LOL
CPLX_RealMultiply(pi_, w)
CPLX_Exp(w, w)
CPLX_Add(w, realOne, w)
DeleteMEMBlock realOne

Repeat
	Text 5, 5, "i^i = " + CPLX_Re(z) + " + " + CPLX_Im(z) + " i"
	Text 5, 20, "e^(i * pi) + 1 = " + CPLX_Re(w) + " + " + CPLX_Im(w) + " i"
	DrawScreen
Forever
CoolBasic henkilökuntaa
Tech-kehittäjä
CoolBasic Classic, Cool VES

CoolPhysicsEngine | MissileSystem | Jana-ympyrä -törmäys | cbSimpleTexture | CoolCPLX
User avatar
esa94
Guru
Posts: 1855
Joined: Tue Sep 04, 2007 5:35 pm

Re: CoolCPLX

Post by esa94 »

SPuntte wrote:Kompleksiluvut on "suurin" (ehkä paremminkin monimutkaisin :P) lukujoukko, jolle on mahdollista määritellä reaalilukujen kanssa analogiset (yhtenevät) laskulait.
No teknisesti ottaenhan kompleksilukuja on ∞², mutta onko sillä väliä, kun äärettömästi on kuitenkin aina äärettömästi :D
Post Reply