OpenGL编程实习报告

OpenGL编程实习报告

班    级:

      学    号:

姓    名:

        专    业:摄影测量与遥感

指导老师:

实习目的:

1、  了解OPENGL绘图原理;熟悉OPENGL的编程步骤;掌握在OPENGL中绘图。

2、 实现在VC++6.0环境下在OPENGL中绘图,绘制一个圆形或正方形;实现这个三维  物体的变换。

实习原理:

OpenGL的基本工作流程为:

OpenGL程序的基本结构为定义窗口、清理窗口、绘制物体、结束运行。其基本操作有:描述图元、绘制图元、OpenGL变换。

在Windows下用GDI作图必须通过设备上下文(DeviceContext简写DC)调用相应的函数;用OpenGL作图也是类似,OpenGL函数是通过"渲染上下文"(RenderingContext简写RC)完成三维图形的绘制。Windows下的窗口和设备上下文支持"位图格式"(PIXELFORMAT)属性,和RC有着位图结构上的一致。只要在创建RC时与一个DC建立联系(RC也只能通过已经建立了位图格式的DC来创建),OpenGL的函数就可以通过RC对应的DC画到相应的显示设备上。

实习步骤:

1、 首先创建工程。用AppWizard产生一个MFC单文档(SDI)的EXE文件。选中三维控制(3D Controls),其余保持默认值即可。

2、 将此工程所需的OpenGL文件 和库加入到工程中。在工程菜单中,选择"Build"下的"Settings"项。单击"Link"标签,选择"General"目录,在Object/Library Modules的编辑框中输入"OpenGL32.lib glu32.lib glaux.lib",选择"OK"结束。然后打开文件"stdafx.h",将语句#include <gl\gl.h>和#include <gl\glu.h>插入到文件中。

3、 设置显示设备DC的位图格式(PIXELFORMAT)属性。通过填充一个PIXELFORMATDESCRIPTOR的结构来完成(关于PIXELFORMATDESCRIPTOR 中各项数据的意义,请参照VC的帮助信息),该结构决定了OpenGL作图的物理设备的属性,比如该结构中的数据项dwFlags中PFD_DOUBLEBUFFER位如果没有设置(置1),通过该设备的DC上作图的OpenGL命令就不可能使用双缓冲来做动画。有一些位图格式(PIXELFORMAT)是DC支持的,而有一些DC就不支持了。所以程序必须先用ChoosePixelFormat来选择DC所支持的与指定位图格式最接近的位图格式,然后用SetPixelFormat设置DC的位图格式。

4、 利用刚才的设备DC建立渲染上下文RC(wglCreateContext),使得RC与DC建立联系(wglMakeCurrent)。

5、 调用OpenGL函数作图。

(1)定义一个窗口:

     auxInitDisplayMode(AUX_SINGLE|AUX_RGBA);

     auxInitPosition(0,0,500,400);

     auxInitWindow("Create Your Own Program");

(2)清理窗口:

     glClearColor(0.0,0.0,0.0,0.0);

     glClearDepth(0.0);

     glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

(3)绘制物体:(包括和构造几何图元)

定义顶点:在OpenGL中,所有的几何物体最终都由有一定顺序的顶点集来描述。

在实际应用中,通常用一组相关的顶点序列以一定的方式组织起来定义某个几何图元,而不采用单独定义多个顶点来构造几何图元。

允许在glBegin()与glEnd()之间调用的OpenGL命令为:

glVertex*();

glColor*();

glIndex();

glNormal();

glEvalCoord*();

glCallList(),glCallLists();

glTexCoord();

glEdgeFlag();

glMaterial();

设置图元的颜色、大小、线段、线型、多边形的绘制和填充

    (4)设置变换方式。有几何变换、正射投影等。

        (5)结束运行。

 6、作图完毕以后,先通过置当前线程的RC为NULL(::wglMakeCurrent(NULL, N ULL);),断开当前线程和该渲染上下文的联系,由此断开与DC的联系。在后面删除RC的时候要先判断以下RC句柄的有效性(if(m_hrc)::wglDeleteContext(m_hrc);)。再根据情况释放(ReleaseDC)或者删除(DeleteDC)DC。

实习小结:

     通过本次实习使我更好的了解了OPENGL的原理,也提高了我的VC编程能力,学到了不少东西。同时也让我初步的知道如何利用OPENGL来进行绘图。得到不少收获。

 

第二篇:算法与编程实习报告

算法与编程实习报告

指导老师:XXX

                专业:通信工程

                班级:10083415

                学号:XXXXXXXX

                姓名:   XX

第一题

一、问题描述

一、题目:统计字母的使用频率

二、目的与要求

1.目的:

通过编写程序统计字母的使用频率,培养学生综合利用C语言进行程序设计的能力,熟悉字符串的操作方法,加强函数的运用,提高软件系统分析能力和程序文档建立、归纳总结的能力。

2.基本要求:

1)要求用C语言编程,在Visual C++环境下调试完成;

2)要求按照程序功能分成几个功能模块来实现,各个功能模块分别使用函数来完成;

3)要求应用本课所讲授的程序设计语言知识来解决问题

三、设计方法和基本原理

1.课题功能描述

本程序的功能,就是要统计英文字母的使用频率。

2.问题详细描述

为统计英文字母的使用频率,输入一个不包括空格的由英文字母组成的字符串,长度不超过200个字符。统计26个英文字母的使用频率,不区分大小写。最后按使用频率从大到小输出字母(小写字母)和使用频率(出现的次数)。

3.问题的解决方案

按照程序要求,本程序应采用模块化设计方法,设计几个功能模块。例如(仅供参考):

1) 将字符串中的大写字母转换为小写字母

2) 统计输入的字符串中字母的使用频率

3) 按使用频率从大到小进行排序

4) 主函数中控制输入、函数调用和输出。

四、主要技术问题的描述

根据三的分析,主要问题在于:

1) 为统计字母的使用频率,定义一个长度为26的int数组存放所统计的各个字母的使用频率。

2) 在统计字母的使用频率时,不要使用if语句或switch语句,利用字母的ASCII码与数组元素下标之间的关系来求得。

3) 按使用频率从大到小进行排序时,建议使用指针数组更为方便。

五、创新要求

实现程序功能后,可进行创新设计:

1) 使用多文件,即主函数和各个函数分别存放在不同的.c文件中,在头文件中进行函数原型声明。

2) 读入一篇英文文档,并对其进行字母频率分析。

二、功能描述

一、利用MFC实现友好界面,设计了两个功能按钮,“打开文件”和“计算”

二、对文档的读入有两种方案,一是直接在界面上直接输入,二是利用“打开文件”按钮,打开一个存放于D盘根目录的data.txt文本文件。

三、把读取来的英文数据都在显示框内显示。

四、当用户按下“计算”按钮时,程序读取显示框内的数据,用于计算。

五、将计算得到的结果在结果输出框内显示,并写入D盘的result.txt文本文件。

(下页流程图)

三、解决方案(流程图)

算法与编程实习报告                                                                               

四、主要函数描述

1)  OnButtonCalc()             按钮处理函数“计算”,用于控制数据的输入与输出

2)  OnButtonFopen()           按钮处理函数“打开文件”,用于打开文件操作

3)  result_display()                     结果显示函数

   

4)  freq_sort()                 结果排序,并写入文件

5)  freq_calc()                 计算字母出现频率

6)  num_change                字母大小写转换

五、主要技术问题

一、对字符串的操作和问件的操作。

二、指针的运用,函数的调用。

六、结论(实验心得)

一、函数必须加上必要的注释,不然要记起当时的思路很难。

附录:第一题部分源程序

/*****************************按钮处理函数“计算”*****************************/

void CTask_oneDlg::OnButtonCalc()   

{

       // TODO: Add your control notification handler code here

       UpdateData(TRUE);                //  把当前文本框中的内容保存到变量中

    char en_in[N];

       char en_out[250]={0};

       int res[26]={0};

       strcpy(en_in,m_input);                //  读取EDIT中的值,存入字符数组

      

       data_input(en_in,res);                //  输入数据处理函数

       result_display(en_out);               //  结果显示

       m_display=en_out;                     //  变量传入控件

      

       UpdateData(FALSE);

}

/**************************按钮处理函数“打开文件”***************************/

void CTask_oneDlg::OnButtonFopen()

{

       // TODO: Add your control notification handler code here

       UpdateData(TRUE);                    //  把当前文本框中的内容保存到变量中

       char en_in[N];                           //  定义字符数组用于存放输入数据

       char en_out[250]={0};                              //  定义字符数组用于存放结果,写入文件

       int res[26]={0};                           //  26个字母的数组用于频率值

       FILE *fp_r;

       if((fp_r=fopen("d:\\data.txt","r"))==NULL)      //  打开D盘根目录的data.txt文件

       {

              MessageBox(TEXT("在D:\\中找不到文件data.txt!"),TEXT("错误"),MB_OK);

       }

       else

       {

              fscanf(fp_r,"%s",en_in);                //  文件的值读取到数组中

              fclose(fp_r);  

              m_input=en_in;                       //  把读入的数据在界面上显示(原数据)

       }

       UpdateData(FALSE);    

}

/***************************字母大小写变换******************************/

void num_change(char *en)  

{

    int i=0;

       for(i=0;*(en+i)!='\0';i++)   // 三目运算符 当字在AZ之间时,转化为小写

       {

              *(en+i)=('A'<=*(en+i)&&*(en+i)<='Z')?(*(en+i)+32):(*(en+i));

       }

}

/**************************计算字母出现频率****************************/

void freq_calc(char *en,int *res)

{

       int i=0;

       for(i=0;*(en+i)!='\0';i++)

       {

              (*(res+(int)(*(en+i))-97))++;  //  字符与结果数组相对应 自加一次

       }

}

/*************************结果显示,并写入文件**************************/

void result_display(char *en_out)       

{

       FILE *fp;                            //  存入D盘根目录的result.txt文件中

       if((fp=fopen("d:\\result.txt","r"))==NULL)

       {

              exit(1);

       }

       fscanf(fp,"%s",en_out);              //  读取并在界面上显示(处理后的数据)

       fclose(fp);

}

第二题

一、问题描述

一、题目:自然数的进制转换

二、目的与要求

1.  目的:

通过编写对自然数进行不同进制转换程序,培养学生综合利用C语言进行程序设计的能力,熟悉字符串的操作方法,加强函数的运用,提高软件系统分析能力和程序文档建立、归纳总结的能力。

2.  基本要求:

1)要求用C语言编程,在Visual C++环境下调试完成;

2)要求按照程序功能分成几个功能模块来实现,各个功能模块分别使用函数来完成;

3)要求应用本课所讲授的程序设计语言知识来解决问题.

三、设计方法和基本原理

1.课题功能描述

本程序的功能,就是实现自然数的十进制、二进制、八进制、十六进制转换。即根据用户选择的进制和输入的数据,转换得到该数所对应的十进制、二进制、八进制和十六进制数。

2.问题详细描述

程序运行时,首先由用户选择输入数据所使用的进制,如:

欢迎使用进制转换程序!

        1. 十进制

        2. 二进制

        3. 八进制

        4. 十六进制

        0. 退出

请选择输入数据的进制:

用户选择后,再输入数据,如选择3(八进制),则显示:

请输入八进制数据:

输入数据后,程序进行转换,最后输出该数所对应的十进制、二进制、八进制和十六进制数。如输出:

转换结果:

        十进制  21809

        二进制  101010100110001

        八进制  52461

        十六进制  5531

3.问题的解决方案

实际上,C语言在输入输出时可直接输入或输出各种进制的数,本题目是为了提高学生的编程能力,所以要自己编程来实现数制的转换。根据问题的描述,使用字符数组来存放输入的数据,转换后的数据也存放到字符数组中,按字符串进行输入和输出。

注意:问题的解决方案有很多,下面给出的仅供同学们参考。

按照程序要求,每次要将数据转换成各种进制,因此将输入数据(字符数组中)先转换成十进制数(long),再将其转换成各种进制并存入相应的字符数组中,最后输出。

本程序应采用模块化设计方法,设计几个功能模块。例如(仅供参考):

1) 检验输入数是否合法(例八进制数中只能出现0~7)

2) 将数据(字符数组中)转换成十进制数(long)

3) 将十进制数(long)转换成某种进制数据(字符数组中)

还可以把这几个模块中都使用的字符与数字之间的转换作为独立模块,供上面的模块调用。例如(仅供参考):

4) 字符转数字

5) 数字转字符

主函数中控制输入、函数调用和输出。

四、主要技术问题的描述

根据三的分析,主要问题在于:

1) 单个字符与数字的转换

在字符转数字时,’0’~’9’只需减去’0’即可,要考虑到’a’~’f’和’A’~’F’的转换(十六进制数)。同样的,数字转字符时,要考虑到10~15的转换与0~9不同。

2) 将数据(字符数组中)转换成十进制数(long)时,采用的算法是:按当前数制的位权进行多项式展开相加,即得到对应的十进制数。

3) 将十进制数(long)转换成某种进制数据(字符数组中)时,采用除留余数法:将十进制数除以转换进制的位权,保留余数(存到字符数组中),商继续除,直到商为零;然后将字符数组中的内容求头逆序,即得到转换数据。其中求逆序也可用一个独立模块来实现。

五、创新要求

实现程序功能后,可进行创新设计:

1) 使用多文件,即主函数和各个函数分别存放在不同的.c文件中,在头文件中进行函数原型声明;

2) 本程序实现的是自然数的不同进制的转换,可进一步实现带小数的转换;

3) 实现负数的转换

二、功能描述

一、利用MFC实现友好界面,设计了两个功能按钮,“转换”和“退出”。

二、设计了一个Combox用来选择当前输入数据的进制。

三、一个Edit框用于存放输入数据。

四、其余Edit框用于显示。

(下页流程图)

三、解决方案(流程图)

算法与编程实习报告

                                                                   

四、主要函数描述

1)  OnButtonChange()           “转换”按钮处理函数

2)  Change_dec()                 按类别把输入的数据转换为十进制存入value中

3)  dec_to_string()   dec_to_bin()  dec_to_oct()  dec_to_hex

                                                        十进制转化为各种进制

4)  OnButtonExit()               “退出”按钮处理函数

一、主要技术问题

一、Combox控件的运用,Combox选取值的读取。

二、按读进来的进制类型,统一转换为十进制。

三、字符串转数字,数字转字符串。

二、结论(实验心得)

一、合理利用MFC可以使程序简洁又友好。

附录:第二题部分源程序

/**************************Combox初始化******************************/

    m_kind.InsertString(0,"十进制");

    m_kind.InsertString(1,"二进制");

    m_kind.InsertString(2,"八进制");

    m_kind.InsertString(3,"十六进制");

m_kind.SetCurSel(0);                         //  默认显示十进制

/************************“转换”按钮处理函数************************/

void CTask_twoDlg::OnButtonChange()    

{

    // TODO: Add your control notification handler code here

    int kind=0;              //  输入数据的类别

    char s_dat[30]={0};       //  用于存放输入的数据

    long value=0;             //  十进制存储位置 把读到数据统一转换为十进制再处理

    kind=m_kind.GetCurSel();   //  读取combox的值,得到选中的类别

    UpdateData(TRUE);         //  把当前文本框中的内容保存到变量中

                                    

    strcpy(s_dat,m_data);     //  把文本框的内容拷贝到字符数组里

    Change_dec(s_dat,kind,&value);  //  调用数据处理函数 把读到数据统一转换为十进制

/*******************************显示函数*******************************/

    dec_to_string(s_dat,&value);    //  十进制输出

    m_dec=s_dat;                                    //  把变量的值传控件中显示

    UpdateData(FALSE);              

                                    

    dec_to_bin(s_dat,&value);       //  二进制输出

    m_bin=s_dat;

    UpdateData(FALSE);

    dec_to_oct(s_dat,&value);       //  八进制输出

    m_oct=s_dat;

    UpdateData(FALSE);

    dec_to_hex(s_dat,&value);    //  十六进制输出

    m_hex=s_dat;

    UpdateData(FALSE);

}

/***************************************************************************/

void Change_dec(char *dat,int kind,long *value)  // 把输入的数据转换为十进制存入value中

{

    int i=0;

    kind=kind+1;              //  Combox 中类别从0开始

    switch(kind)              //  按类别把输入的数据转换为十进制存入value中

    {

        case 1:                                         //  十进制

            while(*(dat+i)>='0'&&*(dat+i)<='9')                

            {

                *value=(*value)*10+(*(dat+i)-'0');   

                i++;

            }

            break;

        case 2:                                         //  二进制

            while(*(dat+i)>='0'&&*(dat+i)<='1')

            {

                *value=(*value)*2+(*(dat+i)-'0'); 

                i++;

            }

            break;

        case 3:                                        //  八进制

            while(*(dat+i)>='0'&&*(dat+i)<='7')

            {

                *value=(*value)*8+(*(dat+i)-'0');   

                i++;

            }

            break;      

        case 4:                                         //  十六进制

            while(*(dat+i)>='0'&&*(dat+i)<='F')

            {

                 if((*dat)>'9')             // 十六进制时当数据大于9,单独处理

                 {

                     *value=(*value)*16+(*(dat+i)-'7');     //  把大写的A转化为10

                 }

                 else

                 {

                                     *value=(*value)*16+(*(dat+i)-'0');

                 }

                 i++;

             }

             break;         

    }

}

/*****************************十进制转十六进制***********************/

void dec_to_hex(char *dat,long *vp)    

{

       int i=0,j=0;

       char num=0;

       long temp=*vp;

       memset(dat,0,30);                              //  清空字符串

       while(temp)

       {

              if((temp%16)>9)

              {

                     *(dat+i)=temp%16+'7';       //  余数大于9时处理 10-15 to A-F

              }

              else

              {

                     *(dat+i)=temp%16+'0';    

              }

              temp=temp/16;

              i++;

       }    

       for(j=0;j

       {

              num=*(dat+j);

              *(dat+j)=*(dat+i-1-j);

              *(dat+i-1-j)=num;

       }

}

第三题

一、问题描述

一、题目:四则运算

二、目的与要求

1.目的:

通过编写四则运算程序,培养学生综合利用C语言进行程序设计的能力,熟悉字符串的操作方法,加强函数的运用,提高软件系统分析能力和程序文档建立、归纳总结的能力。

2.基本要求:

1)要求用C语言编程,在Visual C++环境下调试完成;

2)要求按照程序功能分成几个功能模块来实现,各个功能模块分别使用函数来完成;

3)要求应用本课所讲授的程序设计语言知识来解决问题.

三、设计方法和基本原理

1.课题功能描述

本程序的功能,就是实现数的加减乘除四则运算,如自动计算3+5*8的结果。

2.问题详细描述

程序运行时,首先提示用户输入四则运算表达式(表达式中最多有3个运算符,数据范围为1-100的整数);

输入结束后,程序自动行计算并给进出结果。

如:输入13-10+5/8时输出3.625。

3.问题的解决方案

注意:问题的解决方案有很多,下面给出的仅供同学们参考。

该问题主要注意四则运算的优先级问题:乘除运算比加减运算优先级高,同级运算按从左到右的顺序运算。

本程序应采用模块化设计方法,设计几个功能模块。例如(仅供参考):

1) 字符串解析函数(将输入字符串分解成数和运算符)

2) 将数据(字符数组中)转换成十进制数(long)

3) 判读是否存在高优先级运算符,若存在首先计算其运算结果并保存。

4) 同级运算按先后顺序进行。

四、创新要求

实现程序功能后,可进行创新设计:

1) 使用多文件,即主函数和各个函数分别存放在不同的.c文件中,在头文件中进行函数原型声明;

2) 在程序中增加自动出题功能及自动批卷功能

3) 不限定运算符个数

4) 允许括号运算的存在。

二、功能描述

一、读入当前字符串,并进行转换。

二、按类别,把运算数字和运算符区分开分别存入对应字符数组中。

三、按四则运算法则,先乘除后加减执行计算。

三、主要函数描述

1)  get_dat()           字符串解析函数

2)  data_make()        判读是否存在高优先级运算符,若存在首先计算其运算结果并保存

四、主要技术问题

一、字符串的解析,数据和运算符的分类

二、先乘除后加减,把已运算过的数据赋值为0,已运算过的变为加号

三、输入字符串必须以数字开头

五、结论(实验心得)

一、在处理先乘除后加减的过程中,对已进行乘除运算的数据处理时一个关键,这里我把这

类数据赋值为0,乘除号变为加号,便于下面的加减运算。

附录:第三题源程序

#include

/**************************数据和运算符归类处理***************************/

void get_dat(char *dat,float *num,char *sig)                //  字符串解析函数

{

       int i=0,j=0;

       *num=0;                                         //  初始化

       printf("欢迎使用简易四则运算器,请输入:\n");

       scanf("%s",dat);                       

       for(i=0;*(dat+i)!='\0';i++)

       {    

              if((*(dat+i)<'0')||(*(dat+i)>'9'))                 //  如果输入的不是0-9的自然数

              {

                     if(i==0)

                     {

                            printf("算式有误,请重新输入!\n");   / / 如果输入字符不是以数字开头

                            break;

                     }

                     *(sig+j)=*(dat+i);                       //  如果是运算符就存储

                     j++;                                  //  指针位置加一

              }

              else

              {

                     *(num+j)=*(num+j)*10+(*(dat+i)-'0');       // 不是运算符就转化为数据存储

              }

       }

}

//  判读是否存在高优先级运算符,若存在首先计算其运算结果并保存

void data_make(float *num,char *sig)  

{

       int i=0;

       for(i=0;*(sig+i)!='\0';i++)           // 扫描一遍  先乘除后加减

       {

              if(*(sig+i)=='*')               // 执行对应法则 计算结果存入后一个数据单元

              {

                     *(num+i+1)=(*(num+i))*(*(num+i+1));

                     *(num+i)=0;              //  清空前一个数据单元,便于加减的运算

                     *(sig+i)='+';               //  把乘除转换为加 防止运算符干扰

              }

              if(*(sig+i)=='/')

              {

                     *(num+i+1)=(*(num+i))/(*(num+i+1));

                     *(num+i)=0;

                     *(sig+i)='+';

              } 

       }

       for(i=0;*(sig+i)!='\0';i++)              //  扫描一遍 加减运算

       {

              if(*(sig+i)=='+')           //  执行对应法则 计算结果存入后一个数据单元

              {

                     *(num+i+1)=(*(num+i))+(*(num+i+1));  

                     *(num+i)=0;             //  清空前一个数据单元,便于下一个运算

              }    

              if(*(sig+i)=='-')

              {

                     *(num+i+1)=(*(num+i))-(*(num+i+1));

                     *(num+i)=0;

              }

       }

       printf("计算答案是:%.3f\n",*(num+i));    //  最后一个数据单元为计算结果

/*******************************主函数**********************************/

int main()                            //   主函数

{

       int i=0;

       char calc_dat[200]={0};             //  定义一个保存算式的字符数组

       char calc_sig[100]={0};             //  定义一个保存运算符的字符数组

       float num_dat[100]={0};             //  定义一个保存运算数据的数组

// 字符串解析函数 用户输入算式 运算符 运算数据

       get_dat(calc_dat,num_dat,calc_sig);   

// 运算数据  运算符  先乘除后加减 

       data_make(num_dat,calc_sig);         

       return 0;

}

第四题

一、问题描述

一、题目:数字游戏

    玲玲喜欢通过玩数字游戏的方式来加深别人对她的印象。她最喜欢的一个数字游戏是让人给出一个数N,然后她会立即说出N的阶乘最末尾有多少个连续的零。很显然,这会让别人会对她印象深刻,因为,一般来说N!是一个非常大的数。例如,N为100时,100!会比地球上所有原子的数目还要大,但玲玲可以很快说出100!末尾有连续24个0。但是,她的一些朋友通常不是以10为进制的。这时,玲玲却不知道该怎么修改她的技巧来适应这些朋友了。

问题:

给出一个进制b和一个数n,计算当采用b进制时,n!末尾有多少个连续的0。例如,当b=2和n=5时,由于5!=120=1111000(2),结果应该为3.

输入:

第一行包含了总的计算次数。接下来的每一行给出了不同情况下的问题中的两个数b(2 ≤ b ≤ 1 000)和n(1 ≤ n ≤ 1 000 000),这两个数都是10进制的。

输出:

输出结果中,对每一次计算都以"Scenario #i:"开始,其中的i是从1开始的第i次计算。然后打印一行,输出:当采用b进制时,n!末尾有多少个连续的0(以十进制形式)。对每一次计算都以一个空白行结束。

输入样例:

3

2 5

10 100

45 10000

对样例的正确输出:

Scenario  #1:

3

Scenario  #2:

24

Scenario  #3:

2498

二、功能描述

这个问题是对n!后面有几个0的变种。如果是问n!最后有几个0应该怎么算?肯定不是先算出n!是几,然后再数0的。如题目所言,N为100时,100!会比地球上所有原子的数目还要大,那么如何得出我们想要的结果呢?

现在我们知道,5!=120,所以当5!采用十进制表示的时候,5!末尾有一个零。也就是说5!只能被一个10整除!那么同理,当问5!采用二进制表示的时候,5!末尾有几个零,实际就是5!能被多少个2整除,120能被3个2整除,所以末尾就是3个0。

例如现在要求12进制时9!末尾有几个0。我们先把12分解质因数,得12=2*2*3,然后再算9!=1*2*3*4*5*6*7*8*9,把这些阶乘逐个分解质因数,算出共有几个2,几个3相乘。显然里面有2+(2+2)+2+(2+2+2)共7个2,有3+3+(3+3)共4个3,又因为12里面有2个2,所以7/2=3.5,一个3,所以4/1=4,显然只能取3,所以9!能被3个12整除,末尾必有3个0。

三、解决方案(流程图)

算法与编程实习报告   

四、主要函数描述

1)  factor_calc()               //  对进制进行分解质因数

2)  data_calc()                //  对阶乘逐个进行分解质因数

3)  result_calc                //  对统计的质因数进行比较

4)  display()                 //  结果输出

五、主要技术问题

一、该题实际上是求n!能够被多少个对应的进制整除。

二、利用C语言对进制进行分解质因数。

三、利用C语言对阶乘逐个分解质因数。

四、把两个结果进行比较,得出n!至多能被多少个进制整除,则在该进制下,它的末尾就有几个0。

六、结论(实验心得)

一、巧妙的算法很重要。

附录:第四题源程序

#include

void factor_calc(int base,int *factor,int *factor_num)        //  计算进制的因数种类和个数

{

       int i=0,j=0,n=2,flag=0;

       while(n<=base)

       {

              if(base%n==0)                               //  如果整除

              {

                     flag=1;                                 //  整除标志

                     base=base/n;                            //  下次用商进行计算

                     *(factor+i)=n;                            //  记录因数

                     *(factor_num+i)=++j;                      //  对应次数加一

              }

              else

              {

                     n++;                                    //  除数加一

                     if(flag==1)                               //  如果上次整除了

                     {

                            i++;                               //  记录的因数的数组向后移

                            j=0;                                 //  释放j

                            flag=0;                              //  释放flag

                     }

              }

       }

}

void data_calc(int data,int *factor,int *data_factor)        //  阶乘的因素计算

{

       int i=0,data_s=0,value=1;                        //  计算n!中各个数所含因数

       int temp=0;                                   //  临时值用于存储n的阶乘

       for(i=0;*(factor+i)!=0;i++)                       //  因数一个个比较下去

       {

              for(data_s=2;data_s<=data;data_s++)         //  阶乘一个个计算下去

              {

                     temp=data_s;                        

                     while(temp%(*(factor+i))==0)          //  如果整除 对应计数值就加一

                     {

                            *(data_factor+i)=value++;

                            temp=temp/(*(factor+i));           //  商用于下次计算

                     }

              }

              value=1;                                 //  释放value

       }

}

void result_calc(int *factor_num,int *data_factor,int *result)

{

       int i=0;

       *result=((*(data_factor+i))/(*(factor_num+i)));                 

       for(i=0;*(factor_num+i)!=0;i++)                    //  赋初值

       {

              if((*(data_factor+i))/(*(factor_num+i))<(*result))     //  如果一对因数的商较小

              {

                     *result=(*(data_factor+i))/(*(factor_num+i));    //  把结果赋给较小的那一组

              }

       }

}

void display(int count,int *result)                          //  传递次数和结果

{

       int i=0;

      

       for(i=0;i

       {

              printf("Scenario #%d\n",i+1);

              printf("%d\n",*(result+i));

       }

}

/********************************主函数*************************************/

int main()                                               //  主函数

{

       int count=0,base=0,data=0;               //  定义 运算次数 进制类型 运算数据

       int factor[20]={0};                     //  定义 数组 用于存放进制的因数

       int factor_num[20]={0};                 //  定义 数组 用于存放对应因数的个数

       int data_factor[20]={0};                 //  定义 数组 用于存放n!对应因数的个数

       int result[100]={0};                      //  定义 数组 用于存放结果

       int i=0;

       printf("请输入计算次数和对应的运算数据:\n");

       scanf("%d",&count);                      //  扫描运算次数        

      

       for(i=0;i

       {

              scanf("%d %d",&base,&data);          //  扫描进制和运算数据

              factor_calc(base,factor,factor_num);                 //  进制因数计算

              data_calc(data,factor,data_factor);                   //  数据因数计算

              result_calc(factor_num,data_factor,result+i);           //  结果比较

              base=0;                             //  释放存储单元

              data=0;

       }

       display(count,result);                        //  结果输出

       return 0;

}

相关推荐