Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

Interpolacja Liniowa

Ostatnio zmodyfikowano 2016-09-06 21:34
Autor Wiadomość
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 :)

C/C++
#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;
}
P-151037
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

C/C++
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
C/C++
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_liniowa


Powodzenia
P-151053
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 :) :

C/C++
#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ę





P-151057
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

C/C++
#include <iostream>
#include <fstream>
#include <vector>

int main()
{
    std::ifstream in( "liczby.txt" );
   
    /* double na wypadek nie-okrągłych wyników */
    std::vector < double > numbers;
   
    /* Wczytanie liczb */
    for( int i; in >> i; )
         numbers.push_back( i );
   
    /* Iteracja po wszystkich elementach vectora poza ostatnim */
    for( auto i = 0u; i + 1 < numbers.size(); i++ )
    {
        /* Jeśli następna liczba to zero */
        if( numbers[ i + 1 ] == 0 )
        {
            /* Zapisać pierwszą wartość przed zerem ('b') */
            double beginVal = numbers[ i ];
           
            /* Zapisać obecny indeks */
            auto index = i;
           
            /* Inkrementować 'i' aż trafimy na nie-zero */
            while( numbers[ ++i ] == 0 )
                 continue;
           
            /* Zapisanie pierwszej niezerowej wartości */
            double endVal = numbers[ i ];
           
            /* Różnica indeksów - ilość zer ('i') */
            double diff = i - index;
           
            /* Powrót na poczatek */
            i = index;
           
            /* Iteracja po wszystkich zerach */
            while( numbers[ ++i ] == 0 )
                 numbers[ i ] = beginVal +( endVal - beginVal ) / diff *( i - index ); //Wyjaśnione w poście
           
        }
    }
   
    /* Wypisanie wszystkich liczb */
    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:
C/C++
#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 )
P-151058
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 >
.
P-151059
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.
P-151062
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ę :)




P-151069
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.
P-151070
« 1 » 2 3 4
  Strona 1 z 4 Następna strona