Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++: Arduinolle tehdyn koodin siirto Windowsiin

Jokamies [27.03.2021 07:53:45]

#

Yritin pyörittää arduinolle kirjoitettua neuroverkko-ohjelmaa windowsin code::blocks 20.03 GNU GCC kehitysympäristössä. Alkuperäinen koodi on täältä

Yritin muuttaa kaikki yhteensopimattomat kohdat. Vaihdoin esim. bytet -> uint8_t ja muokkasin randomia ja tulosteita. Ohjelma ei kuitenkaan toimi odotetulla tavalla, vaan virhe kasvaa valtavaksi ja ulostulot saturoituvat välittömästi. Osaisiko joku sanoa mikä tuossa mättää?

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <math.h>

using namespace std;
/******************************************************************
 * Network Configuration - customized per network
 ******************************************************************/

const int16_t PatternCount = 10;
const int16_t InputNodes = 7;
const int16_t HiddenNodes = 8;
const int16_t OutputNodes = 4;
const float LearningRate = 0.3;
const float Momentum = 0.9;
const float InitialWeightMax = 0.5;
const float Success = 0.0004;

const uint8_t Input[PatternCount][InputNodes] = {
  { 1, 1, 1, 1, 1, 1, 0 },  // 0
  { 0, 1, 1, 0, 0, 0, 0 },  // 1
  { 1, 1, 0, 1, 1, 0, 1 },  // 2
  { 1, 1, 1, 1, 0, 0, 1 },  // 3
  { 0, 1, 1, 0, 0, 1, 1 },  // 4
  { 1, 0, 1, 1, 0, 1, 1 },  // 5
  { 0, 0, 1, 1, 1, 1, 1 },  // 6
  { 1, 1, 1, 0, 0, 0, 0 },  // 7
  { 1, 1, 1, 1, 1, 1, 1 },  // 8
  { 1, 1, 1, 0, 0, 1, 1 }   // 9
};

const uint8_t Target[PatternCount][OutputNodes] = {
  { 0, 0, 0, 0 },
  { 0, 0, 0, 1 },
  { 0, 0, 1, 0 },
  { 0, 0, 1, 1 },
  { 0, 1, 0, 0 },
  { 0, 1, 0, 1 },
  { 0, 1, 1, 0 },
  { 0, 1, 1, 1 },
  { 1, 0, 0, 0 },
  { 1, 0, 0, 1 }
};

/******************************************************************
 * End Network Configuration
 ******************************************************************/


int16_t i, j, p, q, r;
int16_t ReportEvery1000;
int16_t randomizedIndex[PatternCount];
long  TrainingCycle;
float Rando;
float Error;
float Accum;


float Hidden[HiddenNodes];
float Output[OutputNodes];
float HiddenWeights[InputNodes+1][HiddenNodes];
float OutputWeights[HiddenNodes+1][OutputNodes];
float HiddenDelta[HiddenNodes];
float OutputDelta[OutputNodes];
float ChangeHiddenWeights[InputNodes+1][HiddenNodes];
float ChangeOutputWeights[HiddenNodes+1][OutputNodes];

void toTerminal()
{

  for( p = 0 ; p < PatternCount ; p++ ) {
    cout <<" " << endl;
    cout <<"  Training Pattern: "<< p <<endl;
    cout << "  Input ";
    for( i = 0 ; i < InputNodes ; i++ ) {
      cout << int(Input[p][i]);
      cout<< (" ");
    }
    cout << "  Target ";
    for( i = 0 ; i < OutputNodes ; i++ ) {
      cout << int(Target[p][i]);
      cout <<" ";
    }
/******************************************************************
* Compute hidden layer activations
******************************************************************/

    for( i = 0 ; i < HiddenNodes ; i++ ) {
      Accum = HiddenWeights[InputNodes][i] ;
      for( j = 0 ; j < InputNodes ; j++ ) {
        Accum += Input[p][j] * HiddenWeights[j][i] ;
      }
      Hidden[i] = 1.0/(1.0 + expf(-Accum)) ;
    }

/******************************************************************
* Compute output layer activations and calculate errors
******************************************************************/

    for( i = 0 ; i < OutputNodes ; i++ ) {
      Accum = OutputWeights[HiddenNodes][i] ;
      for( j = 0 ; j < HiddenNodes ; j++ ) {
        Accum += Hidden[j] * OutputWeights[j][i] ;
      }
      Output[i] = 1.0/(1.0 + expf(-Accum)) ;
    }
    cout << "  Output ";
    for( i = 0 ; i < OutputNodes ; i++ ) {
      cout<< Output[i];
      cout << " ";
    }
  }


}


void setup(){
srand(time(0));
  ReportEvery1000 = 1;
  for( p = 0 ; p < PatternCount ; p++ ) {
    randomizedIndex[p] = p ;
  }
}
int16_t random(int16_t from, int16_t to){
    return (rand() % (to - from + 1) + from);
}

int main (){
    setup();
    while(1){


/******************************************************************
* Initialize HiddenWeights and ChangeHiddenWeights
******************************************************************/

  for( i = 0 ; i < HiddenNodes ; i++ ) {
    for( j = 0 ; j <= InputNodes ; j++ ) {
      ChangeHiddenWeights[j][i] = 0.0 ;
      Rando = float(random(0,100))/100;
      HiddenWeights[j][i] = 2.0 * ( Rando - 0.5 ) * InitialWeightMax ;
    }
  }
/******************************************************************
* Initialize OutputWeights and ChangeOutputWeights
******************************************************************/

  for( i = 0 ; i < OutputNodes ; i ++ ) {
    for( j = 0 ; j <= HiddenNodes ; j++ ) {
      ChangeOutputWeights[j][i] = 0.0 ;
      Rando = float(random(0,100))/100;
      OutputWeights[j][i] = 2.0 * ( Rando - 0.5 ) * InitialWeightMax ;
    }
  }
  cout <<"Initial/Untrained Outputs: ";
  toTerminal();
/******************************************************************
* Begin training
******************************************************************/

  for( TrainingCycle = 1 ; TrainingCycle < 2147483647 ; TrainingCycle++) {

/******************************************************************
* randize order of training patterns
******************************************************************/

    for( p = 0 ; p < PatternCount ; p++) {
      q = random(0,PatternCount);

      r = randomizedIndex[p] ;
      randomizedIndex[p] = randomizedIndex[q] ;
      randomizedIndex[q] = r ;
    }
    Error = 0.0 ;
/******************************************************************
* Cycle through each training pattern in the randized order
******************************************************************/
    for( q = 0 ; q < PatternCount ; q++ ) {
      p = randomizedIndex[q];

/******************************************************************
* Compute hidden layer activations
******************************************************************/

      for( i = 0 ; i < HiddenNodes ; i++ ) {
        Accum = HiddenWeights[InputNodes][i] ;
        for( j = 0 ; j < InputNodes ; j++ ) {
          Accum += Input[p][j] * HiddenWeights[j][i] ;

        }
        Hidden[i] = 1.0/(1.0 + expf(-Accum)) ;
        //cout<< "i:"<<i<<" "<<Hidden[i] <<endl;
      }

/******************************************************************
* Compute output layer activations and calculate errors
******************************************************************/

      for( i = 0 ; i < OutputNodes ; i++ ) {
        Accum = OutputWeights[HiddenNodes][i] ;
        for( j = 0 ; j < HiddenNodes ; j++ ) {
          Accum += Hidden[j] * OutputWeights[j][i] ;
        }
        Output[i] = 1.0/(1.0 + expf(-Accum)) ;
        OutputDelta[i] = (Target[p][i] - Output[i]) * Output[i] * (1.0 - Output[i]) ;
        //cout<< OutputDelta[i]<<endl;
        Error += 0.5 * (Target[p][i] - Output[i]) * (Target[p][i] - Output[i]) ;
      }

/******************************************************************
* Backpropagate errors to hidden layer
******************************************************************/

      for( i = 0 ; i < HiddenNodes ; i++ ) {
        Accum = 0.0 ;
        for( j = 0 ; j < OutputNodes ; j++ ) {
          Accum += OutputWeights[i][j] * OutputDelta[j] ;
        }
        HiddenDelta[i] = Accum * Hidden[i] * (1.0 - Hidden[i]) ;
      }


/******************************************************************
* Update Inner-->Hidden Weights
******************************************************************/


      for( i = 0 ; i < HiddenNodes ; i++ ) {
        ChangeHiddenWeights[InputNodes][i] = LearningRate * HiddenDelta[i] + Momentum * ChangeHiddenWeights[InputNodes][i] ;
        HiddenWeights[InputNodes][i] += ChangeHiddenWeights[InputNodes][i] ;
        for( j = 0 ; j < InputNodes ; j++ ) {
          ChangeHiddenWeights[j][i] = LearningRate * Input[p][j] * HiddenDelta[i] + Momentum * ChangeHiddenWeights[j][i];
          HiddenWeights[j][i] += ChangeHiddenWeights[j][i] ;
        }
      }

/******************************************************************
* Update Hidden-->Output Weights
******************************************************************/

      for( i = 0 ; i < OutputNodes ; i ++ ) {
        ChangeOutputWeights[HiddenNodes][i] = LearningRate * OutputDelta[i] + Momentum * ChangeOutputWeights[HiddenNodes][i] ;
        OutputWeights[HiddenNodes][i] += ChangeOutputWeights[HiddenNodes][i] ;
        for( j = 0 ; j < HiddenNodes ; j++ ) {
          ChangeOutputWeights[j][i] = LearningRate * Hidden[j] * OutputDelta[i] + Momentum * ChangeOutputWeights[j][i] ;
          OutputWeights[j][i] += ChangeOutputWeights[j][i] ;
        }
      }
    }

/******************************************************************
* Every 1000 cycles send data to terminal for display
******************************************************************/
    ReportEvery1000 = ReportEvery1000 - 1;
    if (ReportEvery1000 == 0)
    {
      cout << " " <<endl;
      cout << " " <<endl;
      cout <<"TrainingCycle: ";
      cout <<TrainingCycle;
      cout<<"  Error = ";
      cout <<Error;

      toTerminal();

      if (TrainingCycle==1)
      {
        ReportEvery1000 = 999;
      }
      else
      {
        ReportEvery1000 = 1000;
      }
    }


/******************************************************************
* If error rate is less than pre-determined threshold then end
******************************************************************/

    if( Error < Success ) break ;
  }
  cout <<" " << endl;
  cout <<" " << endl;
  cout << "TrainingCycle: " << endl;
  cout<<TrainingCycle;
  cout <<"  Error = ";
  cout <<Error;

  toTerminal();

  cout << " " << endl;
  cout <<" " << endl;
  cout <<"Training Set Solved! " << endl;
  cout <<"--------"<< endl;
  cout <<" " << endl;
  cout <<" " << endl;
  ReportEvery1000 = 1;
}
return(0);
}

Tässä taas alkuperäinen koodi:

#include <math.h>

/******************************************************************
 * Network Configuration - customized per network
 ******************************************************************/

const int PatternCount = 10;
const int InputNodes = 7;
const int HiddenNodes = 8;
const int OutputNodes = 4;
const float LearningRate = 0.3;
const float Momentum = 0.9;
const float InitialWeightMax = 0.5;
const float Success = 0.0004;

const byte Input[PatternCount][InputNodes] = {
  { 1, 1, 1, 1, 1, 1, 0 },  // 0
  { 0, 1, 1, 0, 0, 0, 0 },  // 1
  { 1, 1, 0, 1, 1, 0, 1 },  // 2
  { 1, 1, 1, 1, 0, 0, 1 },  // 3
  { 0, 1, 1, 0, 0, 1, 1 },  // 4
  { 1, 0, 1, 1, 0, 1, 1 },  // 5
  { 0, 0, 1, 1, 1, 1, 1 },  // 6
  { 1, 1, 1, 0, 0, 0, 0 },  // 7
  { 1, 1, 1, 1, 1, 1, 1 },  // 8
  { 1, 1, 1, 0, 0, 1, 1 }   // 9
};

const byte Target[PatternCount][OutputNodes] = {
  { 0, 0, 0, 0 },
  { 0, 0, 0, 1 },
  { 0, 0, 1, 0 },
  { 0, 0, 1, 1 },
  { 0, 1, 0, 0 },
  { 0, 1, 0, 1 },
  { 0, 1, 1, 0 },
  { 0, 1, 1, 1 },
  { 1, 0, 0, 0 },
  { 1, 0, 0, 1 }
};

/******************************************************************
 * End Network Configuration
 ******************************************************************/


int i, j, p, q, r;
int ReportEvery1000;
int RandomizedIndex[PatternCount];
long  TrainingCycle;
float Rando;
float Error;
float Accum;


float Hidden[HiddenNodes];
float Output[OutputNodes];
float HiddenWeights[InputNodes+1][HiddenNodes];
float OutputWeights[HiddenNodes+1][OutputNodes];
float HiddenDelta[HiddenNodes];
float OutputDelta[OutputNodes];
float ChangeHiddenWeights[InputNodes+1][HiddenNodes];
float ChangeOutputWeights[HiddenNodes+1][OutputNodes];

void setup(){
  Serial.begin(9600);
  randomSeed(analogRead(3));
  ReportEvery1000 = 1;
  for( p = 0 ; p < PatternCount ; p++ ) {
    RandomizedIndex[p] = p ;
  }
}

void loop (){


/******************************************************************
* Initialize HiddenWeights and ChangeHiddenWeights
******************************************************************/

  for( i = 0 ; i < HiddenNodes ; i++ ) {
    for( j = 0 ; j <= InputNodes ; j++ ) {
      ChangeHiddenWeights[j][i] = 0.0 ;
      Rando = float(random(100))/100;
      HiddenWeights[j][i] = 2.0 * ( Rando - 0.5 ) * InitialWeightMax ;
    }
  }
/******************************************************************
* Initialize OutputWeights and ChangeOutputWeights
******************************************************************/

  for( i = 0 ; i < OutputNodes ; i ++ ) {
    for( j = 0 ; j <= HiddenNodes ; j++ ) {
      ChangeOutputWeights[j][i] = 0.0 ;
      Rando = float(random(100))/100;
      OutputWeights[j][i] = 2.0 * ( Rando - 0.5 ) * InitialWeightMax ;
    }
  }
  Serial.println("Initial/Untrained Outputs: ");
  toTerminal();
/******************************************************************
* Begin training
******************************************************************/

  for( TrainingCycle = 1 ; TrainingCycle < 2147483647 ; TrainingCycle++) {

/******************************************************************
* Randomize order of training patterns
******************************************************************/

    for( p = 0 ; p < PatternCount ; p++) {
      q = random(PatternCount);
      r = RandomizedIndex[p] ;
      RandomizedIndex[p] = RandomizedIndex[q] ;
      RandomizedIndex[q] = r ;
    }
    Error = 0.0 ;
/******************************************************************
* Cycle through each training pattern in the randomized order
******************************************************************/
    for( q = 0 ; q < PatternCount ; q++ ) {
      p = RandomizedIndex[q];

/******************************************************************
* Compute hidden layer activations
******************************************************************/

      for( i = 0 ; i < HiddenNodes ; i++ ) {
        Accum = HiddenWeights[InputNodes][i] ;
        for( j = 0 ; j < InputNodes ; j++ ) {
          Accum += Input[p][j] * HiddenWeights[j][i] ;
        }
        Hidden[i] = 1.0/(1.0 + exp(-Accum)) ;
      }

/******************************************************************
* Compute output layer activations and calculate errors
******************************************************************/

      for( i = 0 ; i < OutputNodes ; i++ ) {
        Accum = OutputWeights[HiddenNodes][i] ;
        for( j = 0 ; j < HiddenNodes ; j++ ) {
          Accum += Hidden[j] * OutputWeights[j][i] ;
        }
        Output[i] = 1.0/(1.0 + exp(-Accum)) ;
        OutputDelta[i] = (Target[p][i] - Output[i]) * Output[i] * (1.0 - Output[i]) ;
        Error += 0.5 * (Target[p][i] - Output[i]) * (Target[p][i] - Output[i]) ;
      }

/******************************************************************
* Backpropagate errors to hidden layer
******************************************************************/

      for( i = 0 ; i < HiddenNodes ; i++ ) {
        Accum = 0.0 ;
        for( j = 0 ; j < OutputNodes ; j++ ) {
          Accum += OutputWeights[i][j] * OutputDelta[j] ;
        }
        HiddenDelta[i] = Accum * Hidden[i] * (1.0 - Hidden[i]) ;
      }


/******************************************************************
* Update Inner-->Hidden Weights
******************************************************************/


      for( i = 0 ; i < HiddenNodes ; i++ ) {
        ChangeHiddenWeights[InputNodes][i] = LearningRate * HiddenDelta[i] + Momentum * ChangeHiddenWeights[InputNodes][i] ;
        HiddenWeights[InputNodes][i] += ChangeHiddenWeights[InputNodes][i] ;
        for( j = 0 ; j < InputNodes ; j++ ) {
          ChangeHiddenWeights[j][i] = LearningRate * Input[p][j] * HiddenDelta[i] + Momentum * ChangeHiddenWeights[j][i];
          HiddenWeights[j][i] += ChangeHiddenWeights[j][i] ;
        }
      }

/******************************************************************
* Update Hidden-->Output Weights
******************************************************************/

      for( i = 0 ; i < OutputNodes ; i ++ ) {
        ChangeOutputWeights[HiddenNodes][i] = LearningRate * OutputDelta[i] + Momentum * ChangeOutputWeights[HiddenNodes][i] ;
        OutputWeights[HiddenNodes][i] += ChangeOutputWeights[HiddenNodes][i] ;
        for( j = 0 ; j < HiddenNodes ; j++ ) {
          ChangeOutputWeights[j][i] = LearningRate * Hidden[j] * OutputDelta[i] + Momentum * ChangeOutputWeights[j][i] ;
          OutputWeights[j][i] += ChangeOutputWeights[j][i] ;
        }
      }
    }

/******************************************************************
* Every 1000 cycles send data to terminal for display
******************************************************************/
    ReportEvery1000 = ReportEvery1000 - 1;
    if (ReportEvery1000 == 0)
    {
      Serial.println();
      Serial.println();
      Serial.print ("TrainingCycle: ");
      Serial.print (TrainingCycle);
      Serial.print ("  Error = ");
      Serial.println (Error, 5);

      toTerminal();

      if (TrainingCycle==1)
      {
        ReportEvery1000 = 999;
      }
      else
      {
        ReportEvery1000 = 1000;
      }
    }


/******************************************************************
* If error rate is less than pre-determined threshold then end
******************************************************************/

    if( Error < Success ) break ;
  }
  Serial.println ();
  Serial.println();
  Serial.print ("TrainingCycle: ");
  Serial.print (TrainingCycle);
  Serial.print ("  Error = ");
  Serial.println (Error, 5);

  toTerminal();

  Serial.println ();
  Serial.println ();
  Serial.println ("Training Set Solved! ");
  Serial.println ("--------");
  Serial.println ();
  Serial.println ();
  ReportEvery1000 = 1;
}

void toTerminal()
{

  for( p = 0 ; p < PatternCount ; p++ ) {
    Serial.println();
    Serial.print ("  Training Pattern: ");
    Serial.println (p);
    Serial.print ("  Input ");
    for( i = 0 ; i < InputNodes ; i++ ) {
      Serial.print (Input[p][i], DEC);
      Serial.print (" ");
    }
    Serial.print ("  Target ");
    for( i = 0 ; i < OutputNodes ; i++ ) {
      Serial.print (Target[p][i], DEC);
      Serial.print (" ");
    }
/******************************************************************
* Compute hidden layer activations
******************************************************************/

    for( i = 0 ; i < HiddenNodes ; i++ ) {
      Accum = HiddenWeights[InputNodes][i] ;
      for( j = 0 ; j < InputNodes ; j++ ) {
        Accum += Input[p][j] * HiddenWeights[j][i] ;
      }
      Hidden[i] = 1.0/(1.0 + exp(-Accum)) ;
    }

/******************************************************************
* Compute output layer activations and calculate errors
******************************************************************/

    for( i = 0 ; i < OutputNodes ; i++ ) {
      Accum = OutputWeights[HiddenNodes][i] ;
      for( j = 0 ; j < HiddenNodes ; j++ ) {
        Accum += Hidden[j] * OutputWeights[j][i] ;
      }
      Output[i] = 1.0/(1.0 + exp(-Accum)) ;
    }
    Serial.print ("  Output ");
    for( i = 0 ; i < OutputNodes ; i++ ) {
      Serial.print (Output[i], 5);
      Serial.print (" ");
    }
  }


}

Metabolix [27.03.2021 10:16:52]

#

Virhe on siinä, että Arduinon random tuottaa luvun, joka on aina alle parametrin, ja sinun tekemäsi random tuottaa luvun, joka voi olla myös parametrin suuruinen. Tämä johtaa siihen, että luet arvoja taulukon ulkopuolelta (tuloksena voi olla PatternCount eikä PatternCount - 1). Tästä seuraa ainakin omalla koneellani ohjelman kaatuminen (segfault) ja varmasti sitä ennen outoja tuloksia.

Vertailin antamiasi kahta koodia, ja jäi hämmennys siitä, että et kai nyt sentään ole kirjoittanut käsin uudestaan noin pitkää koodia? Muutoksia näkyy olevan yksittäisten muuttujien nimissä ja jopa kommenttien kirjoitusasussa, mikä ei oikein käy järkeen, jos tavoitteena on vain muuttaa koodi toimivaksi. Looginen lähestymistapa tällaisessa on yrittää kääntää koodia ja korjata vain virhekohdat, mieluiten sellaisella tavalla, ettei tarvitse korjata jokaista erikseen vaan tulee korjattua kaikki samanlaiset kohdat kerralla.

Arduino-koodisi saa suoraan käännettyä C++-koodina ja ajettua, kun tekee alkuun seuraavat lisäykset:

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

#define randomSeed(x) srand((int)time(0))
#define random(x) (rand()%(x))

#define DEC 10
struct Serial_ {
	void begin(int baud) {}
	void println() {
		puts("");
	}
	template <typename T> void println(T x, int format = -1) {
		print(x, format);
		println();
	}
	void print(const char* x, int format = 0) {
		printf("%s", x);
	}
	void print(int32_t x, int format = -1) {
		if (format == -1) format = DEC;
		if (format != DEC) throw 0;
		printf("%d", x);
	}
	void print(float x, int format = -1) {
		if (format == -1) format = 2;
		printf("%.*f", format, x);
	}
} Serial;

void setup();
void loop();
void toTerminal();
int main() {
	setup();
	loop();
}

#define byte uint8_t
#define int int16_t
#define long int32_t

Jos on tarkoitus pitää koodi myös Arduinolla toimivana, on fiksua käyttää jotain tällaista yhteensopivaa tapaa tulostukseen, tai koodista voi erottaa tulostuksen muualle ja tehdä vain laskentaosan järjestelmien välillä yhteensopivaksi. Jos taas on tarkoitus jatkaa kehitystä täysin ilman Arduinoa, tästä on helppo lähteä yksitellen poistamaan yhteensopivuuskikkoja ja korjaamaan kyseiset kohdat koodista ihan oikeasti.

Jokamies [27.03.2021 21:38:11]

#

Kiitos paljon! Tuo sinun ratkaisu on kyllä näppärä. Tarkoitus on tosiaan ehkä kehittelyn jälkeen siirtää takaisin jollekin isompimuistiselle mikrokontrollerille niin tuo on siinä mielessä hyvä. Jotain tuollaista itsekin hahmottelin mutta ei oikein taipunut niin ajattelin että nopeampi kun tekstinkäsittelyn replacella teen pikku muutokset. No sehän meni vähän säheltämiseksi sitten... mutta en suinkaan kirjoittanut koko koodia käsin :) kun kommentissa luki randomized ja korvasin randomit randilla niin tuli randized.

Mikähän ero noilla exp() ja expf() on kun näköjään exp() toimii floatilla?

Metabolix [27.03.2021 22:15:40]

#

Jokamies kirjoitti:

kun kommentissa luki randomized ja korvasin randomit randilla niin tuli randized.

Niinpä tietenkin. Tällaisten vikojen välttämiseksi itse yleensä laitan sulkumerkin mukaan korvaukseen, esimerkiksi ”rand(”. Tietysti joskus tulee ongelmia, jos koodissa on käytetty välilyöntejä vaihtelevasti (tai harvemmin esimerkiksi funktio-osoittimien yhteydessä). Monessa editorissa on mahdollista valita, että korvaus käsittelee vain kokonaisia sanoja. Tietylle kielelle tarkoitetut editorit voivat myös analysoida koodia niin hyvin, että on mahdollista vaihtaa yksittäisen funktion tai muuttujan nimi ilman sekaannuksen vaaraa.

Jokamies kirjoitti:

Mikähän ero noilla exp() ja expf() on kun näköjään exp() toimii floatilla?

C:ssä samalla nimellä voi olla vain yksi funktio, minkä vuoksi (standardin mukaan) exp toimii doublella ja expf floatilla ja muistakin matematiikkafunktioista on vastaavasti erilliset versiot. Joissain piireissä eletään yhä tuolla kivikaudella, mutta uudemmassa C99-standardissa (vuodelta 1999 nimensä mukaan) on tehty näistä geneerisen nimisistä verioista makroja, jotka tunnistavat parametrin tyypin ja kutsuvat oikeaa funktiota, joten enää ei pitäisi olla tarvetta f-päätteelle funktioissa.

C++ taas sisältää funktioiden ylikuormitukset, jolloin samalla nimellä löytyy funktiosta versioita usealle eri tietotyypille.

Arduinon tilanne jää dokumentaatiosta epäselväksi, kun siellä mainitaan matemaattisten funktioiden parametrin tyypiksi float ja paluuarvon tyypiksi double ja on ilmeisesti vain tuo yksi versio funktiosta. Itse en käytä Arduinoa, joten en tiedä asian todellista laitaa.

The Alchemist [28.03.2021 11:01:12]

#

Search/replace on oma taiteenlajinsa. Säännöllisten lausekkeiden käyttö voi myös auttaa, joskus selviää noilla yksinkertaisilla kikoilla kuten Metabolixin neuvomalla sulkumerkin lisäämisellä etsittävään merkkijonoon.

Viimeisenä oljenkortena on tehdä uusi, korjaava korvaus. Eli jos ensimmäisen korvauksen jälkeen ongelmana on merkkijonon "randized" esiintyminen, niin korvaa sitten sana randized takaisin sanaksi randomized.

Monet tekstieditorit sallivat myös käydä korvattavat esiintymät läpi yksitellen, jolloin voi manuaalisesti ohittaa ne esiintymät, joita et haluakaan korvata. (Eli yksi korvaushaku löytää esimerkiksi 10 osumaa, jolloin nextiä painamalla voit käydä osumat läpi yksitellen ja valita jokaisen kohdalla, haluatko suorittaa korvauksen vai ohittaa esiintymän.)

Grez [28.03.2021 14:14:58]

#

clbuttic mistake!

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta