埃拉托斯特尼筛法查找质数

内容分享7小时前发布
0 0 0

table {
border-collapse: collapse;
width: 100%;
margin-bottom: 1rem;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
th {
background-color: #f2f2f2;
}
tr:nth-child(even) {
background-color: #f9f9f9;
}
pre {
background-color: #f8f8f8;
padding: 15px;
border-radius: 4px;
overflow-x: auto;
}

28、埃拉托斯特尼筛法由同名的希腊数学家发明,它提供了一种快速找出给定范围内所有质数的方法。该算法需要创建一个字节数组,通过以下方式插入 1 来“标记”数组位置:从位置 2(它是一个质数)开始,在数组中每个 2 的倍数的位置插入 1。然后对下一个质数 3 的倍数做同样的操作。找到 3 之后的下一个质数 5,并标记所有 5 的倍数的位置。按此方式继续,直到找出所有质数的倍数。数组中未标记的剩余位置表示哪些数字是质数。对于这个程序,创建一个包含 65000 个元素的数组,并显示 2 到 65000 之间的所有质数。在未初始化的数据段声明该数组,并使用 STOSB 指令将其填充为零。

埃拉托斯特尼筛法查找质数

本题要求利用

埃拉托斯特尼筛法

找出

2 到 65000

之间的所有质数。

具体步骤:

创建一个包含 65000 个元素的数组;



未初始化的数据段

声明该数组;

使用

STOSB 指令

将数组填充为零;

从位置

2

开始,标记

2 的倍数

位置为 1;

接着标记

3、5 等质数的倍数

位置为 1;

最终,数组中

未标记的位置

对应的数字即为质数;

将这些质数显示出来。

29、编写一个冒泡排序程序,添加一个变量作为交换标志。当内循环中交换一对数值时将该变量设为1。如果在对数组进行一次完整遍历的过程中没有发生交换,就使用这个变量提前结束排序。

以下是添加交换标志变量以优化冒泡排序的伪代码示例:


procedure BubbleSort(arr[], n):
    exchangeFlag = 0
    for i from 0 to n - 1:
        exchangeFlag = 0
        for j from 0 to n - i - 1:
            if arr[j] > arr[j + 1]:
                // 交换 arr[j] 和 arr[j+1]
                temp = arr[j]
                arr[j] = arr[j + 1]
                arr[j + 1] = temp
                exchangeFlag = 1
        if exchangeFlag == 0:
            break

在上述伪代码中,

exchangeFlag

作为交换标志变量。每次外循环开始时,将其初始化为 0。在内循环中,如果发生了交换操作,就将

exchangeFlag

设为 1。如果一次外循环结束后

exchangeFlag

仍为 0,说明这一轮没有发生交换,数组已经有序,可以提前结束排序。

30、创建一个宏,用于等待按键并返回按下的键。该宏应包含用于存储 ASCII 码和键盘扫描码的参数。编写一个测试该宏的程序。例如,以下代码等待按键;返回时,两个参数将包含 ASCII 码和扫描码:数据段定义 ascii 字节变量留空,scan 字节变量留空;代码段调用 mReadkey 宏并传入 ascii 和 scan 。

以下是实现该功能的代码:


TITLE Testing mReadkey (TestmReadkey.asm)
INCLUDE Irvine32.inc
INCLUDE Macros.inc

; 定义宏 mReadkey
MACRO mReadkey ascii, scan
    call ReadKey
    mov ascii, al
    mov scan, ah
ENDM

.data
ascii BYTE ?
scan  BYTE ?

.code
main PROC
    ; 调用宏等待按键
    mReadkey ascii, scan

    ; 显示 ASCII 码和扫描码
    movzx eax, ascii
    call WriteDec
    mWrite <' ASCII code, ', 0dh, 0ah>

    movzx eax, scan
    call WriteDec
    mWrite <' Scan code', 0dh, 0ah>

    exit
main ENDP
END main

上述代码中,首先定义了

mReadkey

宏,它调用

ReadKey

函数,然后将返回的 ASCII 码和扫描码分别存储到传入的参数中。在

main

过程里,调用该宏等待按键,并将结果存储在

ascii


scan

变量中,最后显示这两个值。

31、创建一个宏,该宏能以给定的文本颜色将一个以空字符结尾的字符串写入控制台。宏的参数应包括字符串名称和颜色。调用一个名为 SetTextColor 的函数来设置文本颜色。编写一个程序,用几种不同颜色的字符串测试你的宏。示例调用:数据段 myString db “Here is my string”.0 代码段 mWritestring myString, white

以下是实现该功能的宏和测试程序示例:


; 定义宏
mWriteStringColor MACRO buffer:REQ, color:REQ
    push eax
    mov eax, color
    call SetTextColor
    push edx
    mov edx, OFFSET buffer
    call WriteString
    pop edx
    pop eax
ENDM

; 测试程序
TITLE Test mWriteStringColor Macro
INCLUDE Irvine32.inc

.data
    myString1 BYTE "String in white", 0
    myString2 BYTE "String in blue", 0
    white EQU 15
    blue  EQU 1

.code
main PROC
    ; 测试白色字符串
    mWriteStringColor myString1, white
    call Crlf

    ; 测试蓝色字符串
    mWriteStringColor myString2, blue
    call Crlf

    exit
main ENDP
END main

这个程序定义了一个名为

mWriteStringColor

的宏,它接受字符串名称和颜色作为参数。在宏内部,先设置文本颜色,然后输出字符串。测试程序中使用了两个不同颜色的字符串进行测试。

32、创建一个名为mScroll的宏,用于在控制台窗口中显示一个彩色矩形。在宏定义中包含以下参数。如果attrib为空,假设颜色为黑色背景上的浅灰色字符:ULrow(窗口左上角行)、ULcol(窗口左上角列)、LRrow(窗口右下角行)、LRcol(窗口右下角列)、attrib(滚动行的颜色)。编写一个测试该宏的程序。


以下是满足你需求的代码示例:
```asm
; 宏定义 mScroll
mScroll MACRO ULrow, ULcol, LRrow, LRcol, attrib
LOCAL scroll_code

scroll_code:
    MOV AH, 6           ; 滚动窗口向上功能号
    MOV AL, 0           ; 滚动所有行
    MOV CH, ULrow       ; 左上角行
    MOV CL, ULcol       ; 左上角列
    MOV DH, LRrow       ; 右下角行
    MOV DL, LRcol       ; 右下角列

    ; 检查 attrib 是否为空,如果为空则设置默认颜色
    IFIDNI <attrib>, <>
        MOV BH, 7       ; 浅灰色字符在黑色背景上
    ELSE
        MOV BH, attrib
    ENDIF

    INT 10h             ; 调用 BIOS 中断
ENDM

; 测试程序
TITLE Test mScroll Macro
INCLUDE Irvine16.inc

.code
main PROC
    ; 初始化数据段
    MOV AX, @data
    MOV DS, AX

    ; 调用 mScroll 宏
    mScroll 5, 10, 15, 20, 12  ; 示例调用,颜色为红色

    ; 等待用户按键
    call ReadChar

    ; 退出程序
    MOV AH, 4Ch
    INT 21h
main ENDP

END main

代码说明:


宏定义

mScroll


:该宏接受五个参数,分别是窗口的左上角行、左上角列、右下角行、右下角列和滚动行的颜色。如果

attrib

参数为空,则默认颜色为浅灰色字符在黑色背景上。


测试程序

:在

main

过程中,调用

mScroll

宏并传入示例参数,然后等待用户按键,最后退出程序。



##33、32位程序如何处理文本输入输出?32位控制台模式下如何处理颜色?Irvine32链接库是如何工作的?MS - Windows中如何处理时间和日期?如何使用MS - Windows函数读写数据文件?是否可以用汇编语言编写图形化Windows应用程序?保护模式程序如何将段和偏移量转换为物理地址?虚拟内存好的原因是什么?
## Windows下32位编程基础

本章将介绍在Microsoft Windows下进行32位编程的基础知识,以回答这些问题。

大部分信息针对32位控制台模式文本应用程序,Irvine32链接库完全基于Win32控制台函数构建。

关于图形化Windows应用程序,若用汇编语言或C编写,代码冗长且复杂。第11.2节以通用方式介绍了32位图形编程,仅作入门引导。

32位控制台模式程序与16位MS-DOS程序在运行模式和使用的函数库上存在差异:

- **32位控制台程序**:
  - 运行在32位保护模式
  - 使用与图形化Windows应用程序相同的库

- **MS-DOS程序**:
  - 使用BIOS和MS-DOS中断

Win32 API可让用户调用32位版本MS-Windows的函数。与之密切相关的Microsoft Platform SDK是创建MS-Windows应用程序的工具集。

更多关于Win32 API函数的详细信息,可通过以下方式查询:

- Microsoft Visual C++ Express的帮助功能
- Microsoft MSDN网站

##34、使用栈参数实现自己版本的ReadString过程。向其传递一个字符串指针和一个整数,该整数表示允许输入的最大字符数。返回实际输入的字符数(存于EAX中)。该过程必须从控制台输入一个字符串,并在字符串末尾(即ODh所在位置)插入一个空字节。编写一个简短的程序来测试你的过程。
```markdown
以下是实现自定义ReadString过程及测试程序的示例代码:

```asm
TITLE Custom ReadString (CustomReadString.asm)
INCLUDE Irvine32.inc

; 自定义ReadString过程
CustomReadString PROC
    push ebp
    mov ebp, esp
    ; 获取栈参数
    mov edx, [ebp + 8]      ; 字符串指针
    mov ecx, [ebp + 12]     ; 最大字符数

    ; 调用ReadConsole
    INVOKE GetStdHandle, STD_INPUT_HANDLE
    mov ebx, eax            ; 保存标准输入句柄
    INVOKE ReadConsole, ebx, edx, ecx - 2, ADDR [ebp + 16], 0

    ; 查找ODh并替换为0
    mov esi, edx
    mov al, 0Dh
L1:
    cmp [esi], al
    jne Next
    mov [esi], byte ptr 0   ; 替换为0
    jmp Done
Next:
    inc esi
    loop L1
Done:
    mov eax, [ebp + 16]     ; 返回实际读取的字符数

    pop ebp
    ret 8                   ; 清理栈
CustomReadString ENDP

; 测试程序
.data
buffer   BYTE 21 DUP(0)     ; 缓冲区
maxChars DWORD 20           ; 最大字符数
bytesRead DWORD ?           ; 实际读取的字符数

.code
main PROC
    ; 调用自定义ReadString过程
    push maxChars
    push OFFSET buffer
    call CustomReadString
    mov bytesRead, eax

    ; 显示缓冲区内容
    mov esi, OFFSET buffer
    mov ecx, bytesRead
    mov ebx, TYPE buffer
    call DumpMem

    exit
main ENDP
END main

代码说明:


CustomReadString过程

:该过程接受两个栈参数,一个是字符串指针,另一个是最大字符数。它调用Win32的ReadConsole函数从控制台读取输入,并在找到ODh时将其替换为0。最后返回实际读取的字符数。


测试程序

:在

main

过程中,我们调用

CustomReadString

过程,并将结果存储在

bytesRead

变量中。然后使用

DumpMem

函数显示缓冲区内容。



##35、编写一个汇编语言版本的清屏过程 Clrscr,该过程能清屏并将光标定位到第 0 行第 0 列。
下面是一个清屏并将光标定位到第 0 行第 0 列的示例代码:

```asm
Clrscr PROC         ; 清屏并定位光标
    pusha
    mov ax, 0600h   ; 滚动整个窗口向上
    mov cx, 0       ; 左上角 (0,0)
    mov dx, 184Fh   ; 右下角 (24,79)
    mov bh, 7       ; 正常属性
    int 10h         ; 调用 BIOS

    mov ah, 2       ; 定位光标在 0,0
    mov bh, 0       ; 视频页面 0
    mov dx, 0       ; 第 0 行,第 0 列
    int 10h
    popa
    ret
Clrscr ENDP

此代码使用 BIOS 中断

int 10h

来清屏并定位光标。

36、编写一个程序来创建一个新的文本文件。提示用户输入学生的学号、姓氏、名字和出生日期。将这些信息写入文件。以同样的方式输入更多的记录,然后关闭文件。

以下是一个使用 Python 语言实现该功能的示例代码:


# 打开一个新的文本文件以写入数据
with open('students.txt', 'w') as file:
    while True:
        # 提示用户输入学生信息
        student_id = input('请输入学生学号(输入 q 退出):')
        if student_id.lower() == 'q':
            break
        last_name = input('请输入学生姓氏:')
        first_name = input('请输入学生名字:')
        birth_date = input('请输入学生出生日期:')
        # 将学生信息写入文件
        file.write(f'{student_id},{last_name},{first_name},{birth_date}
')

代码解释:


文件打开

:使用

open('students.txt', 'w')

以写入模式打开一个名为

students.txt

的文件。

with

语句确保在操作完成后自动关闭文件。


循环输入

:使用

while True

创建一个无限循环,直到用户输入

q

退出。


信息输入

:提示用户输入学生的学号、姓氏、名字和出生日期。


信息写入

:将用户输入的信息以逗号分隔的形式写入文件,并在末尾添加换行符



退出条件

:如果用户输入

q

,则使用

break

语句退出循环,程序结束。

37、修改一个读取文件的汇编程序(原程序名为Readfile.asm),使其能够读取比输入缓冲区大的文件。将缓冲区大小减小到1024字节。使用循环继续读取并显示文件,直到无法读取更多数据。如果打算使用WriteString显示缓冲区,请记得在缓冲区数据末尾插入一个空字节。

修改Readfile.asm程序的步骤

可按以下步骤修改Readfile.asm程序:

将缓冲区大小设为1024字节;

用循环持续读取文件,直至无更多数据;

若用WriteString显示缓冲区,在数据末尾插入空字节。

示例代码修改思路


BUFFER_SIZE

定义为1024;

在读取文件部分添加循环逻辑;

每次读取后检查是否还有数据,若有则继续读取并显示;

每次读取后在缓冲区末尾插入空字节。

38、需要一个16位实模式C++编译器,在MS – DOS、Windows 95、98或千禧版系统下运行。编写一个C++程序,添加一个新的过程,该过程调用ReadSector过程(ReadSector过程用于读取扇区数据到缓冲区)。这个新过程应该以十六进制形式显示每个扇区。使用iomanip.setfill()为每个输出字节填充前导零。

可按以下步骤实现该需求:

首先,在C++程序中包含必要的头文件,如

<iomanip>

用于设置填充。

然后添加新过程,在新过程里调用

ReadSector

过程读取扇区数据到缓冲区,接着遍历缓冲区,使用

std::hex


std::setfill('0')


std::setw(2)

以十六进制形式输出每个字节,并填充前导零。

示例代码如下:


#include <iostream>
#include <iomanip>
#include <stdlib.h>

const int SECTOR_SIZE = 512;
extern "C" ReadSector( char * buffer, long startSector, int driveNum, int numSectors );

void DisplaySectorHex( char * buffer, long startSector, int numSectors ) {
    for (int i = 0; i < numSectors; ++i) {
        std::cout << "Sector " << startSector + i << std::endl;
        for (int j = 0; j < SECTOR_SIZE; ++j) {
            std::cout << std::hex << std::setfill('0') << std::setw(2)
                      << static_cast<int>(static_cast<unsigned char>(buffer[i * SECTOR_SIZE + j]))
                      << " ";
            if ((j + 1) % 16 == 0) {
                std::cout << std::endl;
            }
        }
        std::cout << std::endl;
    }
}

int main() {
    int driveNum, numSectors;
    long startSector;

    std::cout << "Sector display program.

"
              << "Enter drive number [1=A, 2=B, 3=C, 4=D, 5=E,...]: ";
    std::cin >> driveNum;
    std::cout << "Starting sector number to read:";
    std::cin >> startSector;
    std::cout << "Number of sectors to read:";
    std::cin >> numSectors;

    char * buffer = new char[numSectors * SECTOR_SIZE];
    ReadSector( buffer, startSector, driveNum, numSectors );
    DisplaySectorHex( buffer, startSector, numSectors );
    delete[] buffer;
    return 0;
}

39、读取文本文件。打开一个文件用于输入,读取该文件,并以十六进制形式在屏幕上显示其内容。将输入缓冲区设置得小一些,大约256字节,这样程序就可以使用循环根据需要多次调用3Fh功能,直到整个文件处理完毕。

功能实现步骤

需要编写程序实现此功能,步骤如下:

打开文件用于输入;

定义一个约256字节的输入缓冲区;

使用循环多次调用3Fh功能读取文件内容;

将每次读取的内容以十六进制形式显示在屏幕上;

重复步骤3和4,直到整个文件处理完毕。


注意:

要在实地址模式下操作,不使用Irvine 16库,使用INT 21h功能调用进行所有输入输出。

40、复制文本文件。编写一个程序,使其能够读取任意大小的文件。假设缓冲区小于输入文件,使用循环读取所有数据。使用256字节的缓冲区大小。如果任何INT 21h函数调用后进位标志被设置,则显示相应的错误消息。

要完成此任务,可按以下步骤编写程序:

打开输入文件和输出文件;

定义一个256字节的缓冲区;

使用循环调用 INT 21h 的

3Fh

功能读取输入文件的数据到缓冲区,每次读取 256 字节;

每次读取后检查进位标志,如果进位标志被设置,显示相应的错误消息;

将缓冲区中的数据写入输出文件;

重复步骤 3 – 5,直到整个输入文件被处理完;

关闭输入文件和输出文件。

41、文本匹配程序。编写一个程序,打开一个最多包含 60K 字节的文本文件,并对一个字符串进行不区分大小写的搜索。字符串和文件名可由用户输入。显示文件中出现该字符串的每一行,并在每行前面加上行号。程序必须在实地址模式下运行。

程序需求说明

需编写程序实现以下功能:


运行环境

:实地址模式下运行。


文件操作

打开最大 60K 字节的文本文件。


字符串搜索

进行不区分大小写的字符串搜索。


用户交互

用户输入字符串和文件名。


输出要求

显示包含该字符串的所有行。

每行前显示对应的行号。

42、使用异或(XOR)进行文件加密。提示用户输入明文文件和密文文件的名称。打开明文文件用于输入,打开密文文件用于输出。让用户输入一个1到255之间的整数作为加密代码。将明文文件内容读入缓冲区,并将每个字节与加密代码进行异或运算。将处理后的缓冲区内容写入密文文件。只能使用INT 21h进行所有输入/输出操作(除了调用Readint过程获取加密代码)。编写的代码也可用于解密密文文件,恢复出原始的明文文件。

要实现该功能,可按以下步骤编写程序:

提示用户输入明文文件和密文文件的名称,使用

INT 21h

获取用户输入。

打开明文文件用于输入,打开密文文件用于输出,使用

INT 21h

的相应功能。

提示用户输入一个1到255之间的整数作为加密代码,调用

Readint

过程获取输入。

循环将明文文件内容读入缓冲区,每次读取一定数量字节(如256字节),使用

INT 21h

的功能。

对缓冲区中的每个字节与加密代码进行异或运算。

将处理后的缓冲区内容写入密文文件,使用

INT 21h

的功能。

重复步骤4 – 6,直到明文文件全部处理完。

解密时,使用相同的加密代码对密文文件进行同样的异或操作,即可恢复出原始的明文文件。

43、以滚动文本窗口练习为起点,进行如下更改:在循环开始前,随机选择每一列是向上还是向下滚动。在程序运行期间,每列应保持同一滚动方向。提示:将每列定义为一个单独的滚动窗口。

要实现这个需求,可按以下步骤操作:

在程序开始时,为每列随机选择滚动方向(向上或向下),可以使用随机数生成函数,生成0或1来代表不同方向。

将每列视为一个单独的滚动窗口,在滚动文本时,根据每列预先确定的方向进行滚动。

在滚动过程中,保持每列的滚动方向不变。

以下是一个示例代码框架,假设使用汇编语言实现:


TITLE Scrolling Text Window with Random Column Directions
INCLUDE Irvine32.inc

outHandle HANDLE ?
byteswritten DWORD ?
lineNum DWORD 0
columnDirections BYTE 80 DUP(?) ; 假设最多80列
windowRect SMALL_RECT <0,0,60,11> ; 窗口矩形

.data
message BYTE ": This line of text was written",0dh,0ah
messageSize = ($-message)

.code
main PROC
    ; 初始化每列的滚动方向
    MOV ECX, 80 ; 假设最多80列
    MOV ESI, OFFSET columnDirections
INIT_LOOP:
    CALL RandomRange ; 随机生成0或1(假设RandomRange是生成随机数的函数)
    MOV [ESI], AL
    INC ESI
    LOOP INIT_LOOP

    ; 获取标准输出句柄
    INVOKE GetStdHandle, STD_OUTPUT_HANDLE
    MOV outHandle, eax

    ; 写入50行文本
    REPEAT
        MOV eax, lineNum
        CALL WriteDec
        INVOKE WriteConsole, outHandle, ADDR message, messageSize, ADDR byteswritten, NULL
        INC lineNum
    .UNTIL lineNum > 50

    ; 滚动每列文本
    MOV ECX, 80 ; 假设最多80列
    MOV ESI, OFFSET columnDirections
SCROLL_LOOP:
    MOV AL, [ESI]
    CMP AL, 0
    JE SCROLL_UP ; 如果为0,向上滚动

    ; 向下滚动的代码(这里需要实现具体的向下滚动逻辑)
    JMP NEXT_COLUMN

SCROLL_UP:
    ; 向上滚动的代码(这里需要实现具体的向上滚动逻辑)

NEXT_COLUMN:
    INC ESI
    LOOP SCROLL_LOOP

    call ReadChar
    call Clrscr
    call ReadChar
    INVOKE ExitProcess, 0
main ENDP
END main

需要注意的是,上述代码中的

RandomRange

函数、向上和向下滚动的具体逻辑需要根据实际情况进行实现。同时,代码中的列数假设为80,可根据实际需求进行调整。该代码只是一个基本框架,实际实现时可能需要根据具体的编程环境和需求进行修改和完善。

© 版权声明

相关文章

暂无评论

none
暂无评论...