efekt_motyla Temat założony przez niniejszego użytkownika |
Interpolacja Liniowa » 2016-08-22 22:35:44 Witam wszystkich, chciałbym zrobić program do interpolacji Liniowej. Program ma czytać z pliku txt dane , a jeśli w pliku jest pusta linijka to program powinien obliczyć co powinno się znajdować w pustej linii. Zrobiłem program który działa gdy z pliku usuniemy jedną lub dwie po koleii linie. Ale gdy usune 3 lub więcej linii po sobie to program wyrzuca mi głupoty. Wiem jaki błąd robię, mój program bierze liczy linijki po kolei , a powinien robić to zawsze dla środkowego wyrazu.... tylko nie wiem jak to zrobić??? zastosować mediane dla zmiennej i w tablicy??? Sami popatrzcie ponieważ siedzę już dłuższy czas i nie potrafię tego zrobić. W moim programie zamiast pustych linijek są zera (ponieważ jestem początkowym i nie zagłębiałem się jeszcze jak zamienić na stringa... ). Czyli jeśli mam plik txt (u mnie nazywa się "zrodlo.txt" ) to zrobiłem tak aby czytało po spacji. Że niby dwie kolumny pierwsza to x, a druga to y. tak wygląda u mnie plik txt. " 13 13 14 14 13 13 14 14 0 0 16 16 17 17 18 18 19 19 20 20 I chodzi o to żeby w jakiejś linijce usunąć dane ( po mojemu wstawić "0" ponieważ jak wcześniej pisałem nie wiem narazie jak czytać puste linie, przykładowo zero u mnie jest w linijce piątej i po kompilacji program wyliczy ze powinno być tam: 15) i program ma wyliczyć dane. ale gdy juz jest trzy lub więcej wierszy zer po sobie, to program wywala głupoty "0 " : np: 13 13 14 14 13 13 14 14 0 0 0 0 0 0 18 18 19 19 20 20 Proszę o pomoc. Mam nadzieje że w dobrym miejscu wkleiłem temat, ponieważ jestem tu nowy :) #include <iostream> #include <fstream> #include <cstdlib> #include <Eigen/Dense>
using namespace std;
int x[ 100 ]; int y[ 100 ];
int test( int markers[ 10 ][ 2 ], int x, int y, int xLength, int yLength ) { int marker = 0; for( int i = x + 1; i < xLength; i++ ) { if( markers[ i ][ y ] != 0 ) { marker = markers[ i ][ y ]; break; } } return( markers[ x - 1 ][ y ] + marker ) / 2; }
string int2str( int i ) { stringstream ss; string temp; ss << i; ss >> temp; return temp; }
int main() { int markers[ 10 ][ 2 ]; int markersAfter[ 10 ][ 2 ]; int xLength = 0; int yLength = 0; ifstream plik( "zrodlo.txt" ); for( xLength = 0; xLength < 10; xLength++ ) { for( yLength = 0; yLength < 2; yLength++ ) plik >> markers[ xLength ][ yLength ]; } for( int x = 0; x < 10; x++ ) for( int y = 0; y < 2; y++ ) { if( markers[ x ][ y ] == 0 ) markers[ x ][ y ] = test( markers, x, y, xLength, yLength ); } ofstream file; file.open( "zrodloAfter.txt" ); string output; for( int x = 0; x < 10; x++ ) { output = ""; for( int y = 0; y < 2; y++ ) output += int2str( markers[ x ][ y ] ) + " "; cout << output + "\n"; file << output + "\n"; } file.close(); system( "pause" ); return 0; } |
|
darko202 |
» 2016-08-23 09:11:30 1. bardzo ważne jest !! abyś zapoznał się z technologią debugowania programu dzięki temu możesz * analizować stan zmiennych linia po linii * zatrzymać się w konkretnym momencie (tzw. breakpoint) i zobaczyć jak jest wtedy dzięki temu sam namierzysz 90% problemów 2. w linii return( markers[ x - 1 ][ y ] + marker ) / 2; dla x=0 odwołujesz się poza zakres tablicy int test.... ... return( markers[ x - 1 ][ y ] + marker ) / 2; ..... for( int x = 0; x < 10; x++ ) for( int y = 0; y < 2; y++ ) { if( markers[ x ][ y ] == 0 ) markers[ x ][ y ] = test( markers, x, y, xLength, yLength ); }
3. czytasz 20 razy - gdy zmienisz ilość linii * pojawi się błąd odczytu * wymaga poprawek w programie * program się sypie nie jest to eleganckie i bezpieczne rozwiązanie popraw poniższy kod uwzględniając powyższe uwagi int xLength = 0; int yLength = 0;
ifstream plik( "zrodlo.txt" );
for( xLength = 0; xLength < 10; xLength++ ) { for( yLength = 0; yLength < 2; yLength++ ) plik >> markers[ xLength ][ yLength ]; }
4. >>chciałbym zrobić program do interpolacji Liniowej z definicji interpolacji liniowej - robisz tylko 1 przypadek https://pl.wikipedia.org/wiki/Interpolacja_liniowaPowodzenia |
|
efekt_motyla Temat założony przez niniejszego użytkownika |
interpolacja liniowa » 2016-08-23 23:31:31 Tak wiem o tych wszystkich błędach, i że wygląda to mało profesionalnie. Poprostu chce nad tym popracować pózniej. Narazie proszę o pomoc jeśli chodz o wzór który mi zinterpoluje wartości pustych linii (u mnie są to narazie zera ponieważ nie wiem jak zmienic inty na stringi, ale to nie ważne). Uproszczona wersja kodu :) : #include <iostream> #include <fstream> #include <cstdlib>
using namespace std;
int main() { int liczba[ 10 ]; ifstream plik( "nauka.txt" ); for( int i = 0; i < 10; i++ ) plik >> liczba[ i ]; for( int i = 0; i < 10; i++ ) { cout << liczba[ i ] << " "; cout << "\n"; } cout << endl << endl; for( int i = 0; i <= 10; i++ ) { if( liczba[ i ] == 0 ) { liczba[ i ] =( liczba[ i - 1 ] + liczba[ i + 1 ] ) / 2; cout << endl << "Klatka " << i << ": " << endl << liczba[ i ] << endl; } else { cout << endl << "Klatkaa " << i << ": " << endl << liczba[ i ] << endl; } } system( "pause" ); return 0; }
Jeśli program wczyta mi z notatnika plik z jedną wartością zerową np: : 11 12 13 14 0 - tutaj , jak widzimy. Program zinterpoluje wartosc 0. ( 14+16/2 = 15 ) 16 17 18 19 20 21 22 Natomiast mój problem dotyczy sytuacji w której plik będzie miał następujące po sobie wartości zerowe np: (zakładamy że pierwsza i ostatnia wartość nigdy u mnie nie będzie zerem , żeby można było móc interpolować łątwo (i nie chce się zagłębiać w takie trudności :))) 11 12 0 0 0 0 0 0 0 20 21 22 Więc proszę jeszcze raz o pomoc, jak powinien wyglądać algorytm który zliczy wartosci zerowe. Myślę że powinno to wyglądać tak: 1) program musi wybrać wartość napotkaną przed zerem 2) Następnie musi iść do wartości po zerach , która jest różna od zera 3) wybrać środek (środek to u mnie znaczy ze wybrac srodkowa wartosc biorac pod uwage zliczanie samych wartosci zerowych) , i przypisac do niej wzór : (wartosc różna od zera z punktu 1 + wartosc różna od zera punktu 2 ) /2. 4) I potem tak to dzielić jakoś na pół i na pół aż wszystkie wartości nie będą zerami. Czy dobrze myślę ??? Nie mam pojęcia jak to przełożyć na program dlatego proszę o POMOC . Dziękuję |
|
Gibas11 |
» 2016-08-24 00:49:48 Można duuużo prościej. ;) 1. Znajdujesz zera, ich ilość należy zapamiętać jako np. 'z'. 2. Bierzesz pierwszą wartość przed zerami i pierwszą za. Nazwiemy je kolejno 'b' i 'e' (od begin i end). Teraz za n-te zero (n zaczyna się od 1) należy wstawić: 'b' + ('e' - 'b') / 'z' * n Pamiętaj o kolejności wykonywania działań, jest tu ważna. :P #include <iostream> #include <fstream> #include <vector>
int main() { std::ifstream in( "liczby.txt" ); std::vector < double > numbers; for( int i; in >> i; ) numbers.push_back( i ); for( auto i = 0u; i + 1 < numbers.size(); i++ ) { if( numbers[ i + 1 ] == 0 ) { double beginVal = numbers[ i ]; auto index = i; while( numbers[ ++i ] == 0 ) continue; double endVal = numbers[ i ]; double diff = i - index; i = index; while( numbers[ ++i ] == 0 ) numbers[ i ] = beginVal +( endVal - beginVal ) / diff *( i - index ); } } for( auto it = numbers.begin(); it != numbers.end(); ++it ) std::cout << * it << std::endl; return 0; }
Radzi sobie też z bardziej skompilowanymi przykładami: 11 12 0 0 0 0 0 0 0 20 21 22 0 0 16
Da to: 11 12 13 14 15 16 17 18 19 20 21 22 20 18 16
Program nie zadziała jeśli plik zaczyna lub kończy się zerem, ale chyba pisałeś, że coś takiego nie występuje. //edit: Teraz zauważyłem, że chcesz to zrobić dla par liczb (współrzędne?), generalnie nie ma z tym problemu i wystarczy drobna modyfikacja mojego kodu, już bez komentarzy bo się robi śmietnik: #include <iostream> #include <fstream> #include <vector>
template < typename T > void interpolate( std::vector < T >& numbers ) { for( auto i = 0u; i + 1 < numbers.size(); i++ ) { if( numbers[ i + 1 ] == 0 ) { auto beginVal = numbers[ i ]; auto index = i; while( numbers[ ++i ] == 0 ) continue; auto endVal = numbers[ i ]; auto diff = i - index; i = index; while( numbers[ ++i ] == 0 ) numbers[ i ] = beginVal +( endVal - beginVal ) / diff *( i - index ); } } }
int main() { std::ifstream in( "liczby.txt" ); std::vector < double > x; std::vector < double > y; for( int i, j; in >> i >> j; ) { x.push_back( i ); y.push_back( j ); } interpolate( x ); interpolate( y ); for( auto i = 0u; i < x.size() && i < y.size(); ++i ) std::cout << "[" << x[ i ] << ", " << y[ i ] << "]" << std::endl; return 0; }
Zasada działania jest praktycznie taka sama, zmieniło się tylko wczytywanie danych a samą interpolację wsadziłem do funkcji. //edit2: Jak masz problemy z kompilacją ( typename w szablonach trafiło do standardu dopiero w c++17) możesz wywalić szablon funkcji i dać tam zwykłe void interpolate( std::vector < double >& numbers ) |
|
Elaine |
» 2016-08-24 06:16:23 typename w szablonach trafiło do standardu dopiero w c++17 |
Co? To, jak w kodzie użyłeś typename jest w standardzie od 1998, czyli odkąd w ogóle istnieje standard. W C++17 zmieni się w tej kwestii tylko tyle, że template < template < typename > typename T > stanie się poprawne – obecnie wymagane jest tam class: template < template < typename > class T > . |
|
Gibas11 |
» 2016-08-24 11:34:34 @up: A, to najwyraźniej źle zinterpretowałem wpis na wiki, mi tam to na rękę. :P Dzięki. |
|
efekt_motyla Temat założony przez niniejszego użytkownika |
» 2016-08-24 21:48:56 Dziękuję mam dwa pytania . 1) Skąd wpadłeś że można to tak zrobić.... kurcze myślałem nad tym długo i jedyne co mi przychodziło do głowy to tylko wyłapanie środka i dzielenie tego :). A po przeczytaniu " Można dużo prościej " od razu pomyślałem "Ciekawe kur... jak ;) ". 2) nie rozumiem jednego . Wzór który podałeś : powiedzmy ze mam 1 2 0 0 0 0 0 0 9 10 rozumiem ze wzór po kolei, na początku dla pierwszego napotkanego zera (u mnie tego po 2(dwójce :) ) to : b = 2 e = 9 z = 6 a n ???? 3) W pierwszym jak i zarówno w drugim kodzie w linijce : for( auto i = 0u; i + 1 < numbers.size(); i++ ) , wyskakuje mi błąd: error 'i' does not name type' expected';' before 'i' Kurcze dziękuję :) |
|
Gibas11 |
» 2016-08-24 22:00:33 1. Tak… po prostu. To tylko podzielenie różnicy na równe kroki i 'chodzenie' nimi po kolejnych zerach. 2. 1 2 0 n = 1, 2 + (7) / 7 * 1 = 3 0 n = 2 ... = 4 0 ... = 5 0 ... 0 0 9 10 Btw 'z' to chyba jednak ilość zer + 1. :P 3. Co do błędu „error 'i' does not name type” – włącz w kompilatorze standard c++11 albo zastąp auto tym: unsigned int etc. |
|
« 1 » 2 3 4 |