एक अंश के लिए द्विआधारी खोज

Nov 24 2020

मैं किताब के एल्गोरिदम से एक अभ्यास को हल करने की कोशिश कर रहा हूँ जो सेडग्विक से है जो निम्नानुसार है:

फॉर्म के प्रश्नों की लघुगणक संख्या का उपयोग करने वाली एक विधि को तैयार करें क्या संख्या x से कम है? एक परिमेय संख्या p / q ज्ञात करने के लिए ऐसा 0 <p <q <N. संकेत: एन से कम भाजक वाले दो अंश 1 / N ^ 2 से अधिक भिन्न नहीं हो सकते।

मुझे पता है कि जिस अंतराल में मुझे बाइनरी सर्च करना है] 0, 1 [लेकिन मुझे यकीन नहीं है कि मुझे क्या देखना चाहिए और क्या है। क्या कोई इसे मुझे समझा सकता है?

जवाब

btilly Nov 25 2020 at 16:48

संकेत की उपेक्षा, यहाँ एक बहुत कठिन समस्या का समाधान है।

अर्थात् खोजने के किसी भी , द्विआधारी खोज से तर्कसंगत एक लघुगणकीय अंश / भाजक का निरपेक्ष मान पर बाध्य के साथ, पहले से जानते हुए भी है कि कितना बड़ा बिना।

यह स्टर्न-ब्रोकोट पेड़ की एक द्विआधारी खोज है।

class GuessState:
    def __init__ (self):
        self.direction = None
        self.start = [0, 1]
        self.bound = [0, 0]
        self.multiple_upper = 1
        self.multiple_lower = 1
        self.is_widening = True
        self.is_choosing = None

    def next_guess (self):
        if self.is_widening:
            multiple = self.multiple_upper
        else:
            multiple = (self.multiple_lower + self.multiple_upper) // 2
        return (self.start[0] + multiple * self.bound[0], self.start[1] + multiple * self.bound[1])

    def add_response (self, response):
        next_level = False
        if self.direction is None:
            if 0 < response:
                self.bound[0] = 1
                self.direction = 1
            else:
                self.bound[0] = -1
                self.direction = -1
            self.is_choosing = True
            return
        elif self.is_choosing:
            if self.direction * response < 0:
                # Reverse direction.
                self.direction = - self.direction
                (self.start, self.bound) = (self.bound, self.start)
            self.multiple_upper = 2
            self.is_choosing = False
        elif self.is_widening:
            if 0 < response * self.direction:
                self.multiple_lower = self.multiple_upper
                self.multiple_upper += self.multiple_upper
            else:
                self.is_widening = False
                if self.multiple_lower + 1 == self.multiple_upper:
                    next_level = True
        elif self.multiple_lower + 1 < self.multiple_upper:
            if 0 < self.direction * response:
                self.multiple_lower = (self.multiple_lower + self.multiple_upper) // 2
            else:
                self.multiple_upper = (self.multiple_lower + self.multiple_upper) // 2
        else:
            next_level = True

        if next_level:
            next_start = (self.start[0] + self.multiple_lower * self.bound[0], self.start[1] + self.multiple_lower * self.bound[1])
            next_bound = (self.start[0] + self.multiple_upper * self.bound[0], self.start[1] + self.multiple_upper * self.bound[1])
            self.start = next_start
            self.bound = next_bound
            self.multiple_lower = 1
            self.multiple_upper = 1
            self.is_choosing = True
            self.is_widening = True

def guesser (answerer):
    state = GuessState()
    response = answerer(state.next_guess())
    while response != 0:
        state.add_response(response)
        response = answerer(state.next_guess())
    return state.next_guess()

def answerer (answer):
    def compare (guess):
        val = guess[0] / guess[1]
        print(f"Comparing answer {answer} to guess {val} ({guess[0]}/{guess[1]})")
        if val < answer:
            return 1
        elif answer < val:
            return -1
        else:
            return 0
    return compare

print(guesser(answerer(0.124356)))