银行家算法c++

news2025/5/24 9:04:03

银行家算法

  • 1. 银行家算法
  • 1.1 银行算法家的目的
  • 1.2 银行算法家的作用
  • 2. 设计原理
    • 2.1 银行家算法的数据结构
    • 2.2 银行家算法介绍
    • 2.3 安全性算法
  • 3. 实验要求
  • 4. 银行家算法实例
  • 5. 完整代码和运行测试
    • 5.1 测试结果
    • 5.2 完整代码

1. 银行家算法

1.1 银行算法家的目的

银行家算法是避免死锁的一种重要方法, 能够有效的在资源分配的过程中, 对系统的安全性进行检测。通过银行家算法设计与实现, 可以加深对死锁的理解, 掌握死锁的预防、 避免、 检测和解除的基本原理, 重点掌握死锁的避免方法—银行家算法。 初步具有研究、 设计、 编制和调试操作系统模块的能力。

1.2 银行算法家的作用

银行家算法通过在进程请求资源时进行安全性检查,来确保系统不会进入死锁状态。在银行家算法中,客户申请贷款的数量是有限的,每个客户在第一次申请贷款时要声明完成该项目所需的最大资金量,在满足所有贷款要求时,客户应及时归还。如果所有进程都可以完成并终止,则一个状态被认为是安全的。银行家算法的主要作用是避免死锁的产生,特别是在进程间共享资源时。

2. 设计原理

2.1 银行家算法的数据结构

● 可用资源向量 Available [m]
m为系统中资源种类数, Available[j]=k表示系统中第j类资源数为k个。
● 最大需求矩阵Max[n][m]
n为系统中进程数, Max[i][j]=k表示进程i对j类资源的最大需求数为k。
● 分配矩阵Allocation[n][m]
Allocation[i][j]=k表示进程i已分得j类资源的数目为k个。
● 需求矩阵Need[n][m]
Need[i][j]=k 表示进程i还需要j类资源k个。
Need[i][j]=Max[i][j]-Allocation[i][j]

2.2 银行家算法介绍

假设在进程并发执行时进程i提出请求j类资源k个后, 表示为Requesti[j]=k,系统按下述步骤进行安全检查:
1.如果Requesti≤Needi则继续以下检查, 否则显示需求申请超出最大需求值的错误。
2. 如果Requesti≤Available则继续以下检查, 否则显示系统无足够资源, Pi阻塞等待。
3.系统试探把要求的资源分配给进程i并修改有关数据结构的值:
Available = Available-Requesti ;
Allocationi =Allocationi+Requesti ;
Needi=Needi-Requesti ;
4.系统执行安全性算法, 检查此次资源分配后, 系统是否处于安全状态, 若安全,才正式将资源分配给进程i, 以完成本次分配; 否则将试探分配作废, 恢复原来的资源分配状态, 让进程Pi等待。

2.3 安全性算法

A.设置完成标志向量 Finish[n]。
初始化: Finish[i] = false表示i进程尚末完成
B.从进程集合n设置Work[m]表示系统可提供给进程的各类资源数目。 初始化:Work = Available
中找到一个能满足下述二个条件:Finish[i] = false , Needi≤Work,如找到则执行步骤C, 找不到则执行步骤D
C.当进程i获得资源后可顺利执行直到完成, 并释放出分配给它的资源, 表示如下:
work = work+Allocationi ; Finish[i]=true
转执行步骤B。
D.如果所有的Finish[i]=ture, 则表示系统处于安全状态, 否则系统处于不安全状态。

3. 实验要求

能够考虑社会、 健康、 安全、 法律、 文化及环境等因素的影响, 针对银行家算法避免死锁进行建模, 设计实验方案, 运用恰当的集成开发工具编程模拟实现上述算法, 要求:
(1) 有录入界面, 动态录入进程个数、 资源种类数、 诸进程对各类资源的最大需求、 T0时刻系统为诸进程已分配的资源数以及系统中各类资源的资源总数;
(2) 能够判断T0时刻系统是否安全, 进程之间能否无死锁的运行下去, 若能输出安全序列;
(3) 有输出界面, 能够从录入界面模拟进程又提出新的申请, 根据银行家算法判断请求是否能得到满足, 并输出当前时刻下诸进程对各类资源的需求列表及系统可用资源数, 若能输出安全序列, 若不能分配输出无法分配的原因。

4. 银行家算法实例

例题就用课本上的例题,题目如下图所示:
在这里插入图片描述
假定系统中有5个进程{P0,P1,P2,P3,P4},和3类资源{A,B,C},各类资源的数量分别为10、5、7,在时刻的资源分配情况如图3-17所示。
Max矩阵:一个m×n的矩阵,其中m表示进程数,n表示资源数。Max[i][j]表示进程i需要资源j的最大数量
Allocation矩阵:一个m×n的矩阵,其中m表示进程数,n表示资源数。Allocation[i][j]表示进程i已经分配了资源j的数量
Need矩阵:一个m×n的矩阵,其中m表示进程数,n表示资源数。Need[i][j]表示进程i还需要资源j的数量
Available矩阵:一个长度为n的一维矩阵,表示当前系统中还有多少可用资源。其中,Max矩阵和Allocation矩阵的差值就是Need矩阵,即Need[i][j] = Max[i][j] - Allocation[i][j]。Available矩阵表示当前系统中还有多少可用资源,可以通过计算Allocation矩阵的列和再与Max矩阵的列相减得到。
通过上述概念就可以分析这些进程在t0时刻是否安全,算法过程如下:用可用的资源(Available)去和进程还需要的资源(Need)进行比较,如果1.Available>=Need,则说明该进程可以正常运行至结束,该进程结束后,已分配的资源得到释放(Allocation),所以当前可用的资源变为Available+Allocation;如果2.Available<Need,则说明当前进程不能正常进行,换另一个进程重复比较,如果到最后还有进程未运行完毕,则说明进程产生死锁,当前系统不安全。
如本例题的运算结果如下图所示:
在这里插入图片描述
本题用Banker类来实现,由题易知需要一些矩阵来进行模拟进程资源,如Max矩阵,Allocation矩阵,Need矩阵,Available矩阵,这里做些处理,用Work矩阵来表示可用资源的数量(即上图中Work+Allocation,而上图中的Work矩阵可以去掉),再用一个Finish矩阵表示进程是否成功运行。还需要一个安全序列,如上图中{P1,P3,P4,P2,P0},所以可以用一个哈希表(set)来存某进程是否运行结束(set主要用来查找在不在)。另外还可以加上线程的数目(_m)和可用于资源的种类(_n)。如下为类中的成员变量:

class Banker
{
private:
	vector<bool> Finish;			//进程完成标志向量
	vector<vector<int>> Max;		//最大需求矩阵
	vector<vector<int>> Allocation; //已分配矩阵
	vector<vector<int>> Need;		//需求矩阵
	vector<vector<int>> Work;		//可用资源
	vector<int> Available;			//可用资源向量

	unordered_set<int> set;			//进程完成的安全序列
	int _m;							//进程数目
	int _n;							//资源的种类
};

该类的构造函数用来初始化数据,因为没有开辟空间(使用new,malloc,realloc,calloc等函数),所以析构函数不用写,构造析构函数如下:

class Banker
{
public:
	Banker(const int& m, const int& n)
		:Finish(m, false), Max(m, vector<int>(n)), Allocation(m, vector<int>(n)), Need(m, vector<int>(n)), Work(m, vector<int>(n)),
		Available(n), _m(m), _n(n)
	{
		cout << "请输入最大需求矩阵:" << endl;
		for (int i = 0; i < m; ++i)
		{
			for (int j = 0; j < n; ++j)
			{
				cin >> Max[i][j];
			}
		}
		cout << "请输入已分配资源的矩阵:" << endl;
		for (int i = 0; i < m; ++i)
		{
			for (int j = 0; j < n; ++j)
			{
				cin >> Allocation[i][j];
			}
		}
		for (int i = 0; i < m; ++i)
		{
			for (int j = 0; j < n; ++j)
			{
				Need[i][j] = Max[i][j] - Allocation[i][j];
			}
		}
		cout << "请输入可用资源数目:" << endl;
		for (int i = 0; i < n; ++i)
		{
			cin >> Available[i];
		}
	}
	~Banker()
	{}
};

接下来就是判断t0时刻系统是否安全,算法思路如上述所示,具体代码和详细解释(checkSafe),在这里设计的是如果系统不安全,则强制退出,代码如下:

	bool compare(const vector<int>& v1, const vector<int>& v2)
	{
		for (int i = 0; i < _n; ++i)
		{
			if (v1[i] < v2[i])
			{
				return false;
			}
		}
		return true;
	}

	void checkSafe()
	{
		int flag = 1;	//判断进程是否全部可以执行完毕
		int prev = 0;      //单独执行Work
		Work[0] = Available; //更新Work,Work矩阵在每次检查系统安全是需要修改的
		while (flag) //遍历进程可能遍历多次,并且可能产生死锁,flag是每次遍历进程是否有进程成功运行的标志
		{
			flag = 0;
			//遍历每一个进程
			for (int i = 0; i < _m; ++i)
			{
				unordered_set<int>::iterator it = set.find(i);
				if (it != set.end())
					continue;

				if (compare(Work[prev], Need[i])) // 如果可用资源大于等于还需要的资源数量,则该进程正常运行
				{
					set.insert(i);
					Finish[i] = true;
					flag = 1;

					for (int j = 0; j < _n; ++j)
					{
						Work[i][j] = Allocation[i][j] + Work[prev][j];
					}
					//更新Work的prev
					prev = i;
				}
			}
		}
		if (set.size() != _m) //如果运行结束的所有进程的数量不等于原有进程的数量,则证明死锁
		{
			cout << "进程没有全部执行完毕,已产生死锁,此时系统是不安全的。" << endl;
			cout << "已强制退出" << endl;
			exit(1); //退出码设为1
		}
	}

如上就可以检查系统是否安全。还有一个问题是进程发送请求向量,如下图所示:
在这里插入图片描述
这道题要输入Request矩阵,而且可以是多次输入Request,具体代码和详细解释(checkSafe)如下:

	void request()
	{
		int m = 0;
		vector<int> Request(_n);
		cout << "请输入需要请求资源的进程:";
		cin >> m;
		cout << "请输入P" << m << "发出请求向量Request:";
		for (int i = 0; i < _n; ++i)
			cin >> Request[i];
		cout << "系统按银行家算法进行检查。" << endl;

		int flag = 1; //是否可以进行系统检查的标志
		if (compare(Need[m], Request))
			cout << "Request<=Need( ";
		else
		{
			cout << "Request>Need( ";
			flag = 0;
		}
		for (auto& x : Need[m])
			cout << x << ' ';
		cout << ")" << endl;
		
		if (compare(Available, Request))
			cout << "Request<=Available( ";
		else
		{
			cout << "Request>Available( ";
			flag = 0;
		}
		for (auto& x : Available)
			cout << x << ' ';
		cout << ")";
		if (flag)
		{
			//更新数据
			for (int i = 0; i < _n; ++i)
				Need[m][i] -= Request[i];
			for (int i = 0; i < _n; ++i)
				Available[i] -= Request[i];
			for (int i = 0; i < _n; ++i)
				Allocation[m][i] += Request[i];
			//发送请求后,再检查进程安全之前切记将set表释放,重新统计新的安全序列
			set.erase(set.begin(), set.end());
			//或者set.clear();
			//每次发送请求后进行检查系统安全并打印结果
			checkSafe();
			print();
		}
		else
		{
			cout << "让P" << m << "等待" << endl;
			cout << endl;
		}
	}

打印函数如下:

	void print()
	{
		cout << "Available:";
		for (int i = 0; i < _n; ++i)
			cout << Available[i] << ' ';
		cout << endl;
		cout << " 资源 | Need | Allocation | Work+Allocation | Finish " << endl; //本题默认是5个进程3个资源,如果数量不同打印结果可能不美观
		for (auto i : set) //用进程完成的安全序列来遍历所有数据
		{
			cout << "  P" << i << "  |";
			for (int j = 0; j < _n; ++j)
			{
				cout << Need[i][j] << " ";
			}
			cout << "| ";
			for (int j = 0; j < _n; ++j)
			{
				cout << " " << Allocation[i][j] << " ";
			}
			cout << "  |";
			for (int j = 0; j < _n; ++j)
			{
				cout << "  " << Work[i][j] << "  ";
			}
			cout << "  |" << Finish[i] << endl;;
		}
		cout << "利用安全性算法进行分析,可知存在着一个安全序列";
		for (auto it : set)
		{
			cout << "P" << it << ",";
		}
		cout << "故系统是安全的" << endl;
		cout << endl;
	}

5. 完整代码和运行测试

5.1 测试结果

第一问:
在这里插入图片描述

第二问:
在这里插入图片描述
第三问:
在这里插入图片描述
第四问:
在这里插入图片描述

5.2 完整代码

头文件banker.h代码如下:

#pragma once

#include <iostream>
#include <vector>
#include <unordered_set>
using namespace std;

class Banker
{
public:
	Banker(const int& m, const int& n)
		:Finish(m, false), Max(m, vector<int>(n)), Allocation(m, vector<int>(n)), Need(m, vector<int>(n)), Work(m, vector<int>(n)),
		Available(n), _m(m), _n(n)
	{
		cout << "请输入最大需求矩阵:" << endl;
		for (int i = 0; i < m; ++i)
		{
			for (int j = 0; j < n; ++j)
			{
				cin >> Max[i][j];
			}
		}
		cout << "请输入已分配资源的矩阵:" << endl;
		for (int i = 0; i < m; ++i)
		{
			for (int j = 0; j < n; ++j)
			{
				cin >> Allocation[i][j];
			}
		}
		for (int i = 0; i < m; ++i)
		{
			for (int j = 0; j < n; ++j)
			{
				Need[i][j] = Max[i][j] - Allocation[i][j];
			}
		}
		cout << "请输入可用资源数目:" << endl;
		for (int i = 0; i < n; ++i)
		{
			cin >> Available[i];
		}
	}

	bool compare(const vector<int>& v1, const vector<int>& v2)
	{
		for (int i = 0; i < _n; ++i)
		{
			if (v1[i] < v2[i])
			{
				return false;
			}
		}
		return true;
	}

	void checkSafe()
	{
		int flag = 1;	//判断进程是否全部可以执行完毕
		int prev = 0;      //单独执行Work
		Work[0] = Available; //更新Work
		while (flag) //遍历进程可能遍历多次,并且可能产生死锁,flag是每次遍历进程是否有进程成功运行的标志
		{
			flag = 0;
			//遍历每一个进程
			for (int i = 0; i < _m; ++i)
			{
				unordered_set<int>::iterator it = set.find(i);
				if (it != set.end())
					continue;

				if (compare(Work[prev], Need[i])) // 如果可用资源大于等于还需要的资源数量,则该进程正常运行
				{
					set.insert(i);
					Finish[i] = true;
					flag = 1;

					for (int j = 0; j < _n; ++j)
					{
						Work[i][j] = Allocation[i][j] + Work[prev][j];
					}
					//更新Work的prev
					prev = i;
				}
			}
		}
		if (set.size() != _m) //如果运行结束的所有进程的数量不等于原有进程的数量,则证明死锁
		{
			cout << "进程没有全部执行完毕,已产生死锁,此时系统是不安全的。" << endl;
			cout << "已强制退出" << endl;
			exit(1); //退出码设为1
		}
	}

	void request()
	{
		int m = 0;
		vector<int> Request(_n);
		cout << "请输入需要请求资源的进程:";
		cin >> m;
		cout << "请输入P" << m << "发出请求向量Request:";
		for (int i = 0; i < _n; ++i)
			cin >> Request[i];
		cout << "系统按银行家算法进行检查。" << endl;

		int flag = 1;
		if (compare(Need[m], Request))
			cout << "Request<=Need( ";
		else
		{
			cout << "Request>Need( ";
			flag = 0;
		}
		for (auto& x : Need[m])
			cout << x << ' ';
		cout << ")" << endl;
		
		if (compare(Available, Request))
			cout << "Request<=Available( ";
		else
		{
			cout << "Request>Available( ";
			flag = 0;
		}
		for (auto& x : Available)
			cout << x << ' ';
		cout << ")";
		if (flag)
		{
			//更新数据
			for (int i = 0; i < _n; ++i)
				Need[m][i] -= Request[i];
			for (int i = 0; i < _n; ++i)
				Available[i] -= Request[i];
			for (int i = 0; i < _n; ++i)
				Allocation[m][i] += Request[i];

			//发送请求后,再检查进程安全切记将set表释放,重新统计新的安全序列
			set.erase(set.begin(), set.end());
			//或者set.clear();
			checkSafe();
			print();
		}
		else
		{
			cout << "让P" << m << "等待" << endl;
			cout << endl;
		}
	}

	void print()
	{
		cout << "Available:";
		for (int i = 0; i < _n; ++i)
			cout << Available[i] << ' ';
		cout << endl;
		cout << " 资源 | Need | Allocation | Work+Allocation | Finish " << endl;
		for (auto i : set)
		{
			cout << "  P" << i << "  |";
			for (int j = 0; j < _n; ++j)
			{
				cout << Need[i][j] << " ";
			}
			cout << "| ";
			for (int j = 0; j < _n; ++j)
			{
				cout << " " << Allocation[i][j] << " ";
			}
			cout << "  |";
			for (int j = 0; j < _n; ++j)
			{
				cout << "  " << Work[i][j] << "  ";
			}
			cout << "  |" << Finish[i] << endl;;
		}
		cout << "利用安全性算法对t0时刻进行分析,可知在t0时刻存在着一个安全序列";
		for (auto it : set)
		{
			cout << "P" << it << ",";
		}
		cout << "故系统是安全的" << endl;

		cout << endl;
	}

	~Banker()
	{}
private:
	vector<bool> Finish;			//进程完成标志向量
	vector<vector<int>> Max;		//最大需求矩阵
	vector<vector<int>> Allocation; //已分配矩阵
	vector<vector<int>> Need;		//需求矩阵
	vector<vector<int>> Work;		//可用资源
	vector<int> Available;			//可用资源向量

	unordered_set<int> set;			//进程完成的安全序列
	int _m;							//进程数目
	int _n;							//资源的种类
};

main.cc文件代码如下:

#include "banker.h"

int main()
{
    int m = 0, n = 0; //p表示进程的数目,n表示资源的种类
    cout << "请输入进程的数目:";
    cin >> m;
    cout << "请输入资源的种类:";
    cin >> n;
    Banker bank(m, n);
    bank.checkSafe();
    bank.print();
    while (true)
    {
        bank.request();
    }
    return 0;
}

//测试数据
//7 5 3
//3 2 2
//9 0 2
//2 2 2
//4 3 3
//0 1 0
//2 0 0
//3 0 2
//2 1 1
//0 0 2
//3 3 2

在最后,有些老师会在意输入的一些小问题,如上代码中,没有输入总的资源数目,而输入的是分配之后剩余的资源数目(Available)。如果强调输入的是总的资源数目,剩余的资源数目(Available)是计算出来的,那么在定义一个类的私有成员vector<int> Total,表示总的资源数目,然后将类的构造函数进行修改即可,修改后的析构函数代码如下:

Banker(const int& m, const int& n)
		:Finish(m, false), Max(m, vector<int>(n)), Allocation(m, vector<int>(n)), Need(m, vector<int>(n)), Work(m, vector<int>(n)),
		Available(n), _m(m), _n(n), Total(n)
	{
		cout << "请输入最大需求矩阵:" << endl;
		for (int i = 0; i < m; ++i)
		{
			for (int j = 0; j < n; ++j)
			{
				cin >> Max[i][j];
			}
		}
		cout << "请输入已分配资源的矩阵:" << endl;
		for (int i = 0; i < m; ++i)
		{
			for (int j = 0; j < n; ++j)
			{
				cin >> Allocation[i][j];
			}
		}
		for (int i = 0; i < m; ++i)
		{
			for (int j = 0; j < n; ++j)
			{
				Need[i][j] = Max[i][j] - Allocation[i][j];
			}
		}
		//cout << "请输入可用资源数目:" << endl;
		//for (int i = 0; i < n; ++i)
		//{
		//	cin >> Available[i];
		//}
		cout << "请输入总的资源数目:" << endl;
		for (int i = 0; i < n; ++i)
		{
			cin >> Total[i];
		}
		//计算Available
		vector<int> temp = Total; //尽量不要修改Total数组
		for (int i = 0; i < m; ++i)
		{
			for (int j = 0; j < n; ++j)
			{
				temp[j] -= Allocation[i][j];
			}
		}
		Available = temp;
	}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1356016.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

奇技淫巧:如何给项目中的RabbitMQ添加总开关

本文主要分享了如何给项目中的RabbitMQ添加总开关&#xff0c;通过简单配置开/关RabbitMQ。 一、需求背景 SpringBoot项目里使用了RabbitMQ&#xff0c;但某些场景下&#xff0c;不希望项目启动时自动检查RabbitMQ连接 例如&#xff1a; 在开发不需要RabbitMQ的功能过程中&…

python的课后练习总结4(for循环)

1&#xff0c;for循环 for 临时变量 in 序列: 重复执行的代码1 重复执行的代码2 ........... 遍历序列 字符串 我是中国人 列表 [‘星期一,星期二,星期三,星期四] 元组 (‘星期一,星期二,星期三,星期四&#xff09; 一&#xff0c;break 终止循环 二&#xff0c;con…

【C初阶——指针2】鹏哥C语言系列文章,基本语法知识全面讲解——指针(2)

崩刃的剑&#xff0c;依旧致命&#xff0c;锈蚀的盾&#xff0c;屹立如初&#xff08;王者荣耀李信&#xff09; 本文由睡觉待开机原创&#xff0c;转载请注明出处。 本内容在csdn网站首发 欢迎各位点赞—评论—收藏 如果存在不足之处请评论留言&#xff0c;共同进步&#xff0…

能翻页的电子图册怎么做

​随着科技的进步&#xff0c;电子图册已经成为了越来越多企业宣传和展示产品的重要工具。相比于传统的纸质图册&#xff0c;电子图册具有更多的优点&#xff0c;如方便携带、易于分享、可交互性强等。那么&#xff0c;如何制作一款能翻页的电子图册呢&#xff1f; 一、确定主题…

INT201各种题型收集

汇总一下 FA 有穷自动机 - RL正则语言 DFA M (Q, Σ, δ, q, F) Q 是有限状态集合&#xff08;Finite Set of States&#xff09;&#xff1a; 这表示自动机中存在一个有限数量的不同状态。每个状态代表了自动机在某个特定时刻的内部状态。这些状态可以用符号或名称表示。 …

基于多反应堆的高并发服务器【C/C++/Reactor】(中)Buffer的创建和销毁

TcpConnection:封装的就是建立连接之后得到的用于通信的文件描述符&#xff0c;然后基于这个文件描述符&#xff0c;在发送数据的时候&#xff0c;需要把数据先写入到一块内存里边&#xff0c;然后再把这块内存里边的数据发送给客户端&#xff0c;除了发送数据&#xff0c;剩下…

内存的基础知识-第四十天

目录 什么是内存&#xff1f;内存的作用 常用的数量单位 指令的工作原理 思考 三种装入方式 绝对装入 可重定位装入&#xff08;静态重定位&#xff09; 动态运行时装入&#xff08;动态重定位&#xff09; 写程序到程序运行 编译和链接 链接的三种方式 本节思维导…

代码随想录27期|Pthon|Day31|贪心算法|理论基础|455.分发饼干|376. 摆动序列|53. 最大子序和

理论基础 首先&#xff0c;贪心算法基本靠“做题感觉”&#xff0c;所以没有规范的总结和做题技巧&#xff0c;只能说见到过之后还能想起来。 一般情况可以看成是对于一个大的问题的子问题的局部最优的求解&#xff0c;然后可以推导出全局的最优。 这个过程没有证明&#xf…

数据库中的几种锁

数据库锁 1.数据库锁的种类 以 mysql innoDB 为例&#xff0c;数据库的锁有 排他锁&#xff0c;共享锁&#xff0c;意向锁&#xff0c;自增锁&#xff0c;间隙锁&#xff0c;锁的范围有包括&#xff0c;行锁&#xff0c;表锁 &#xff0c;区间锁。 从应用研发的视角&#xff…

Gromacs WARNING问题

上述示例中&#xff0c;NA 是对系统净电荷进行中和的阳离子。请根据您的系统特性和仿真需求调整这些值。 总体而言&#xff0c;这个警告是为了提醒您关于电荷中性化的问题&#xff0c;确保您的模拟结果更加物理可信。 收敛性未达到预期精度&#xff1a; 警告指出&#xff0c;优…

普中STM32-PZ6806L开发板(HAL库函数实现-访问多个温度传感器DS18B20)

简介 我们知道多个DS18B20的DQ线是可以被挂在一起的, 也就是一根线上可以访问不同的DS18B20而不会造成数据错乱, 怎么做到的&#xff0c;其实数据手册都有说到&#xff0c; 就是靠64-bit ROM code 进行识别, 也可以理解成Serial Number进行识别, 因为主要差异还是在Serial Numb…

成为一名合格的软件测试工程师,得掌握什么技能?

在这个信息时代&#xff0c;软件行业的需求空前增长&#xff0c;而软件测试工程师作为软件开发过程中的重要角色&#xff0c;也越来越受企业的重视。那么&#xff0c;成为一名合格的软件测试工程师需要掌握什么技能呢&#xff1f;我结合多年的教学经验为大家总结出以下几点。 …

Fast and flexible X-ray tomography using the ASTRA toolbox

使用ASTRA工具箱进行快速灵活的X射线断层扫描 论文链接&#xff1a;http://dX.doi.org/10.1364/OE.24.025129 项目链接&#xff1a;https://astra-toolboX.com/indeX.html Abstract 从一系列投影图像中重建物体&#xff0c;如在计算机断层扫描(CT)中&#xff0c;是许多不同应…

nuxt3 env文件、全局变量处理

有两种方向 通过配置nuxt.config.ts Nuxt提供的钩子函数&#xff0c;实现全局变量的获取 runtimeconfig env文件往runtimeconfig放入内容 useAppConfig 通过env文件配置来获取服务端全局变量&#xff0c;客户端通过vite.define实现 nuxt.config.ts Nuxt钩子 1. runtim…

Unity ab包如何加密

「ab包」全称为 AssetBundle &#xff0c;是Unity提供的一种资源存储压缩包。其中储存了游戏的资源&#xff0c;如图片、模型、纹理、音视频、代码等文件。 由于ab包具有灵活储存、支持热更、包体较小且便于管理等优势&#xff0c;已经成为了市面上主流的游戏资源压缩方式。 …

李沐机器学习系列4---全连接层到卷积

1 从全连接到卷积 1.1 平移不变性 从概率分布的角度来看卷积的定义, f ( τ ) f(\tau) f(τ)是概率密度&#xff0c; g ( t − τ ) g(t-\tau) g(t−τ)是在这个分布下的均值 ( f ∗ g ) ( t ) ∫ − ∞ ∞ f ( τ ) g ( t − τ ) d τ (f*g)(t)\int_{-\infin}^{\infin}f(\t…

2024/01/02 每日AI必读资讯

减少LLM幻觉的方法 这篇论文总结了减少LLM幻觉的32种方法&#xff0c;包括RAG、微调模型&#xff0c;提示词工程等。 论文&#xff1a;https://arxiv.org/abs/2401.01313E5-mistral-7b-instruct&#xff1a;使用合成数据训练的Embedding模型 亮点是仅使用LLM生成的数据即可实现…

指令流水线的计算

我们需要知道以下公式&#xff1a; 设指令的条数为 n&#xff0c;指令执行需要 m 个阶段&#xff0c;时钟周期为 t 不采用流水线执行的时间&#xff1a;T1 n x m x t&#xff1b; 采用流水线执行的时间&#xff1a;T2 m x t (n - 1) x t&#xff1b; 加速比 S T1 / T2&…

PTA——逆序的三位数

程序每次读入一个正3位数&#xff0c;然后输出按位逆序的数字。注意&#xff1a;当输入的数字含有结尾的0时&#xff0c;输出不应带有前导的0。比如输入700&#xff0c;输出应该是7。 输入格式&#xff1a; 每个测试是一个3位的正整数。 输出格式&#xff1a; 输出按位逆序…

MacOS M1/M2 Go Debug 配置

前言 换电脑&#xff0c;Go 环境带来一些麻烦&#xff0c;耽误很多时间&#xff0c;稍作记录。 原始电脑是 Mac 旧款&#xff0c;CPU x86 构型&#xff0c;新电脑 M2&#xff0c;因为旧电脑里本地文件很多&#xff0c;为了简化搬迁&#xff0c;还是用了 Mac 自带的迁移&#x…