Kirjautuminen

Haku

Tehtävät

Keskustelu: Koodit: C++: Moniulotteinen algebra

jone2712 [02.02.2020 14:28:03]

#

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

typedef long double lreal;
#define lr(xx) (lreal)(xx)

/******************************************************************************
* Moniulotteinen algebra                                                      *
*                                                                             *
* Algebran mahdollisuuksiin liittyy myös sellainen työkalu, jolla             *
* rinnakkaisia syy-seurauksia voi pukea ja approksimoida kompakteiksi         *
* funktioiksi. Kun näytölle piirtää hiirellä suunnilleen juohevan käyrän,     *
* algebra onnistuu approksimoimaan annetun pistejoukon lyhyeksi funktioksi.   *
* Algebran taito on sen kyvyssä kuvata ilmiöitä ja luontoa.                   *
*                                                                             *
* Entä, kun näytölle piirtää erivärisiä käyriä. Valkoinen pistejoukko on      *
* lämpötila, keltainen tuulen suunta, oranssi vuodenaika, sininen edustaisi   *
* ilmankosteutta, jne. Jokainen pistejoukko voidaan kuvata yksittäisenä       *
* ilmiönä, mutta entä se funktio, joka kuvaisi yksistään koko joukon välisiä  *
* syy-seuraus suhteita?                                                       *
*                                                                             *
* Funktion relaatio voi olla myös epäsymmetrinen. Sääfunktion inputtina voi   *
* olla n-kappaletta herätteitä, ja outputtina vain yksi suhteellisen sumea    *
* parametri välillä 0-1, kannattaako lähteä kalaan, vai ei.                   *
*                                                                             *
*                                  ***                                        *
*                                                                             *
* Tietokoneen voi ohjelmoida tutkimaan matematiikkaa. Pitävillä algebran      *
* aksioomilla ja ristiriidattomilla sarjakehitelmillä bittihirmu syventyy     *
* edelleen geometriaan ja symmetriaan. Lopullisessa ratkaisussa tietokone oli *
* osittain joutunut luopumaan symbolisista käsitteistä, mitä on positiivinen, *
* negatiivinen, reaalinen ja imaginaarinen. Algebran ei tarvitse ottaa        *
* kantaa, miten päin monitori on pöydälle laitettu.                           *
*                                                                             *
* Algebran algoritmit ovat vakioita, ja sen oliot voivat kuvata mitä tahansa. *
* Yksi kauneimpia algebran kaavoja on pienimmän neliösumman polynomisovitus.  *
* Jos kaavaan sijoitettava olio on validi ja itsensä kanssa tasapainossa,     *
* algebra käsittelee substanssia järkevin tuloksin, muutoin ei. Hyvä          *
* esimerkki on kvaternio. Algebra ei ota kantaa kvaternion sisäiseen          *
* laskulogiikkaan.                                                            *
*                                                                             *
*                                  ***                                        *
*                                                                             *
* i^2 on -1, mutta mikä on se olio, joka korotettuna toiseen antaa tulokseksi '
* -i? i:n seuralaisilla on mielenkiintoinen yhteys, |e^(xi+yj+zk+...)| = 1.   *
* Moniulotteinen algebra yhdistää myös piin ja luvun yksi. pii^z raja-arvo    *
* reaaliakselilla lähestyy arvoa 1, kun z-yksikkövektori viritetään yhä       *
* kauemmas ja kauemmas reaaliakselista. Samalla akseleiden itseisarvojen      *
* summa lähestyy piitä.                                                       *
*                                                                             *
* Seuraavassa recomplex -luvun yksinkertaiset laskusäännöt C++ esimerkein.    *
* Itse luokka istuu myös melkein sellaisenaan MatLab -työkaluun.              *
*                                                                             *
* ~ recomplex                                                                 *
* ~ kertaluku                                                                 *
* ~ luokkamäärittely                                                          *
* ~ yhteenlasku                                                               *
* ~ vähennyslasku                                                             *
* ~ kertolasku                                                                *
* ~ kantavektoreiden tulot                                                    *
* ~ jakolasku                                                                 *
* ~ abs(recomplex)                                                            *
* ~ sqrt(recomplex)                                                           *
* ~ ln(recomplex)                                                             *
* ~ exp(recomplex)                                                            *
* ~ pow(recomplex, int)                                                       *
* ~ pow(recomplex, double)                                                    *
* ~ pow(recomplex, recomplex)                                                 *
* ~ sin(recomplex)                                                            *
* ~ cos(recomplex)                                                            *
*                                                                             *
* ~~~ recomplex ~~~                                                           *
*                                                                             *
* Kompleksiluku on recomplex -luvun aito osajoukko. Reaaliluvut ja            *
* imaginaariluvut ovat puolestaan kompleksiluvun aitoja osajoukkoja.          *
* Etuliite "re" viittaa takaisinkytkentään, saman peruslogiikan               *
* uudelleen toistamiseen seuraavassa mittakaavassa.                           *
*                                                                             *
* ~~~ kertaluku ~~~                                                           *
*                                                                             *
* Kertaluku käy kahden potenssissa, 1, 2, 4, ..., 2^n. Reaaliluvut virittyvät *
* kertaluvulla 1. Kompleksiluvut käyvät voimaan kertaluvulla 2. Kertaluvussa  *
* 4 kompleksiluvut saavat rinnalleen vastinlogiikalla toimivan olion. Niiden  *
* yhdiste mahdollistaa muun muassa yksinkertaiset funktiokuvaukset            *
* rinnakkaisille syy-seuraus -ilmiöille.                                      *
*                                                                             *
* ~~~ luokkamäärittely ~~~                                                    *
*                                                                             *
* C++ toteutti operaattoreiden kuormituksen, jolloin varsinkaan numeeristen   *
* struktuureiden laskuoperaatiot tietokoneella eivät poikkea tavanomaisesta   *
* suoraviivaisuudesta.                                                        *
******************************************************************************/

class recomplex
{
   public:

   /***********************************
   * DIMENSION voi olla 2^n.          *
   * DIMENSION 1 -> reaaliluvut       *
   * DIMENSION 2 -> kompleksiluvut    *
   * DIMENSION 4 -> 4D-kompleksiluvut *
   * DIMENSION 8 -> 8D-kompleksiluvut *
   ***********************************/
   #define DIMENSION 4
   lreal e[DIMENSION];

   recomplex(void);
   ~recomplex(void);
   recomplex(double);
   recomplex(double*);

   recomplex(int);
   recomplex(int, int);
   recomplex(double, double);
   recomplex(int, int, int, int);
   recomplex(double, double, double, double);

   friend void print(recomplex);
   friend double abs(recomplex);
   friend recomplex sqrt(recomplex);

   friend recomplex operator-(recomplex);
   friend recomplex operator+(recomplex);
   friend recomplex operator+(recomplex, recomplex);
   friend recomplex operator-(recomplex, recomplex);

   friend recomplex operator*(recomplex, recomplex);
   friend recomplex operator/(recomplex, recomplex);

   friend recomplex operator*(recomplex, double);
   friend recomplex operator/(recomplex, double);

   friend recomplex operator*(double, recomplex);
   friend recomplex operator/(double, recomplex);

   friend recomplex ln(recomplex);
   friend recomplex exp(recomplex);

   friend recomplex pow(recomplex, int);
   friend recomplex pow(recomplex, double);
   friend recomplex pow(recomplex, recomplex);

   friend recomplex sin(recomplex);
   friend recomplex cos(recomplex);
};

/********************************
* alustaa muistilohkon nollaksi *
********************************/
void mem00set(void *os, int size)
{
   char *a=(char*)os;
   for (int i=0; i<size; i++)
   a[i]=0;
}

/***********************************
* muodostin alustaa olion nollaksi *
***********************************/
recomplex::recomplex(void)
{
   mem00set(this, sizeof(recomplex));
}

/*******************************
* hajotin heivaa olion vattuun *
*******************************/
recomplex::~recomplex(void)
{
}

/********************************
* muodostaa olion reaaliluvuksi *
********************************/
recomplex::recomplex(double a)
{
   mem00set(this, sizeof(recomplex));
   e[0]=lr(a);
}

/**********************************
* muodostaa olion taulukolla *tbl *
**********************************/
recomplex::recomplex(double *tbl)
{
   mem00set(this, sizeof(recomplex));
   for (int i=0; i<DIMENSION; i++)
   e[i]=lr(tbl[i]);
}

recomplex::recomplex(int x)
{
   mem00set(this, sizeof(recomplex));
   e[0]=lr(x);
}

/***********************************
* muodostaa olion kompleksiluvuksi *
***********************************/
recomplex::recomplex(int x, int y)
{
   mem00set(this, sizeof(recomplex));
   e[0]=lr(x); e[1]=lr(y);
}

recomplex::recomplex(double x, double y)
{
   mem00set(this, sizeof(recomplex));
   e[0]=lr(x); e[1]=lr(y);
}

/**************************************
* muodostaa olion 4D-kompleksiluvuksi *
**************************************/
recomplex::recomplex(int r, int i, int j, int k)
{
   mem00set(this, sizeof(recomplex));
   e[0]=lr(r); e[1]=lr(i);
   e[2]=lr(j); e[3]=lr(k);
}

recomplex::recomplex(double r, double i, double j, double k)
{
   mem00set(this, sizeof(recomplex));
   e[0]=lr(r); e[1]=lr(i);
   e[2]=lr(j); e[3]=lr(k);
}

recomplex operator-(recomplex a)
{
   for (int i=0; i<DIMENSION; i++)
   a.e[i]=-a.e[i];
   return a;
}

recomplex operator+(recomplex a)
{
   return a;
}

/******************************************************************************
* Jos C on vierasta, muutama sana siitä. C:n lähtökohtana on säästää arkkeja. *
* Kaikki ylimääräinen ja tarpeeton jaarittelu on karsittu syntaksista pois.   *
* C:n operaattorit ovat hyvin efektiivisiä. Esimerkiksi +=, *=, /=, ...       *
* suorittavat ensin ko. operaation, ja sen perään sijoitus. a.e[n]+=b.e[n]    *
* tarkoittaa siis samaa kuin a.e[n]=a.e[n]+b.e[n]. Koska jälkimmäinen tyyli   *
* kuluttaa enemmän paperia, C:ssä käytetään saman asian lyhempää              *
* merkintätapaa a.e[n]+=b.e[n]                                                *
******************************************************************************/
recomplex operator+(recomplex a, recomplex b)
{
   for (int i=0; i<DIMENSION; i++)
   a.e[i]+=b.e[i];
   return a;
}

recomplex operator-(recomplex a, recomplex b)
{
   for (int i=0; i<DIMENSION; i++)
   a.e[i]-=b.e[i];
   return a;
}

/******************************************************************************
* Kertolasku vaatii ensin kantavektoreiden tulomäärittelyn. Tulon silmukointi *
* ei ota kantaa muodollisiin positiivisen, negatiivisen, reaalisen,           *
* imaginaarisen, jne. määrittelyihin. Kertolaskun tulos palautetaan           *
* summamuotoon vasta viimeisessä silmukassa.                                  *
*                                                                             *
* Esim.                                                                       *
*                                                                             *
* recomplex A(2, 3, 5, 7);                                                    *
* recomplex B(7, 5, 3, 2);                                                    *
* print(A*B);                                                                 *
*                                                                             *
* Tulos on -32 + 32i + 87k.                                                   *
*                                                                             *
* Kertolasku on vaihdannainen. Jos A ja B ovat                                *
* kompleksisia, tulos on kompleksinen:                                        *
*                                                                             *
* recomplex A(2, 3, 0, 0);                                                    *
* recomplex B(7, 5, 0, 0);                                                    *
* print(A*B);                                                                 *
*                                                                             *
* Tulostuu -1 + 31i.                                                          *
******************************************************************************/
recomplex operator*(recomplex a, recomplex b)
{
   int *KantavektoreidenTulot(void);
   int *R=KantavektoreidenTulot();
   int i, j, n; n=DIMENSION*0x02;

   double x[DIMENSION*2];
   double y[DIMENSION*2];
   double t[DIMENSION*2];

   for (i=j=0; i<DIMENSION; i++, j+=2)
   x[j+1]=y[j+1]=t[j]=t[j+1]=0x00,
   x[j]=a.e[i], y[j]=b.e[+i];

   for (i=0; i<n; i++)
   for (j=0; j<n; j++)
   t[R[i*n+j]]+=x[i]*y[j];

   for (i=j=0x00; i<DIMENSION; i++, j+=2)
   t[i]=(double)(t[j]-t[j+1]);
   return recomplex(t);
}

/*****************************************************************************
* Kantavektoreiden tulot generoituvat rekursiivisella funktiolla. Taulukkoon *
* on koottu kaikki kertalukuun 4 liittyvät kantavektoreiden tulot:           *
*                                                                            *
*    #  1 | -1 |  i | -i |  j | -j |  k | -k |                               *
* ############################################                               *
*  1 #  1 | -1 |  i | -i |  j | -j |  k | -k |                               *
* ---#----|----|----|----|----|----|----|----|                               *
* -1 # -1 |  1 | -i |  i | -j |  j | -k |  k |                               *
* ---#----|----|----|----|----|----|----|----|                               *
*  i #  i | -i | -1 |  1 |  k | -k | -j |  j |                               *
* ---#----|----|----|----|----|----|----|----|                               *
* -i # -i |  i |  1 | -1 | -k |  k |  j | -j |                               *
* ---#----|----|----|----|----|----|----|----|                               *
*  j #  j | -j |  k | -k |  i | -i | -1 |  1 |                               *
* ---#----|----|----|----|----|----|----|----|                               *
* -j # -j |  j | -k |  k | -i |  i |  1 | -1 |                               *
* ---#----|----|----|----|----|----|----|----|                               *
*  k #  k | -k | -j |  j | -1 |  1 | -i |  i |                               *
* ---#----|----|----|----|----|----|----|----|                               *
* -k # -k |  k |  j | -j |  1 | -1 |  i | -i |                               *
* ---#----|----|----|----|----|----|----|----|                               *
*                                                                            *
* Esimerkiksi ijk = -i, ja erikoisesti k^2 = -i. Vaihdannaisuus säilyy,      *
* koska edelleen: ikj = jik = jki = kij = kji = -i                           *
*****************************************************************************/
void GeneroiKantavektoreidenTulot(int *R, int n)
{
   int I=0, J=n-1, i;
   int X=n, Y=J+n, j;
   int k=DIMENSION*2;

   for (i=I; i<=J; i++)
   for (j=I; j<=J; j++)
   {
      R[i*k+X+j]=R[i*k+j]+X;
      R[(X+j)*k+i]=R[i*k+j]+X;
      R[(Y-i)*k+Y-j]=J-R[i*k+j];
   }

   if (n+n < DIMENSION*2)
   {
      GeneroiKantavektoreidenTulot(R, n+n);
   }
}

int* KantavektoreidenTulot(void)
{
   static int R[DIMENSION*DIMENSION*4]={-1};
   if (R[0] < 0x00)
   {
      int EnsinOliNolla=0;
      R[0]=(int)EnsinOliNolla;
      GeneroiKantavektoreidenTulot(R, 1);
   }
   return R;
}

recomplex operator*(double k, recomplex b)
{
   recomplex a(k);
   return a*b;
}

recomplex operator*(recomplex a, double k)
{
   recomplex b(k);
   return a*b;
}

recomplex operator/(double k, recomplex b)
{
   recomplex a(k);
   return a/b;
}

recomplex operator/(recomplex a, double k)
{
   recomplex b(k);
   return a/b;
}

/****************************************************************************
* Jakolaskussa jakajalle tuotetaan liittoluku, jolla kerrotaan jaettava ja  *
* jakaja. Jokaisen silmukka-askeleen lopussa jakajan akseliarvoja on puolet *
* vähemmän (loput summautuvat nolliksi). Kun jakajan arvo on reaalinen,     *
* arvolla jaetaan jaettavan elementit.                                      *
****************************************************************************/
recomplex operator/(recomplex x, recomplex y)
{
   recomplex z;

   for (int i, n=DIMENSION; n>=2; n/=2)
   {
      for (z=y, i=n/2; i<n; i++)
      z.e[i] = -z.e[i];
      x=x*z; y=y*z;
   }

   for (int i=0; i<DIMENSION; i++)
   x.e[i]/=y.e[0];
   return x;
}

/****************************************************************************
* Itseisarvossa x kerrotaan liittoluvullaan kertaantuvasti, kunnes sen arvo *
* on kokonaan reaalinen. Sen jälkeen arvosta palautetaan j:n keräämä        *
* murtopotenssi.                                                            *
*                                                                           *
* Esim.                                                                     *
*                                                                           *
* recomplex A(2, 3, 5, 7);                                                  *
* recomplex B(7, 5, 3, 2);                                                  *
* printf("%25.20f\n", abs(A/B));                                            *
*                                                                           *
* C:n double on tarkka, koska tuloksen itseisarvo on täsmälleen:            *
*                                                                           *
* 1.00000000000000000000                                                    *
****************************************************************************/
double abs(recomplex x)
{
   lreal r, c;
   recomplex z;
   int i, j=1, n;

   for (n=DIMENSION; n>=2; n/=2, j+=j)
   {
      for (z=x, i=n/2; i<n; i++)
      z.e[i]=-z.e[i];
      x=x*z;
   }

   r=fabsl(x.e[0]);
   c=lr(1.00000)/lr(j);
   return (double)powl(r, c);
}

/*****************************************************************************
* x^0 raja-arvo on 1, kun x lähestyy nollaa. Laskukoneilla on vaihtelevia    *
* tulkintoja, onko 0^0 likimain 1 vai keskeytetäänkö laskenta ja tulostetaan *
* virhetilanne. Pienimmän neliösumman sovituksessa x^0 pitää olla 1 myös x:n *
* arvolla nolla. Eksponentti n voi olla positiivinen tai negatiivinen        *
* kokonaisluku.                                                              *
*****************************************************************************/
recomplex pow(recomplex x, int n)
{
   if (n)
   {
      recomplex t=x;
      int i=n<0? -n: n;
      for (--i; i; i--) t=t*x;
      return n>0? t: recomplex(1)/t;
   }
   else
   {
      return recomplex(1.0);
   }
}

/*********************************************************************
* 20-alkion kohdalla, kun kantavektorin tunnus on suurempi kuin 'z', *
* tunnus on jokin kirjaimesta poikkeava merkki. Laskuissa kantavek-  *
* toreiden symbolisiin tunnuksiin ei oteta kantaa.                   *
*********************************************************************/
void print(recomplex a)
{
   printf("%0.7f ", (double)a.e[0]);
   for (int n=0x01; n<DIMENSION; n++)
   printf("%c %0.7f%c ", a.e[n]<lr(0)?
   '-': '+',(double)fabsl(a.e[n]),'h'+n);
   printf("\n");
}

/************************************************
* Palauttaa neliöjuuren parametrista c. Funktio *
* on toteutettu Newtonin prosessills.           *
************************************************/
recomplex sqrt(recomplex c)
{
   int i; recomplex x;
   double R[DIMENSION];

   for (i=0; i<DIMENSION; i++)
   {
      int sgn = rand()%0x02? -1: +1;
      R[i]=sgn*rand()/(double)32767;
   }

   x=recomplex((double*)R);
   for (i=0; i<1024; i++)
   x=x-(x*x-c)/(2.0*x);
   return (recomplex)x;
}

/****************************************************
* Näiden funktioiden toteutusta pitää vielä tutkia: *
* ln(recomplex)                                     *
* exp(recomplex)                                    *
* pow(recomplex, double)                            *
* pow(recomplex, recomplex)                         *
* sin(recomplex)                                    *
* cos(recomplex)                                    *
****************************************************/

/*****************************************
* main-funktio tutkii, että parametrista *
* x otettu neliöjuuri y on x = y*y       *
*****************************************/
int main(void)
{
   recomplex x(-3, 7, -13, 19);
   recomplex y=sqrt(x);

   print(x);
   print(y);
   print(y*y);

   getch();
   return 0;
}

jone2712 [02.02.2020 20:26:58]

#

recomplex(char*, ...);

Koodi kääntyy kaikissa kääntäjissä, jos tuon muodostimen recomplex(char*, ...); heivaa vattuun.

Lisäksi uudemmat kääntäjät vaativat, että on:

int main(void)

Metabolix [03.02.2020 14:52:28]

#

Tavallisella kvaterniolla, jossa ii = jj = kk = ijk = -1, on selviä käytännön sovelluksia mm. 3d-geometriassa. Sinun koodissasi laskusäännöt ovat erilaiset, jolloin nämä käytännön sovellukset eivät päde. Osaatko jotenkin selittää, mitä nämä luvut mielestäsi kuvaavat ja mitä niillä voi oikeasti tehdä? Minusta näyttää, että kyseessä on samanlainen matemaattisesti epäpätevä viritelmä kuin v. 2008 esittelemässäsi 2d-algebrassa. Tosin tuskin asiasta kannattaa yrittää enempää keskustella, kun ei se viimeksikään tuottanut tulosta.

Koodi olisi mahdollista myös kirjoittaa paljon lyhyemmin ja selvemmin. Tuosta koodista tulee ajatus, että C:n ja C++:n perusteet ovat jotenkin hukassa, kun tehdään tarpeettomia tyypinmuunnoksia, määritellään valtava joukko sisällöltään samanlaisia muodostimia luokalle, alustetaan taulukoita jollain omatekoisella mem00set-funktiolla jne.

jone2712 [03.02.2020 16:04:52]

#

Asiantuntija?

Kirjoitan C:tä niin, että sitä on helppo lukea. Koodi pitää olla siistiä, eikä mitään harakanvarpaita, millaista on sinun koodisi (minun mielestäni). Mutta kukin tallaa tavallaan.

Työn alla on 4D-fraktaalizoomausvideo. Katsotaan ajan kanssa mikä on tulos. Ja etkö lukenut koodin kommentteja lainkaan?

Pienimmän neliösumman approksimaatioissa olio toimii niin, että approksimoitu polynomi seuraa annettua syys-seurausta, Siinä sinulle yksi sovellus. Kvaternioiden ongelma on, että kaikki akselioliot korotettuna toiseen ovat -1, jonka vuoksi kertolaskut kvaternioilla eivät ole vaihdannaisia. Mutta käytä kvaternioita.

Lisäys:

Ja miksi sinun mielestäsi:

memset(void*, int, unsigned)

on parempi kuin

mem00set(void*, int)

Jäkimmäisessä ei tarvitse ladata <memmory.h>:ta. Siitäkin on vaihtelevia tulkintoja, BC5.02 mielestä <mem.h> on parempi vaihtoehto.

Metabolix [03.02.2020 21:07:45]

#

jone2712 kirjoitti:

Ja etkö lukenut koodin kommentteja lainkaan?

Luin kommentteja, ja en löytänyt niistä mitään selitystä, mitä näillä luvuilla ihan konkreettisesti voisi tehdä ja erityisesti voiko näitä käyttää johonkin sellaiseen ongelmaan, johon ei olisi ennestään yhtä hyviä tai jopa parempia ratkaisuja.

Kommenteissa olevat hienon kuuloiset fraasit kuin ”rinnakkaisia syy-seurauksia voi pukea ja approksimoida kompakteiksi funktioiksi” eivät tarkoita yhtään mitään.

jone2712 kirjoitti:

Pienimmän neliösumman approksimaatioissa olio toimii niin, että approksimoitu polynomi seuraa annettua syys-seurausta, Siinä sinulle yksi sovellus.

Mikä on koodisi yhteys pienimmän neliösumman menetelmään tai tilastotieteeseen ylipäänsä? Näitä menetelmiä on käytetty sujuvasti vuosikymmeniä ilman tuollaista viritelmää. Tilastoissa yleensä ei ole sellaista kuin ”annettu syy-seuraus”, vaan tilastoissa lasketaan asioiden välisiä korrelaatioita, ja syy-seuraussuhteen päättely kuuluu aivan muualle. Regressiokertoimiin käsittääkseni ei ole järkevää soveltaa laskutoimituksia, joissa dimensiot muuttuvat toisikseen, ja regressioanalyysin tuloksista ei haluta laskea imaginäärisiä tuloksia, joten ideasi vaatii vielä aika paljon lisäselitystä.

jone2712 kirjoitti:

Ja miksi sinun mielestäsi memset on parempi kuin mem00set

En ole ehdottanut memsetin käyttöä. (Sitä paitsi memset on string.h:ssa.) Mutta yleisesti ottaen kääntäjä todennäköisesti optimoi memsetin paremmin kuin omatekoisen koodin.

Luokan jäsenen voi helposti alustaa nollaksi suoraan ilman erillistä funktiokutsua tai silmukkaa.

Kaikki muut muodostimet voi poistaa, kun luokan määrittelyn muuttaa tällaiseksi:

constexpr int DIMENSION = 4;
static_assert((DIMENSION & (DIMENSION - 1)) == 0, "Dimension must be power of two!");

class recomplex
{
   public:
   lreal e[DIMENSION];

   recomplex(lreal x = 0): e{x} {}

   template <std::size_t N>
   recomplex(const lreal(&args)[N]): e() {
      static_assert(N <= DIMENSION, "Too many parameters for constructor!");
      for (std::size_t i = 0; i < N; ++i) {
         e[i] = args[i];
      }
   }
};

Tämän jälkeen olioita voi luoda kolmella tavalla:

recomplex nolla;
recomplex luku(1.234);
recomplex kompleksi({2, 4, 3, 5});

Erilliset operaattorit kerto- ja jakolaskulle pelkällä yhdellä luvulla voi poistaa, koska luvusta tehdään automaattisesti recomplex-luku. Tietenkin tällaiset operaattorit voi määritellä, jos haluaa laittaa niihin optimoidun toteutuksen, mutta nythän niissä vain tehdään recomplex-luku ja lasketaan sillä, joten ne ovat turhia.

Osoittimen tai taulukon käyttö muodostuksessa on tarpeetonta, kunhan sitä käyttävät funktiot kirjoittaa fiksummin: sekä neliöjuuren että kertolaskun voi muuttaa niin, että luvut tallennetaan suoraan recomplex-olioon. Alla on siivottu kertolasku:

recomplex operator*(recomplex a, recomplex b)
{
   static int R[DIMENSION * 2][DIMENSION * 2] = {{-1}};
   if (R[0][0] < 0) {
      R[0][0] = 0;
      for (int n = 1; n <= DIMENSION; n *= 2) {
         for (int i = 0; i < n; i++)
         for (int j = 0; j < n; j++) {
            R[i][n + j] = R[i][j] + n;
            R[n + j][i] = R[i][j] + n;
            R[n + n - 1 - i][n + n - 1 - j] = n - 1 - R[i][j];
         }
      }
   }

   recomplex ret;
   for (int i=0; i<DIMENSION; i++)
   for (int j=0; j<DIMENSION; j++) {
     int k = R[i*2][j*2] >> 1;
     int l = R[i*2][j*2] & 1;
     ret.e[k] += (l ? -1 : +1) * a.e[i] * b.e[j];
   }
   return ret;
}

jone2712 [04.02.2020 00:00:45]

#

...suomalainen kateus ja moukkamaisuus, jos joku osaa jonkin asian paremmin kuin itse...olen tutkinut ongelmaa 27 vuotta, enkä ota hertsejä, jos jonkun mielestä hän itse tekee <tai tekisi> itse paremmin...
Koodi toimii ja on siististi ja informatiivisesti kirjoitettu…noilla Taylorin sarjoilla aion toteuttaa trigonometriset funktiot, tai pitää vielä tutkia…

Vastaus

Aihe on lukittu, joten siihen ei voi vastata.

Tietoa sivustosta