C++课设:简易科学计算器(支持+-*/、sin、cos、tan、log等科学函数)

名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》
创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊)
专栏介绍:《编程项目实战》

目录

    • 一、项目概览与设计理念
      • 1. 功能特色
      • 2. 技术架构
    • 二、核心算法深度解析
      • 1. 词法分析(Tokenization)
      • 2. 中缀转后缀(调度场算法)
      • 3. 后缀表达式求值
    • 三、代码架构与类设计
      • 1. Calculator类的整体结构
      • 2. 函数注册机制
    • 四、特色功能详解
      • 1. 角度与弧度的智能处理
      • 2. 错误处理与用户体验
      • 3. 交互式演示功能
    • 五、实际运行演示
      • 1. 基础运算示例
      • 2. 科学计算示例
      • 3. 复杂表达式示例
    • 六、完整源代码
    • 七、总结与扩展思考

在编程学习的道路上,表达式求值一直是一个经典而重要的问题。今天我们将深入探讨如何用C++从零开始构建一个功能完整的科学计算器,它不仅支持基础的四则运算,还能处理复杂的科学函数计算。这个项目将带你领略词法分析调度场算法后缀表达式求值等核心计算机科学概念的魅力。

一、项目概览与设计理念

1. 功能特色

这个计算器具备以下核心功能:

  • 基础运算:加减乘除、幂运算(支持^**两种语法)
  • 科学函数:三角函数、对数函数、开方、绝对值等
  • 角度支持:同时支持弧度和角度计算(sin vs sind
  • 智能解析:完整的表达式词法分析和语法解析
  • 错误处理:友好的错误提示和异常处理

2. 技术架构

整个计算器采用三阶段处理流程

输入表达式 → 词法分析 → 中缀转后缀 → 后缀求值 → 输出结果

在这里插入图片描述

这种设计遵循了编译原理的经典思想,将复杂问题分解为独立的处理阶段,每个阶段都有明确的职责。

二、核心算法深度解析

1. 词法分析(Tokenization)

词法分析是整个计算过程的第一步,它将输入的字符串分解为有意义的词法单元(Token)。

enum TokenType {NUMBER,      // 数字OPERATOR,    // 操作符FUNCTION,    // 函数LEFT_PAREN,  // 左括号RIGHT_PAREN  // 右括号
};struct Token {TokenType type;string value;double numValue;
};

词法分析器会识别以下模式:

  • 数字识别:支持整数和浮点数
  • 操作符识别:包括特殊的双字符操作符**
  • 函数识别:动态匹配预定义的函数名
  • 括号匹配:正确处理嵌套括号

2. 中缀转后缀(调度场算法)

这里使用了著名的调度场算法(Shunting-yard Algorithm),这是计算机科学家Edsger Dijkstra发明的经典算法。

为什么要转换为后缀表达式?

  • 消除了操作符优先级的歧义
  • 无需括号就能明确表达计算顺序
  • 求值过程更加简单高效
vector<Token> infixToPostfix(const vector<Token>& tokens) {vector<Token> output;stack<Token> operators;for (const Token& token : tokens) {switch (token.type) {case NUMBER:output.push_back(token);break;case OPERATOR:// 处理操作符优先级和结合性while (!operators.empty() && shouldPopOperator(token, operators.top())) {output.push_back(operators.top());operators.pop();}operators.push(token);break;// ... 其他情况处理}}return output;
}

3. 后缀表达式求值

后缀表达式的求值过程非常直观:遇到数字压栈,遇到操作符弹出操作数计算

double evaluatePostfix(const vector<Token>& postfix) {stack<double> values;for (const Token& token : postfix) {if (token.type == NUMBER) {values.push(token.numValue);} else if (token.type == OPERATOR) {double b = values.top(); values.pop();double a = values.top(); values.pop();values.push(calculate(a, token.value, b));}// ... 函数处理}return values.top();
}

三、代码架构与类设计

1. Calculator类的整体结构

class Calculator {
private:map<string, int> operatorPrecedence;        // 操作符优先级map<string, bool> rightAssociative;        // 右结合性标记map<string, double (*)(double)> functions; // 函数指针映射public:Calculator() {initOperators();initFunctions();}double calculate(const string& expression);void showInfixToPostfix(const string& expression);void showSupportedFunctions();
};

这种设计的优势:

  • 封装性好:所有计算逻辑都在类内部
  • 可扩展性强:新增函数只需修改初始化代码
  • 配置化:操作符优先级和函数都通过映射表管理

2. 函数注册机制

计算器使用函数指针映射实现动态函数调用:

void initFunctions() {// 基础数学函数functions["sin"] = sin;functions["cos"] = cos;functions["sqrt"] = sqrt;// 角度版本的三角函数functions["sind"] = sind;functions["cosd"] = cosd;functions["tand"] = tand;
}

这种设计使得添加新函数变得极其简单,只需要定义函数并注册到映射表中即可。

四、特色功能详解

1. 角度与弧度的智能处理

这个计算器的一大亮点是同时支持角度和弧度计算

// 弧度版本(标准数学函数)
sin(1.57)  // ≈ 1.0// 角度版本(添加d后缀)
sind(90)   // = 1.0

实现原理:

static double sind(double deg) {return sin(degToRad(deg));
}static double degToRad(double deg) {return deg * 3.14159265358979323846 / 180.0;
}

2. 错误处理与用户体验

代码中实现了多层次的错误处理:

try {double result = calc.calculate(input);cout << "结果: " << fixed << setprecision(6) << result << endl;
} catch (const exception& e) {cout << "错误: " << e.what() << endl;
}

常见错误类型:

  • 除零错误if (b == 0) throw runtime_error("除零错误");
  • 语法错误:括号不匹配、操作符缺少操作数
  • 函数错误:未知函数名、参数缺失

3. 交互式演示功能

计算器提供了丰富的演示功能:

// 输入 "demo" 查看处理过程
calc.showInfixToPostfix("3 + 4 * 2 / ( 1 - 5 ) ^ 2");// 输出:
// 原始表达式: 3 + 4 * 2 / ( 1 - 5 ) ^ 2
// 词法分析结果: 3 4 2 * 1 5 - 2 ^ / +
// 后缀表达式: 3 4 2 * 1 5 - 2 ^ / +

五、实际运行演示

1. 基础运算示例

请输入表达式: 3 + 4 * 2
结果: 11.000000请输入表达式: 2 ^ 3 * 4
结果: 32.000000请输入表达式: sqrt(16) + log10(100)
结果: 6.000000

在这里插入图片描述

2. 科学计算示例

请输入表达式: sind(30) + cosd(60)
结果: 1.000000请输入表达式: log(exp(5))
结果: 5.000000

在这里插入图片描述

3. 复杂表达式示例

请输入表达式: sin(deg2rad(45)) * sqrt(2)
结果: 1.000000请输入表达式: (sind(30) + cosd(60)) * log10(100)
结果: 2.000000

在这里插入图片描述

六、完整源代码

以下是完整的计算器实现代码:

#include <iostream>
#include <string>
#include <vector>
#include <stack>
#include <cmath>
#include <cctype>
#include <sstream>
#include <map>
#include <iomanip>
#include <stdexcept>
#include <cstdlib>using namespace std;// 枚举类型定义操作符和函数类型
enum TokenType {NUMBER,OPERATOR,FUNCTION,LEFT_PAREN,RIGHT_PAREN
};// 表示一个词法单元
struct Token {TokenType type;string value;double numValue;Token(TokenType t, const string& v, double n = 0) : type(t), value(v), numValue(n) {}
};class Calculator {
private:map<string, int> operatorPrecedence;map<string, bool> rightAssociative;map<string, double (*)(double)> functions;void initOperators() {// 设置操作符优先级operatorPrecedence["+"] = 1;operatorPrecedence["-"] = 1;operatorPrecedence["*"] = 2;operatorPrecedence["/"] = 2;operatorPrecedence["^"] = 3;operatorPrecedence["**"] = 3;// 设置右结合性(只有幂运算是右结合的)rightAssociative["^"] = true;rightAssociative["**"] = true;}// 角度转弧度辅助函数static double degToRad(double deg) {return deg * 3.14159265358979323846 / 180.0;}static double radToDeg(double rad) {return rad * 180.0 / 3.14159265358979323846;}// 角度版本的三角函数static double sind(double deg) {return sin(degToRad(deg));}static double cosd(double deg) {return cos(degToRad(deg));}static double tand(double deg) {return tan(degToRad(deg));}// 包装函数来避免直接使用库函数指针static double log_wrapper(double x) {return log(x);}static double log10_wrapper(double x) {return log10(x);}static double exp_wrapper(double x) {return exp(x);}static double sqrt_wrapper(double x) {return sqrt(x);}static double abs_wrapper(double x) {return fabs(x);}static double sin_wrapper(double x) {return sin(x);}static double cos_wrapper(double x) {return cos(x);}static double tan_wrapper(double x) {return tan(x);}static double ceil_wrapper(double x) {return ceil(x);}static double floor_wrapper(double x) {return floor(x);}void initFunctions() {// 注册科学计算函数(使用包装函数)functions["sin"] = sin_wrapper;functions["cos"] = cos_wrapper;functions["tan"] = tan_wrapper;// 注册角度版本的三角函数functions["sind"] = sind;functions["cosd"] = cosd;functions["tand"] = tand;// 其他数学函数(使用包装函数)functions["sqrt"] = sqrt_wrapper;functions["log"] = log_wrapper;functions["log10"] = log10_wrapper;  // 重点修复functions["exp"] = exp_wrapper;functions["abs"] = abs_wrapper;functions["ceil"] = ceil_wrapper;functions["floor"] = floor_wrapper;// 角度转换函数functions["deg2rad"] = degToRad;functions["rad2deg"] = radToDeg;}// 词法分析器vector<Token> tokenize(const string& expression) {vector<Token> tokens;string current = "";for (size_t i = 0; i < expression.length(); i++) {char c = expression[i];if (isspace(c)) {continue;}if (isdigit(c) || c == '.') {current += c;} else {// 如果当前有数字,先处理数字if (!current.empty()) {double num = atof(current.c_str());tokens.push_back(Token(NUMBER, current, num));current = "";}// 处理操作符和特殊字符if (c == '+' || c == '-' || c == '*' || c == '/' || c == '^') {// 检查是否是幂运算符 **if (c == '*' && i + 1 < expression.length() && expression[i + 1] == '*') {tokens.push_back(Token(OPERATOR, "**"));i++; // 跳过下一个 *} else {string op(1, c);tokens.push_back(Token(OPERATOR, op));}} else if (c == '(') {tokens.push_back(Token(LEFT_PAREN, "("));} else if (c == ')') {tokens.push_back(Token(RIGHT_PAREN, ")"));} else if (isalpha(c)) {// 处理函数名(支持包含数字的函数名如log10)string funcName = "";while (i < expression.length() && (isalpha(expression[i]) || isdigit(expression[i]))) {funcName += expression[i];i++;}i--; // 回退一位,因为for循环会自增if (functions.find(funcName) != functions.end()) {tokens.push_back(Token(FUNCTION, funcName));} else {cout << "未知函数: " << funcName << endl;return vector<Token>(); // 返回空向量表示错误}} else {// 遇到不支持的字符,给出相应提示if (c < 0 || c > 127) {cout << "警告: 忽略特殊字符(可能是°符号)" << endl;cout << "提示: 请使用角度函数 sind(), cosd(), tand() 代替°符号" << endl;} else {cout << "警告: 忽略不支持的字符 '" << c << "'" << endl;}}}}// 处理最后的数字if (!current.empty()) {double num = atof(current.c_str());tokens.push_back(Token(NUMBER, current, num));}return tokens;}// 中缀转后缀(调度场算法)vector<Token> infixToPostfix(const vector<Token>& tokens) {vector<Token> output;stack<Token> operators;for (size_t i = 0; i < tokens.size(); i++) {const Token& token = tokens[i];switch (token.type) {case NUMBER:output.push_back(token);break;case FUNCTION:operators.push(token);break;case OPERATOR: {while (!operators.empty() && operators.top().type != LEFT_PAREN &&((operators.top().type == FUNCTION) ||(operators.top().type == OPERATOR &&((operatorPrecedence[operators.top().value] > operatorPrecedence[token.value]) ||(operatorPrecedence[operators.top().value] == operatorPrecedence[token.value] &&rightAssociative.find(token.value) == rightAssociative.end()))))) {output.push_back(operators.top());operators.pop();}operators.push(token);break;}case LEFT_PAREN:operators.push(token);break;case RIGHT_PAREN:while (!operators.empty() && operators.top().type != LEFT_PAREN) {output.push_back(operators.top());operators.pop();}if (!operators.empty() && operators.top().type == LEFT_PAREN) {operators.pop(); // 移除左括号}// 如果栈顶是函数,也要弹出if (!operators.empty() && operators.top().type == FUNCTION) {output.push_back(operators.top());operators.pop();}break;}}// 弹出剩余的操作符while (!operators.empty()) {output.push_back(operators.top());operators.pop();}return output;}// 计算后缀表达式double evaluatePostfix(const vector<Token>& postfix) {stack<double> values;for (size_t i = 0; i < postfix.size(); i++) {const Token& token = postfix[i];switch (token.type) {case NUMBER:values.push(token.numValue);break;case OPERATOR: {if (values.size() < 2) {throw runtime_error("表达式错误:操作符缺少操作数");}double b = values.top(); values.pop();double a = values.top(); values.pop();double result = 0;if (token.value == "+") {result = a + b;} else if (token.value == "-") {result = a - b;} else if (token.value == "*") {result = a * b;} else if (token.value == "/") {if (b == 0) {throw runtime_error("除零错误");}result = a / b;} else if (token.value == "^" || token.value == "**") {result = pow(a, b);}values.push(result);break;}case FUNCTION: {if (values.empty()) {throw runtime_error("表达式错误:函数缺少参数");}double arg = values.top(); values.pop();// 添加调试信息cout << "正在计算函数: " << token.value << "(" << arg << ")" << endl;if (functions.find(token.value) == functions.end()) {throw runtime_error("未知函数: " + token.value);}double result = functions[token.value](arg);cout << "结果: " << result << endl;values.push(result);break;}default:break;}}if (values.size() != 1) {throw runtime_error("表达式错误");}return values.top();}public:Calculator() {initOperators();initFunctions();}// 主要的计算函数double calculate(const string& expression) {// 1. 词法分析vector<Token> tokens = tokenize(expression);if (tokens.empty()) {throw runtime_error("无效的表达式");}// 调试:显示词法分析结果cout << "词法分析结果: ";for (size_t i = 0; i < tokens.size(); i++) {cout << "[" << tokens[i].value << "] ";}cout << endl;// 2. 中缀转后缀vector<Token> postfix = infixToPostfix(tokens);// 3. 计算后缀表达式return evaluatePostfix(postfix);}// 显示中缀转后缀的过程void showInfixToPostfix(const string& expression) {cout << "原始表达式: " << expression << endl;vector<Token> tokens = tokenize(expression);cout << "词法分析结果: ";for (size_t i = 0; i < tokens.size(); i++) {cout << tokens[i].value << " ";}cout << endl;vector<Token> postfix = infixToPostfix(tokens);cout << "后缀表达式: ";for (size_t i = 0; i < postfix.size(); i++) {cout << postfix[i].value << " ";}cout << endl;}// 显示支持的函数列表void showSupportedFunctions() {cout << "\n支持的科学计算函数:" << endl;cout << "=== 三角函数(弧度) ===" << endl;cout << "sin(x)   - 正弦函数(x为弧度)" << endl;cout << "cos(x)   - 余弦函数(x为弧度)" << endl;cout << "tan(x)   - 正切函数(x为弧度)" << endl;cout << "\n=== 三角函数(角度) ===" << endl;cout << "sind(x)  - 正弦函数(x为角度)" << endl;cout << "cosd(x)  - 余弦函数(x为角度)" << endl;cout << "tand(x)  - 正切函数(x为角度)" << endl;cout << "\n=== 其他数学函数 ===" << endl;cout << "sqrt(x)  - 平方根" << endl;cout << "log(x)   - 自然对数" << endl;cout << "log10(x) - 常用对数" << endl;cout << "exp(x)   - 指数函数" << endl;cout << "abs(x)   - 绝对值" << endl;cout << "ceil(x)  - 向上取整" << endl;cout << "floor(x) - 向下取整" << endl;cout << "\n=== 角度转换函数 ===" << endl;cout << "deg2rad(x) - 角度转弧度" << endl;cout << "rad2deg(x) - 弧度转角度" << endl;cout << "\n支持的操作符: +, -, *, /, ^, ** (幂运算)" << endl;cout << "支持括号: ( )" << endl;cout << "\n使用示例:" << endl;cout << "sind(30)     → 0.5 (30度的正弦值)" << endl;cout << "cosd(60)     → 0.5 (60度的余弦值)" << endl;cout << "sin(deg2rad(30)) → 0.5 (先转弧度再计算)" << endl;}
};int main() {Calculator calc;string input;cout << "=== 简易计算器 (C++98兼容版) ===" << endl;cout << "输入 'help' 查看支持的函数" << endl;cout << "输入 'demo' 查看中缀转后缀演示" << endl;cout << "输入 'quit' 退出程序" << endl;cout << "\n重要提示:" << endl;cout << "? 角度计算请使用: sind(30), cosd(60), tand(45)" << endl;cout << "? 弧度计算请使用: sin(1.57), cos(3.14), tan(0.78)" << endl;cout << "? 不支持°符号,请直接输入数字" << endl;cout << "? 编译时请使用: g++ calculator.cpp -o calculator -lm" << endl;cout << "=================================" << endl;while (true) {cout << "\n请输入表达式: ";getline(cin, input);if (input == "quit" || input == "exit") {cout << "谢谢使用!" << endl;break;}if (input == "help") {calc.showSupportedFunctions();continue;}if (input == "demo") {cout << "\n=== 中缀转后缀演示 ===" << endl;calc.showInfixToPostfix("3 + 4 * 2 / ( 1 - 5 ) ^ 2");calc.showInfixToPostfix("sind(30) + cosd(60)");calc.showInfixToPostfix("sqrt(16) + log10(100)");cout << "\n=== 角度vs弧度计算演示 ===" << endl;cout << "sind(30) = " << calc.calculate("sind(30)") << " (30度的正弦值)" << endl;cout << "sin(30)  = " << calc.calculate("sin(30)") << " (30弧度的正弦值)" << endl;cout << "cosd(60) = " << calc.calculate("cosd(60)") << " (60度的余弦值)" << endl;cout << "cos(60)  = " << calc.calculate("cos(60)") << " (60弧度的余弦值)" << endl;cout << "sin(deg2rad(30)) = " << calc.calculate("sin(deg2rad(30))") << " (先转弧度)" << endl;continue;}if (input.empty()) {continue;}try {double result = calc.calculate(input);cout << "结果: " << fixed << setprecision(6) << result << endl;} catch (const exception& e) {cout << "错误: " << e.what() << endl;}}return 0;
}

七、总结与扩展思考

通过这个项目,我们深入学习了表达式求值的完整实现过程,掌握了从词法分析语法解析再到求值计算的核心技术。这个计算器不仅是一个实用的工具,更是理解编译原理算法设计的绝佳实践。

主要技术收获:

  • 深入理解了调度场算法的工作原理
  • 掌握了词法分析器的设计与实现
  • 学会了使用函数指针映射实现动态调用
  • 体验了面向对象设计的封装和扩展性

可能的扩展方向:

  • 支持变量定义表达式存储
  • 添加矩阵运算复数计算
  • 实现图形化界面Web版本
  • 支持自定义函数定义和脚本执行

这个项目为我们打开了计算机语言处理的大门,无论是后续学习编译器设计,还是开发更复杂的数学计算工具,都有着重要的参考价值。

创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊)

·

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

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

相关文章

WPF八大法则:告别模态窗口卡顿

⚙️ 核心问题&#xff1a;阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程&#xff0c;导致后续逻辑无法执行&#xff1a; var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题&#xff1a…

UOS无法安装deb软件包

UOS无法安装deb软件包 问题描述解决办法: 关闭安全中心的应用隔离结果验证 问题描述 UOS安装Linux微信的deb包时&#xff0c;无法正常安装 解决办法: 关闭安全中心的应用隔离 要关闭-安全中心的应用隔离后才可以正常软件和运行。 应用安全----》 允许任意应用。 结果验证 # …

鸿蒙jsonToArkTS_工具exe版本来了

前言导读 相信大家在学习鸿蒙开发过程中最痛苦的就是编写model 类 特别是那种复杂的json的时候对不对&#xff0c; 这时候有一个自动化的工具给你生成model是不是很开心。我们今天要分享的就是这个工具 JsonToArkTs 的用法 工具地址 https://gitee.com/qiuyu123/jsontomodel…

【Java算法】八大排序

八大排序算法 目录 注意&#xff1a;以下排序均属于内部排序 &#xff08;1&#xff09;插入排序 直接插入排序 改进版本 折半插入排序 希尔排序 &#xff08;2&#xff09;交换排序 冒泡排序 快速排序 &#xff08;3&#xff09;选择排序 简单选择排序 堆排序&…

玩转Docker | 使用Docker部署Qwerty Learner英语单词学习网站

玩转Docker | 使用Docker部署Qwerty Learner英语单词学习网站 前言一、Qwerty Learner简介Qwerty Learner 简介主要特点二、系统要求环境要求环境检查Docker版本检查检查操作系统版本三、部署Qwerty Learner服务下载Qwerty Learner镜像编辑部署文件创建容器检查容器状态检查服务…

Vue3中computed和watch的区别

文章目录 前言&#x1f50d; 一、computed vs watch✅ 示例对比1. computed 示例&#xff08;适合模板绑定、衍生数据&#xff09;2. watch 示例&#xff08;副作用&#xff0c;如调用接口&#xff09; &#x1f9e0; 二、源码实现原理&#xff08;简化理解&#xff09;1. comp…

C++修炼:C++11(二)

Hello大家好&#xff01;很高兴我们又见面啦&#xff01;给生活添点passion&#xff0c;开始今天的编程之路&#xff01; 我的博客&#xff1a;<但凡. 我的专栏&#xff1a;《编程之路》、《数据结构与算法之美》、《题海拾贝》、《C修炼之路》 欢迎点赞&#xff0c;关注&am…

单元测试与QTestLib框架使用

一.单元测试的意义 在软件开发中&#xff0c;单元测试是指对软件中最小可测试单元&#xff08;通常是函数、类的方法&#xff09;进行隔离的、可重复的验证。进行单元测试具有以下重要意义&#xff1a; 1.提升代码质量与可靠性&#xff1a; 早期错误检测&#xff1a; 在开发…

(附实现代码)Step-Back 回答回退策略扩大检索范围

1. LangChain 少量示例提示模板 在与 LLM 的对话中&#xff0c;提供少量的示例被称为 少量示例&#xff0c;这是一种简单但强大的指导生成的方式&#xff0c;在某些情况下可以显著提高模型性能&#xff08;与之对应的是零样本&#xff09;&#xff0c;少量示例可以降低 Prompt…

16-Oracle 23 ai-JSON-Relational Duality-知识准备

一直做DBA的小伙伴&#xff0c;是不是对开发相对陌生一些。JSON 关系二元性是 Oracle Database 23ai 中重要的特性&#xff0c;同时带来的是范式革命。JSON关系二元性解决了数据库领域的根本矛盾​&#xff0c;结构化数据的严谨性与半结构化数据的灵活性之间的矛盾。 JSON Rela…

什么是预训练?深入解读大模型AI的“高考集训”

1. 预训练的通俗理解&#xff1a;AI的“高考集训” 我们可以将预训练&#xff08;Pre-training&#xff09; 形象地理解为大模型AI的“高考集训”。就像学霸在高考前需要刷五年高考三年模拟一样&#xff0c;大模型在正式诞生前&#xff0c;也要经历一场声势浩大的“题海战术”…

思尔芯携手Andes晶心科技,加速先进RISC-V 芯片开发

在RISC-V生态快速发展和应用场景不断拓展的背景下&#xff0c;芯片设计正面临前所未有的复杂度挑战。近日&#xff0c;RISC-V处理器核领先厂商Andes晶心科技与思尔芯&#xff08;S2C&#xff09;达成重要合作&#xff0c;其双核单集群AX45MPV处理器已在思尔芯最新一代原型验证系…

vscode配置lua

官网下载lua得到如下 打开vscode的扩展下载如下三个 打开vscode的此处设置 搜索 executorMap&#xff0c;并添加如下内容

理解 RAG_HYBRID_BM25_WEIGHT:打造更智能的混合检索增强生成系统

目录 理解 RAG_HYBRID_BM25_WEIGHT&#xff1a;打造更智能的混合检索增强生成系统 一、什么是 Hybrid RAG&#xff1f; 二、什么是 RAG_HYBRID_BM25_WEIGHT&#xff1f; 三、参数设置示例 四、什么时候该调整它&#xff1f; 五、实战建议 六、总结 理解 RAG_HYBRID_BM25…

Spring Boot 2 中 default-autowire 的使用

Spring Boot 2 中 default-autowire 的使用 在 Spring Boot 2 中&#xff0c;default-autowire 这个来自传统 XML 配置的概念仍然存在&#xff0c;但它的使用已经大大减少&#xff0c;因为现代 Spring Boot 应用主要使用注解驱动的配置方式。 default-autowire 在 Spring Boo…

Spring Boot + Thymeleaf 防重复提交

在 Spring Boot 与 Thymeleaf 结合的 Web 应用中&#xff0c;防止重复提交可以采用token 机制 客户端禁用按钮的方式实现&#xff0c;在高并发场景下&#xff0c;考虑使用 Redis 存储 token 而非 Session。 第一步&#xff1a;后端实现 Controller public class FormControl…

【20250607接单】Spark + Scala + IntelliJ 项目的开发环境配置从零教学

本教程适用于零基础、一台刚装好 Windows 的全新电脑开始&#xff0c;搭建能运行 Spark Scala IntelliJ 项目的开发环境。以下是超详细、小白级别逐步教程&#xff0c;从“下载什么”到“点击哪里”都帮你列清楚。 &#x1f3af; 目标 操作系统&#xff1a;Windows10/11工具…

【ubuntu】虚拟机安装配置,sh脚本自动化,包含 apt+时间同步+docker+mysql+redis+pgsql

可以说是ubuntu基础环境搭建合集&#xff0c;个人学习用&#xff0c;使用sh一键安装&#xff0c;避免复制各种命令 流程主要包括 0. 可选择不同ubuntu版本对应安装&#xff08;支持 Ubuntu 20.04/22.04/23.04/24.04&#xff09; 1. apt换源aliyun 2. 时间选择上海时区&#x…

Rust 学习笔记:关于智能指针的练习题

Rust 学习笔记&#xff1a;关于智能指针的练习题 Rust 学习笔记&#xff1a;关于智能指针的练习题问题一问题二问题三问题四问题五问题六问题七问题八问题九问题十问题十一 Rust 学习笔记&#xff1a;关于智能指针的练习题 参考视频&#xff1a; https://www.bilibili.com/vi…

JavaScript ES6 解构:优雅提取数据的艺术

JavaScript ES6 解构&#xff1a;优雅提取数据的艺术 在 JavaScript 的世界中&#xff0c;ES6&#xff08;ECMAScript 2015&#xff09;的推出为开发者带来了许多革命性的特性&#xff0c;其中“解构赋值”&#xff08;Destructuring Assignment&#xff09;无疑是最受欢迎的功…