Binäre Suche ohne ohne Istgleich

Gast #3470313
Lesenswert?
• ▲
▼
Hallo,
Ich zerbrech mir jetzt schon seit einer Stunde den Kopf über ein (denke 
ich) simples Problem:

Ich möchte aus dem Wertebereich 0x0 - 0xFF einen Wert suchen, aber die 
Funktion die ich zum Vergleichen benutze liefert mir nur True bei 
kleiner gleich und False bei größer.
Nun möchte ich natürlich mit möglichst wenig vergleichen zum Ziel kommen 
da die Vergleiche auf einem Embedded System (langsam) ablaufen.
Ich wollte die Binäre Suche Einsetzen, aber komm ums verrecken nicht auf 
eine Abbruchbedingung ohne einen Vergleich auf Gleichheit :(
Währe nett wenn mir da schnell jemand unter die Arme greifen könnte :)
Gast #3470340
Lesenswert?
• ▲
▼
Danke schon mal für die Antworten! :)
Aber ich habe gerade einen Fehler in meiner Beschreibung entdeckt.
Ich kann nur folgenden Vergleich durchführen versuchter Wert < gesuchter 
Wert
Das heißt ich kann nur folgendes feststellen:
versuchter Wert < gesuchter Wert und versuchter Wert >= gesuchter Wert

Damit scheiden leider die obigen Vorschläge aus :(
Gast #3470361
Lesenswert?
• ▲
▼
Tja eigentlich schon aber in diesem Fall macht den Vergleich ein 
externes Gerät auf das ich keinen Zugriff habe :(
Ich möchte Daten auslesen, weiß aber nicht wie lang sie sind. Der 
Auslesevorgang kann beliebig wiederholt werden. Ich kann mit einem 
Kommando n bytes auslesen, aber wenn ich zu mehr auslesen will als 
vorhanden ist kommt ein Fehler. Jetzt möchte ich auf dem schnellsten Weg 
wissen wieviele Datenbytes vorhanden sind :)
Gast #3470422
Lesenswert?
• ▲
▼
Danke an alle für die Hilfe, vor allem um die Zeit :)

Ich bin jetzt mit dieser Lösung zufrieden:
1
int left = 0;
2
int right = 0xFF;
3
int gesucht = (left + right)/2;
4
    
5
while(true)
6
{
7
    gesucht = (left + right)/2;
8
    if(isOutOfRange(gesucht)) // gesucht < versucht
9
    {
10
        right = gesucht;
11
    }
12
    else // x >= gesucht
13
    {
14
        left = gesucht;
15
    }
16
    if(left == right)
17
    {
18
        return gesucht;
19
    }
20
}

Ist stark vereinfacht, sollte aber verständlich sein falls jemand das 
gleiche Problem hat.
Gast #3470440
Lesenswert?
• ▲
▼
Aber der Ansatz oben war doch gut.
Nur das er eben nicht mit <= sondern mit < ausgeführt werden muss

(a==b) : !((b<a) || (a<b))

wobei ! die Negation sein soll.

Das ist wie in der boolschen Logik. Mit einer Verknüpfung und der 
Negation kannst Du alle anderen zusammensetzen.
Gast #3470459
Lesenswert?
• ▲
▼
@Logiker und M.H.
Das Problem bei diesen Ansätzen ist das ich die Werte für a und b nicht 
kenne. Mein Problem ist eher so: Ich stell mir eine Zahl vor zwischen 0 
und 255, du musst sie erraten, ich sag dir aber nur ob deine Zahl größer 
ist als die die ich mir denke.

Hab den Code noch ändern müssen, er hat unter bestimmten Umständen 
Endlosschleifen produziert.
1
int left = 0;
2
int right = 0xFF;
3
int gesucht = (left + right)/2;
4
    
5
while(true)
6
{
7
    gesucht = (left + right)/2;
8
    if(isOutOfRange(gesucht)) // gesucht < versucht
9
    {
10
        right = gesucht;
11
    }
12
    else // x >= gesucht
13
    {
14
        left = gesucht;
15
    }
16
    if((left + 1) == right)
17
    {
18
        return left;
19
    }
20
}
Gast #3470469
Lesenswert?
• ▲
▼
Es liegt nun mal in der Natur von Vergleichen, dass es drei 
Möglichkeiten ("<", "=" oder ">")gibt.

Willst Du also alle erfassen, so brauchst Du zwei Vergleiche.

Kannst Du zwei Möglichkeiten zusammenfassen ("<=" oder ">=") so reicht 
natürlich ein Vergleich.
Moderator #3470498
Lesenswert?
• ▲
▼
verzweifler schrieb:
> Hab den Code noch ändern müssen, er hat unter bestimmten Umständen
> Endlosschleifen produziert.

Du musst aber right mit 0x100 statt mit 0xFF initialisieren, sonst
funktioniert dein Code nicht für x=255.

Folgendes ginge ebenfalls, ist kürzer aber nicht ganz so flexibel wie
dein Code, da die mittlere Anzahl der benötigten Versuche nur dann
minimal ist, wenn die Größe des Suchraums eine Zweierpotenz ist:
1
  int gesucht=0, summand, versuch;
2

3
  for(summand = 128; summand; summand /= 2) {
4
    versuch = gesucht + summand;
5
    if(isInRange(versuch))
6
      gesucht = versuch;
7
  }
8
  return gesucht;
Gast #3470504
Lesenswert?
• ▲
▼
verzweifler schrieb:
> @Logiker und M.H.
> Das Problem bei diesen Ansätzen ist ...

Oh. Das habe ich überlesen,

Nun, Du scheinst ja eine Lösung zu haben. Aber etwas würde mich doch 
neugierhalber interessieren.

1. Wenn Du einen Wert unterhalb der gesuchten Länge versuchst, liefert 
die Gegenstelle einfach die Daten oder ist das ein gesonderter Befehl. 
(Deine Beschreibung hört sich nach ersterem an).
2. Sammeln sich in der Gegenstelle zu irgendwelchen Zeitpunkten immer 
mehr Daten an, oder löst Du das über einen dritten Befehl irgendwie aus?
3. Gibt es irgendwelche statistischen Auswertungen wieviele Daten über 
einen gewissen Zeitraum zur Verfügung stehen?

Ich meine es gäbe vielleicht effektivere Strategien. Aber wiegesagt, 
hauptsächlich bin ich neugierig.
#3472273
Lesenswert?
• ▲
▼
Entweder so, wie Reinhard das geschrieben hat, oder
1
  wenn nicht( ( v < g ) oder ( g < v ) )
2
    dann sind sie gleich
(in anderen Worten: wenn keiner kleiner als der andere ist, dann müssen 
sie gleich sein)

oder
1
  wenn (( v >= g ) und ( g >= v ) )
2
    dann sind sie gleich
(in anderen Worten: wenn sowohl v größer/gleich g ist, als auch g 
größer/gleich v, dann ist keiner tatsächlich größer, sondern beide sind 
gleich).

Mit den genannten Vergleichen gibt es immer eine Möglichkeit, wie man 
'sind gleich' ausdrücken kann. Gegebenenfalls muss man eben 2 Vergleiche 
machen und die beiden kombinieren, um daraus seine Schüsse zu ziehen.
Moderator #3472458
Lesenswert?
• ▲
▼
Karl Heinz schrieb:
> wenn nicht( ( v < g ) oder ( g < v ) )
>     dann sind sie gleich
> ...
> oder  wenn (( v >= g ) und ( g >= v ) )
>     dann sind sie gleich


Das Problem ist, dass man weder v<g noch v>=g hat. Im vorliegenden Fall
gibt es nur v<=g und die Negation davon, nämlich v>g (g ist dabei die
gesuchte Variable, auf die nicht direkt zugegriffen werden kann, und v
ist ein beliebiger Ausdruck). Siehe hier:

verzweifler schrieb:
> Ich möchte Daten auslesen, weiß aber nicht wie lang sie sind. Der
> Auslesevorgang kann beliebig wiederholt werden. Ich kann mit einem
> Kommando n bytes auslesen, aber wenn ich zu mehr auslesen will als
> vorhanden ist kommt ein Fehler.

Nach dem Muster von Reinhard kann man also die Gleichheit von v und g
mit v<=g && v+1>g feststellen, eine andere Möglichkeit gibt es nicht.

Dies wird in der vom verzweifler gefundenen Lösung implizit auch so
gemacht.

Wäre g übrigens keine ganze, sondern eine gebrochene Zahl mit unendlich
feiner oder unbekannter Auflösung, könnte man den nächstgrößeren
Nachfolger von v nicht bestimmen, so dass auch Reinhards Methode
versagt. Damit könnte in diesem Fall die Gleichheit mit den gegebenen
Operationen überhaupt nicht entschieden werden.
Moderator #3472564
Lesenswert?
• ▲
▼
Stefan schrieb:
> aber vllt. könnte eine Lösung sein den Algorithnus des successive
> approximation ADCs in dein Programm einzubauen.

Das ist im Prinzip genau das, was der verzweifler hier gemacht hat:

  Beitrag "Re: Binäre Suche ohne ohne Istgleich"

Etwas deutlicher wird die Analogie vielleicht, wenn man in diesem Code

  Beitrag "Re: Binäre Suche ohne ohne Istgleich"

die arithmetischen Operationen durch entsprechende Bit-Operationen
ersetzt und die Namen entsprechend der Anwendung im ADC ändert:
1
  int adcErgebnis=0, bit, dacWert;
2

3
  for(bit = 0x80; bit; bit >>= 1) {             // alle 8 Bits nacheinander durchgehen     
4
    dacWert = adcErgebnis | bit;                // Bit versuchsweise setzen
5
    if(messwertIstGroesserOderGleich(dacWert))  // Mess- mit DAC-Spannung vergleichen
6
      adcErgebnis = dacWert;                    // ggf. Bit ins Ergebnis übernehmen
7
  }
8
  return adcErgebnis;

Genau so wird der ADC auch in Hardware realisiert. Im DAC-Register
(dacWert) werden – getrieben durch das Taktsignal und beginnend mit dem
höchstwertigen Bit – nacheinander alle Bits versuchsweise gesetzt und
die zu messende Spannung durch einen Analogkomparator mit der
Ausgangsspannung des DAC verglichen (messwertIstGroesserOderGleich). Je
nach Ergebnis des Vergleichs wird der Wert mit gesetztem Bit übernommen
(adcErgebnis = dacWert) oder der alte Wert mit nicht gesetztem Bit
stehen gelassen.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren