[Android] Błąd logiczny w programie


(Rdrfear) #1

Witam. Napisałem kod, który ma znależć wszystkie pary pięciocyfrowych liczb, których iloraz daje N - wprowadzane przez użytkownika. Musi obliczenia w tle wykonywać. Kod jest dosyć krótki, ale ciągle wywala mi błąd podczas wykonywania obliczeń - konretnie OOM (brak pamięci). Uważam, że popełniłem gdzieś błąd przy logice programu, a konkretnie w pętlach gdzie obliczam a * N = b i zapisuje parami a i b. Niestety po wielu zmianach w kodzie nadal nie udało mi się uzyskać wyników.

 

Kod:

package com.example.matematyka;

import java.util.ArrayList;
import java.util.concurrent.ExecutionException;

import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Pair;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import android.app.Activity;
import android.content.SharedPreferences;

public class MainActivity extends Activity {

    TextView edn;
    EditText ed;
    TextView txt;
    private SharedPreferences preferences;
    public static final String MY_PREFERENCES = "myPreferences";
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        edn = (TextView) findViewById(R.id.textView4);  
        ed = (EditText) findViewById(R.id.editText1);  
        txt = (TextView) findViewById(R.id.textView5);
        preferences = getSharedPreferences(MY_PREFERENCES, Activity.MODE_PRIVATE);
        fillUIFromPreferences();
    }
    
    private void fillUIFromPreferences()
    {
        int text1 = preferences.getInt("daneN", 0);
        String text2 = preferences.getString("wyniki", "");
        
        if(text1 == 0)
        {
            edn.setText("");
        } else {
            String text1_str = String.valueOf(text1);
            edn.setText(text1_str);
        }
        
        txt.setText(text2);
    }
    
    public void Oblicz(View v) throws InterruptedException, ExecutionException
    {
        String ed_text = ed.getText().toString().trim();
        Integer number;
        
        if(ed_text.isEmpty())
        {
            Toast.makeText(this, "Nie wpisałeś żadnej liczby.", Toast.LENGTH_SHORT).show();
        } else {
            number = Integer.parseInt(ed.getText().toString());
            edn.setText(ed_text);
            SharedPreferences.Editor preferencesEditor = preferences.edit();
            preferencesEditor.putInt("daneN", number);
            preferencesEditor.commit();
            new SideTask().execute(number);
        }
    }
    
    private class SideTask extends AsyncTask<Integer, Void, ArrayList<Pair<Integer, Integer>>>
    {        
        @Override
        protected ArrayList<Pair<Integer, Integer>> doInBackground(Integer...integers)
        {
            ArrayList<Pair<Integer, Integer>> array = new ArrayList<Pair<Integer, Integer>>();
            
            int a = 0, b = 0;
            
            for(int i = 10000; i <= 100000; i++)
            {
                a = i;
                b = a;
                while(b <= 100000)
                {
                    if(a == integers[0] * b)
                    {
                        array.add(Pair.create(b, a));
                    } else {
                        b++;
                    }
                }
            }
            return array;
        }
        
        @Override
        protected void onPostExecute(ArrayList<Pair<Integer, Integer>> array)
        {
            for(int i = 0; i < array.size(); i++)
            {
                Pair<Integer, Integer> a = array.get(i);
                txt.append(a.first + " " + a.second + "\n");
            }
            SharedPreferences.Editor preferencesEditor = preferences.edit();
            preferencesEditor.putString("wyniki", txt.toString());
            preferencesEditor.commit();
        }
    }
}

kod XML:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="26dp"
        android:layout_marginTop="21dp"
        android:text="@string/podaj"
        android:textAppearance="?android:attr/textAppearanceMedium" />

    <EditText
        android:id="@+id/editText1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/textView1"
        android:layout_alignBottom="@+id/textView1"
        android:layout_alignParentRight="true"
        android:ems="10"
        android:inputType="number" >
    </EditText>

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/editText1"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="49dp"
        android:text="@string/licz" 
        android:onClick="Oblicz"/>

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/button1"
        android:layout_marginTop="52dp"
        android:text="@string/ostatnie"
        android:textAppearance="?android:attr/textAppearanceMedium" />

    <TextView
        android:id="@+id/textView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/textView2"
        android:layout_marginTop="35dp"
        android:text="@string/rezultat"
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <TextView
        android:id="@+id/textView5"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_below="@+id/textView3"
        android:text="" />

    <TextView
        android:id="@+id/textView4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/textView2"
        android:layout_alignParentRight="true"
        android:layout_alignTop="@+id/textView2"
        android:layout_toRightOf="@+id/textView2" />

</RelativeLayout>

Czy jest ktoś w stanie mi pomóc? Dziękuję.


(Grzelix) #2
while(b <= 100000)
                {
                    if(a == integers[0] * b)
                    {
                        array.add(Pair.create(b, a));
                    } else {
                        b++;
                    }
                }

 

Powyżej jest błąd:

 

Przykład: 

Pierwsza iteracja a == integres[0] *b nie jest spełniony -> b++ = b1 

Druga iteracja a == integres[0] *b1 jest spełniony -> tworzymy parę a, b1 i przechodzimy do następnej iteracji

Trzecia iteracja a == integres[0] *b1 jest spełniony -> tworzymy parę a, b1 i przechodzimy do następnej iteracji

 

w drugiej i trzeciej iteracji wartość zmiennej b się nie zmieniła więc mamy tutaj nie skończone zapętlenie z tworzeniem nowych par które w końcu wykańczają pamięć.

 

Poniżej moja propozycja do rozważenia.

=================================================

 

Moja propozycja rozwiązania:

Najpierw analiza matematyczna.

  1. Szukamy par liczb pięciocyfrowych których iloraz daje N - zdefiniowany przez użytkownika.

Max liczba 5-cyfrowa - 99 999

Min liczba 5-cyfrowa - 10 000

===================

max liczba N = 9 (liczba całkowita)

for(int i = 1; i < 10; i++){
    int a = 10000; 
    while(i*a < 100000){
        if(i*a == N){
            array.add(Pair.create(i*a, a));
        }
        a++;
    }
}

 


(Rdrfear) #3

Czy to w ogóle możliwe aby warunek w ifie w metodzie, którą podałeś został spełniony choćby raz? Przecież i*a da nam 10000-99999, ale N to jest 1-9. Nie wiem czy ja źle myślę, czy brakuje tu czegoś w ifie.


(Grzelix) #4

Sorry za dużo pomysłów naraz miałem w głowie:

protected ArrayList<Pair<Integer, Integer>> doInBackground(Integer...integers)
        {
            ArrayList<Pair<Integer, Integer>> array = new ArrayList<Pair<Integer, Integer>>();
            int N = integer[0]; //zakładam, że tu jest wejściowe N
            if(N > 9){ //jeśli N jest większe od 9 to nie znajdziemy żadnej pary spełniajacej zadane warunki
                return array;
            }
            int a = 10000;
            while (a*N<100000){
                array.add(Pair.create(a*N, a);
            }
            return array;
        }

Teraz powinno być tak jak chciałem.

 

To jest końcowy "produkcyjny" kod, z dwóch powodów - pisane z palce, i nie pisze na codzień w tym języku. Starałem się tylko pokazać bardziej optymalne podejście.


(Rdrfear) #5

Niestety, teraz metoda, którą podałeś, da mi jedynie jedną parę.

 

Tutaj kod, który ja stworzyłem na podstawie Twoich kodów. Dzięki za pomysły, bo bez nich chyba nie dałbym rady tego zrobić.

protected ArrayList<Pair<Integer, Integer>> doInBackground(Integer...integers)
{
    		ArrayList<Pair<Integer, Integer>> array = new ArrayList<Pair<Integer, Integer>>();
    		int N = integers[0];
    		for(int a = 10000; a < 100000; a++)
                {
            	      if(a*N < 100000)
            	      {
            		    array.add(Pair.create(a*N, a));
            	      }
                }
    		return array;
}

(Grzelix) #6

dziwne wygląda w porządku.

 

Jeśli N = 9 to:

10 000 * 9 = 90 000 < 100 000 => para (90 000, 10 000)

10 001 * 9 = 90 009 < 100 000 => para (90 009, 10 001)

...

11 111* 9 = 99 999 < 100 000 => para (99 999, 11 111)

 

a więc dla N = 9 jest 1 112 par,

 

Może błąd przy odczycie tej listy.

 

BTW z powyższej analizy widać uproszczenie:

protected ArrayList<Pair<Integer, Integer>> doInBackground(Integer...integers)
{
    		ArrayList<Pair<Integer, Integer>> array = new ArrayList<Pair<Integer, Inteer>>();
    		int N = integers[0];
    		for(int a = 10000; a*N < 100000; a++)
                {
            	      array.add(Pair.create(a*N, a));
            	}
    		return array;
}

(Rdrfear) #7

Dzięki bardzo, działa elegancko!