简体   繁体   English

图灵机Euclid算法找到最大公约数python

[英]Turing Machine Euclid's Algorithm for finding greatest common divisor python

My code is at the bottom: (if someone has enough patience to read it all, I'll be really surprised) 我的代码位于底部:(如果某人有足够的耐心阅读所有内容,我会感到非常惊讶)

It outputs the incorrect number, but I don't know why. 输出的数字不正确,但是我不知道为什么。 I've followed the algorithm. 我已经遵循了算法。 The input have to be 2 unary numbers such as 2 and 6 => 01101111110. If there's a easier way to code this algorithm, pls tell me. 输入必须是2个一元数,例如2和6 =>01101111110。如果有更简单的方法来编码此算法,请告诉我。 Here is the algorithm ( from the book The Emperor's New Mind by Roger Penrose ) 这是算法(摘自Roger Penrose的《皇帝的新思维》一书)

在此处输入图片说明

And my code is: 我的代码是:

x = input("Dos numeros en sistema unario separado por un 0: ")
x = list(x)
pos = 0
valorMaq = 0
while (True):
    if valorMaq==0 and x[pos]=='0':
        valorMaq=0
        x[pos]='0'
        pos=pos+1
        print(x)

    elif valorMaq==0 and x[pos]=='1':
        valorMaq=11
        x[pos]='0'
        pos=pos-1
        print(x)

    elif valorMaq==1 and x[pos]=='0':
        valorMaq=10
        x[pos]='1'
        pos=pos+1
        print(x)

    elif valorMaq==1 and x[pos]=='1':
        valorMaq=1
        x[pos]='1'
        pos=pos-1
        print(x)
############################################
    elif valorMaq==10 and x[pos]=='0':
        valorMaq=1010
        x[pos]='0'
        pos=pos+1
        print(x)

    elif valorMaq==10 and x[pos]=='1':
        valorMaq=11
        x[pos]='0'
        pos=pos+1
        print(x)

    elif valorMaq==11 and x[pos]=='0':
        valorMaq=100
        x[pos]='0'
        pos=pos+1
        print(x)

    elif valorMaq==11 and x[pos]=='1':
        valorMaq=11
        x[pos]='1'
        pos=pos+1
        print(x)
#############################################
    elif valorMaq==100 and x[pos]=='0':
        valorMaq=100
        x[pos]='0'
        pos=pos+1
        print(x)

    elif valorMaq==100 and x[pos]=='1':
        valorMaq=101
        x[pos]='0'
        pos=pos+1
        print(x)

    elif valorMaq==101 and x[pos]=='0':
        valorMaq=111
        x[pos]='0'
        pos=pos-1
        print(x)

    elif valorMaq==101 and x[pos]=='1':
        valorMaq=110
        x[pos]='1'
        pos=pos-1
        print(x)

    elif valorMaq==110 and x[pos]=='0':
        valorMaq=110
        x[pos]='0'
        pos=pos-1
        print(x)

    elif valorMaq==110 and x[pos]=='1':
        valorMaq=1
        x[pos]='1'
        pos=pos-1
        print(x)

    elif valorMaq==111 and x[pos]=='0':
        valorMaq=111
        x[pos]='0'
        pos=pos-1
        print(x)

    elif valorMaq==111 and x[pos]=='1':
        valorMaq=1000
        x[pos]='1'
        pos=pos-1
        print(x)
################################################
    elif valorMaq==1000 and x[pos]=='0':
        valorMaq=1001
        x[pos]='0'
        pos=pos-1
        print(x)

    elif valorMaq==1000 and x[pos]=='1':
        valorMaq=1000
        x[pos]='1'
        pos=pos-1

    elif valorMaq==1001 and x[pos]=='0':
        valorMaq=10
        x[pos]='0'
        pos=pos+1
        print(x)

    elif valorMaq==1001 and x[pos]=='1':
        valorMaq=1
        x[pos]='1'
        pos=pos-1
        print(x)

    elif valorMaq==1010 and x[pos]=='1':
        valorMaq=1010
        x[pos]='1'
        pos=pos+1
        print(x)

    elif valorMaq==1010 and x[pos]=='0':
        valorMaq=0
        x[pos]='0'
        pos=pos+1
        break
        print(x)

x = ''.join(x)
print("Maximo comun divisor: ", x)

Despite what you wrote, I did look at every line of your code. 尽管您写了什么,但我确实查看了代码的每一行。

Your implementation of the second rule is incorrect. 您对第二条规则的实现不正确。 Penrose has 0 1 →1 1 L but you programmed 0 1 →11 0 L. So change your lines 12 through 16 to 彭罗斯(Penrose)具有0 1 →1 1 L,但您已将其编程为0 1 →11 0L 。因此,将第12至16行更改为

elif valorMaq==0 and x[pos]=='1':
    valorMaq=1
    x[pos]='1'
    pos=pos-1
    print(x)

That is the only wrong rule. 那是唯一错误的规则。 However, you left out an important idea of a Turing machine: it is potentially infinite and automatically adds blank cells to either end of the tape whenever the reading head moves off the currently-defined tape. 但是,您没有考虑图灵机的重要概念:它可能是无限的,并且每当读取头从当前定义的磁带移开时,都会自动将空白单元添加到磁带的任一端。 You could possibly implement that by adding more lines to each of your sections of code where pos is changed. 您可以通过在更改pos每个代码段中添加更多行来实现这一点。

However, I recommend instead that you make thorough changes to your code. 但是,我建议您对代码进行彻底的更改。 You make your code more difficult than it needs to be. 您使代码变得比原本需要的困难。 For one, you use tabs for indentation, but that is not a good idea in Python--use 4 spaces for each level of indent. 例如,您可以使用制表符进行缩进,但这在Python中并不是一个好主意-每个缩进级别都使用4个空格。

For another, you have much repetitious code, which violates the DRY ( Don't Repeat Yourself principle. Replace your algorithm with a data structure such as a dictionary to represent the rules, and write a small engine that uses the input and that structure to execute the Turing machine. For example, rules[(0, '0')] could be the tuple (0, '0', +1) to represent staying in state zero, writing a '0' character to the current position, and adding 1 to the current position (ie moving right one cell). The second production would have rules[(0, '1')] as (1, '1', -1) for state 1, character '1', and move left. The STOP action could be represented by something the machine can never move, such as None. Such code would be much easier to understand and to debug. 另外,您有很多重复的代码,这违反了DRY( 请勿重复自己的原理。用诸如字典等数据结构表示规则来替换算法,并编写一个使用输入和该结构的小型引擎来例如, rules[(0, '0')]可以是表示停留在零状态的元组(0, '0', +1) ,向当前位置写入一个'0'字符,并将1加到当前位置(即向右移动一个单元格),第二个产生式将状态1,字符“ 1”的rules[(0, '1')]设为(1, '1', -1) ,然后向左移动STOP动作可以用机器永远不会移动的东西来表示,例如None(无),这样的代码将更容易理解和调试。

Here is some code doing just that. 这是一些执行此操作的代码。 I also improved the printout to show the current state and location in the tape and removed your requirement that an extra '0' character be at both ends of the input. 我还改进了打印输出,以显示磁带中的当前状态和位置,并删除了您的要求,即输入的两端必须有一个额外的'0'字符。 I also made the code more flexible, extendable, and testable. 我还使代码更加灵活,可扩展和可测试。 I believe it is clear how to convert the rules as Penrose showed them to the format I use in the rules dictionary, though I used decimal numbers rather than Penrose's binary numbers for convenience and space. 我相信很清楚如何将规则转换为彭罗斯(Penrose)将其显示为规则字典中使用的格式,尽管为了方便和空间,我使用十进制数字而非彭罗斯(Penrose)的二进制数字。 There is no error checking in this code. 此代码中没有错误检查。 I tested this with pairs of numbers, each from 1 through 50, and it always gives the correct greatest common divisor in unary format. 我用成对的数字(每组从1到50)进行了测试,它始终以一进制格式给出正确的最大公约数。 Penrose's algorithm is quite clever--I never would have thought of this algorithm, which uses no extra characters. 彭罗斯(Penrose)的算法非常聪明-我从来没有想过这种算法,它不使用任何额外的字符。

"""Calculate the greatest common divisor of two unary numbers using
Penrose's algorithm for a Turing machine.

Suggested by <https://stackoverflow.com/questions/44467401/turing-
machine-euclids-algorithm-for-finding-greatest-common-divisor-python>
which itself uses Roger Penrose's *The Emperor's New Mind*, Oxford
University Press 1989 (paperback) p.41, the algorithm called EUC.

No error checking is done to the rules dictionary or the input line
that the correct format is followed.

Possible changes:
    1.  Enforce Penrose's requirement that the ending position is to
        the right of the answer (perhaps with blanks between the answer
        and the position).
        a.  Perhaps return ''.join(tape[:pos]).strip(BLANK) which
            removes anything at and right of the ending position.
        b.  Perhaps check that only blanks are at and right of the
            ending position.
"""

# Constants for magic numbers
BLANK = '0'  # blank character
STOP = None  # code to end the calcuation
STATEWIDTH = 3  # number of spaces to print current state in

# A rules dictionary, each entry in the format
#   (oldstate, currentcharacter): (newstate, newcharacter, move_or_stop)
EUC = {
    ( 0, '0'): ( 0, '0', +1),    ( 0, '1'): ( 1, '1', -1),  # state  0 =    0
    ( 1, '0'): ( 2, '1', +1),    ( 1, '1'): ( 1, '1', -1),  # state  1 =    1
    ( 2, '0'): (10, '0', +1),    ( 2, '1'): ( 3, '0', +1),  # state  2 =   10
    ( 3, '0'): ( 4, '0', +1),    ( 3, '1'): ( 3, '1', +1),  # state  3 =   11
    ( 4, '0'): ( 4, '0', +1),    ( 4, '1'): ( 5, '0', +1),  # state  4 =  100
    ( 5, '0'): ( 7, '0', -1),    ( 5, '1'): ( 6, '1', -1),  # state  5 =  101
    ( 6, '0'): ( 6, '0', -1),    ( 6, '1'): ( 1, '1', -1),  # state  6 =  110
    ( 7, '0'): ( 7, '0', -1),    ( 7, '1'): ( 8, '1', -1),  # state  7 =  111
    ( 8, '0'): ( 9, '0', -1),    ( 8, '1'): ( 8, '1', -1),  # state  8 = 1000
    ( 9, '0'): ( 2, '0', +1),    ( 9, '1'): ( 1, '1', -1),  # state  9 = 1001
    (10, '0'): ( 0, '0', STOP),  (10, '1'): (10, '1', +1),  # state 10 = 1010
}

def print_situation(state, tape, pos, printlines):
    if printlines:
        print(str(state).rjust(STATEWIDTH), ''.join(tape))
        print(''.rjust(STATEWIDTH), '^'.rjust(pos + 1))

def turing_machine(inputline, rules, printlines=True):
    tape = list(inputline)
    state = 0
    pos = 0
    print_situation(state, tape, pos, printlines)
    move = 1  # something other than STOP
    while move != STOP:
        # Do the next action
        state, tape[pos], move = rules[(state, tape[pos])]
        if move != STOP:
            pos += move
        else:
            pos += 1  # Penrose says all stops move right once
        # Add any needed blank characters to an end of the tape
        while pos < 0:
            tape.insert(0, BLANK)
            pos += 1  # pos is relative to left end of tape, so adjust both
        while pos >= len(tape):
            tape.append(BLANK)  # left end not changed so pos not adjusted
        # Print current situation
        print_situation(state, tape, pos, printlines)
    return ''.join(tape).strip(BLANK)

print(turing_machine(
        input("Enter two unary numbers separated by a '0': "), EUC))

When I enter the codes for 2 and 6, 110111111 , the returned result is 11 which is the unary code for 2, and the entire printout is: 当我输入2和6的代码时, 110111111 ,返回的结果是11 ,这是2的一元代码,整个打印输出是:

  0 110111111
    ^
  1 0110111111
    ^
  2 1110111111
     ^
  3 1010111111
      ^
  3 1010111111
       ^
  4 1010111111
        ^
  5 1010011111
         ^
  6 1010011111
        ^
  6 1010011111
       ^
  6 1010011111
      ^
  1 1010011111
     ^
  2 1110011111
      ^
  3 1100011111
       ^
  4 1100011111
        ^
  4 1100011111
         ^
  5 1100001111
          ^
  6 1100001111
         ^
  6 1100001111
        ^
  6 1100001111
       ^
  6 1100001111
      ^
  6 1100001111
     ^
  1 1100001111
    ^
  1 01100001111
    ^
  2 11100001111
     ^
  3 10100001111
      ^
  3 10100001111
       ^
  4 10100001111
        ^
  4 10100001111
         ^
  4 10100001111
          ^
  4 10100001111
           ^
  5 10100000111
            ^
  6 10100000111
           ^
  6 10100000111
          ^
  6 10100000111
         ^
  6 10100000111
        ^
  6 10100000111
       ^
  6 10100000111
      ^
  1 10100000111
     ^
  2 11100000111
      ^
  3 11000000111
       ^
  4 11000000111
        ^
  4 11000000111
         ^
  4 11000000111
          ^
  4 11000000111
           ^
  4 11000000111
            ^
  5 11000000011
             ^
  6 11000000011
            ^
  6 11000000011
           ^
  6 11000000011
          ^
  6 11000000011
         ^
  6 11000000011
        ^
  6 11000000011
       ^
  6 11000000011
      ^
  6 11000000011
     ^
  1 11000000011
    ^
  1 011000000011
    ^
  2 111000000011
     ^
  3 101000000011
      ^
  3 101000000011
       ^
  4 101000000011
        ^
  4 101000000011
         ^
  4 101000000011
          ^
  4 101000000011
           ^
  4 101000000011
            ^
  4 101000000011
             ^
  4 101000000011
              ^
  5 101000000001
               ^
  6 101000000001
              ^
  6 101000000001
             ^
  6 101000000001
            ^
  6 101000000001
           ^
  6 101000000001
          ^
  6 101000000001
         ^
  6 101000000001
        ^
  6 101000000001
       ^
  6 101000000001
      ^
  1 101000000001
     ^
  2 111000000001
      ^
  3 110000000001
       ^
  4 110000000001
        ^
  4 110000000001
         ^
  4 110000000001
          ^
  4 110000000001
           ^
  4 110000000001
            ^
  4 110000000001
             ^
  4 110000000001
              ^
  4 110000000001
               ^
  5 1100000000000
                ^
  7 1100000000000
               ^
  7 1100000000000
              ^
  7 1100000000000
             ^
  7 1100000000000
            ^
  7 1100000000000
           ^
  7 1100000000000
          ^
  7 1100000000000
         ^
  7 1100000000000
        ^
  7 1100000000000
       ^
  7 1100000000000
      ^
  7 1100000000000
     ^
  8 1100000000000
    ^
  8 01100000000000
    ^
  9 001100000000000
    ^
  2 001100000000000
     ^
 10 001100000000000
      ^
 10 001100000000000
       ^
 10 001100000000000
        ^
  0 001100000000000
         ^
11

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM