编程实现图灵机XN*2(C语言实现)

一、题目分析

所谓的图灵机就是指一个抽象的机器,它有一条无限长的纸带,纸带分成了一个一个的小方格,每个方格有不同的颜色。有一个机器头在纸带上移来移去。机器头有一组内部状态,还有一些固定的程序。在每个时刻,机器头都要从当前纸带上读入一个方格信息,然后结合自己的内部状态查找程序表,根据程序输出信息到纸带方格上,并转换自己的内部状态,然后进行移动。

通过编程的方式模拟实现图灵机的运行过程,我们需要先对图灵机的操作步骤进行抽象概括。在本次实验中我将通过C语言编程的方式模拟图灵机(XN*2)的运行过程实现求某个整数的倍数运算。

分析:

根据图灵机(XN*2)的运行过程,可将其操作步骤概括为以下五点:

  1. 将输入的十进制数转换成二进制
  2. 将二进制数转换成计算机能够直接识别的扩展二进制数
  3. 根据指令实现对扩展二进制数按指令操作
  4. 因为操作结果仍为扩展二进制数,则需要将其收缩为普通二进制数
  5. 将收缩完成的二进制数转化为十进制数输出

结论:

可以根据这五个步骤设计五个函数,通过main()函数依次调用它们,从而实现对图灵机的编程模拟。

二、算法构造

● 设计transform()函数实现将输入的十进制数转换为二进制

● 设计extend()函数实现扩展二进制

● 设计realize()函数实现对扩展二进制的按指令操作

● 设计shrink()函数实现将扩展二进制收缩为普通二进制

● 设计reverse()函数实现将二进制转换为十进制

已知图灵机(XN*2)的指令如下:

0 0  → 0 0 R,

0 1  → 1 0 R,

1 0  → 0 1 R,

10 0 → 11 1 R,

11 0 → 0 1 STOP。

这五条指令是设计realize()函数的理论依据。

三、算法实现(源代码)

#include <stdio.h>
#include <math.h>

int size1 = 0;    // size1存储二进制数的长度
int size2 = 0;    // size2存储扩展二进制的长度
int size3 = 0;    // size3存储按指令操作后的二进制长度
int size4 = 0;    // size4存储收缩二进制的长度

// 通过transform()函数实现十进制转二进制 
int* transform(int x)
{
	int rem;    // 存储x对2取余后的余数
	int i = 0, j = 0;
	int r;
	int a[100];    // 数组a[]倒序存储十进制转换后的二进制
	static int b[100];    // 数组b[]正序存储十进制转换后的二进制

	while(x!=0)    // 十进制转二进制
	{
		rem = x%2;
		a[i] = rem;
		i++;
		x/=2;
	}

	for(r=i-1; r>=0; r--)    // 通过for循环将二进制数正序存入数组b[]中
	{
		b[j] = a[r];
		j++;
	}

	size1 = j;

	return b;
	
}

// 通过extend()函数实现二进制的扩展 
int* extend(int p[])
{
	int i = 0, j, k;
	static int c[100];    // 数组c[]存储扩展二进制

	c[i] = 0;    // 数组首位存入0
	i++;

	for(j=0; j<size1; j++)
	{
		k = p[j];

		if(k==0)    // 若从二进制数组中扫描到0,则将一个0存入扩展二进制数组c[]中
		{
			c[i] = 0;
			i++;
		}
		else if(k==1)    // 若从二进制数组中扫描到1,则将一个1、一个0依次存入扩展二进制数组c[]中
		{
			c[i] = 1;   
			i++;
			c[i] = 0;
			i++;
		}
	}

	c[i] = 1;
	i++;
	c[i] = 1;
	i++;
	c[i] = 0;

	size2 = i+1;

	return c;
}

// 通过realize()函数实现对扩展二进制的按指令操作
int* realize(int q[])
{
	int i, j = 0, k = 0;
	int inner = 0;    // inner为内态
	
	for(i=0; i<size2+2; i++)
	{
		k = q[i];
		
		if(k==0 && inner==0)    // 输入为0,内态为0
		{
			q[i] = 0;
			inner = 0;
		}
		else if(k==0 && inner==1)    // 输入为0,内态为1
		{
			q[i] = 1;
			inner = 0;
		}
		else if(k==0 && inner==10)    // 输入为0,内态为10
		{
			q[i] = 1;
			inner = 11;			
		}
		else if(k==0 && inner==11)    // 输入为0,内态为11
		{
			q[i] = 1;
			inner = 0;	
		}
		else if(k==1 && inner==0)    // 输入为1,内态为0
		{
			q[i] = 0;
			inner = 1;
		}
		else if(k==1 && inner==1)    // 输入为1,内态为1
		{
			q[i] = 0;
			inner = 10;
		}
		else if(k==1 && inner==10)    // 输入为1,内态为10
		{
			q[i] = 0;
			inner = 0;
		}
	}

	size3 = i;
	printf("%d", size3);

	return q;
}

// 通过shrink()函数实现对操作结果的收缩
int* shrink(int r[])
{
	int i, j = 0;
	static int d[100];

	for(i=1; i<size3-3; i++)
	{
		if(r[i]==0 && r[i+1]==0 )
		{
			d[j] = 0;
			j++;
			continue;
		}
		if(r[i]==0 && r[i+1]==1 && r[i+2]==0)
		{
			d[j] = 1;
			j++;
			continue;
		}
	}

	size4 = j;

	return d;
}

// 通过reverse()函数实现二进制转十进制
int reverse(int s[])
{
	int sum = 0;
	int i;

	for(i=0; i<size4; i++)
	{
		sum += s[i] * (int)pow(2,(size4-1-i));
	}

	return sum;
}

void main()
{
	int x;    // 存放用户键入的整数
	int i = 0;
	printf("请输入一个十进制整数:\n");
	scanf("%d", &x);
	
	int*p;
	p = transform(x);
	printf("十进制数转换成二进制数为:\n");
	for(i=0; i<size1; i++)
		printf("%d", p[i]);
	printf("\n");


	int*q;
	q = extend(p);
	printf("扩展二进制数为:\n");
	for(i=0; i<size2; i++)
		printf("%d", q[i]);
	printf("\n");

	int*r;
	r = realize(q);
	printf("指令执行结束生成的二进制数:\n");
	for(i=0; i<size3; i++)
		printf("%d", r[i]);
	printf("\n");

	int*s;
	s = shrink(r);
	printf("图灵机计算结果的二进制数:\n");
	for(i=0; i<size4; i++)
		printf("%d", s[i]);
	printf("\n");

	int y;
	y = reverse(s);
	printf("图灵机计算结果的十进制数:\n");
	printf("%d", y);
	printf("\n");
}


四、调试、测试及运行结果

测试结果:

输入3,输出8

经调试找出错误原因,错将extend()函数中数组[ ]中的i++写成++i导致程序运行出错。

运行结果:

输入9, 输出18

输入43, 输出86

五、总结

与之前几次作业相比本次实验应该是我写起来最费力的一次了。因为我是通过C语言编程来模拟实现图灵机(XN*2)求解输入值的倍数问题,所以有一些函数不能通过直接调用,而是需要自定义,这对于算法底子不牢的我来说真的是很困难了。就比如说对扩展二进制进行收缩操作,C++中就可以通过调用库函数来实现而C语言就不行,最终我还是通过查阅资料自定义了收缩函数解决了问题。实验中还有一些因为粗心犯下的错误,就比如我把i++写成了++i导致程序出错等等。虽然完成这次实验的过程很是艰难但我还是从中学到了很多,就比如这次实验需要通过定义许多数组来实现一些功能,使我巩固了数组的用法。ps:由于自身能力原因,代码实现的过程中可能会出现一些错误,希望大家能够批评指正,不吝赐教。

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值