当前位置: 首页 > news >正文

Rust 重载运算符|复数结构的“加减乘除”四则运算

eb88291a18a94ba4ace118fb4e46ef23.png

复数

基本概念

复数定义

由实数部分和虚数部分所组成的数,形如a+bi 。

其中a、b为实数,i 为“虚数单位”,i² = -1,即虚数单位的平方等于-1。

a、b分别叫做复数a+bi的实部和虚部。

当b=0时,a+bi=a 为实数;
当b≠0时,a+bi 又称虚数;
当b≠0、a=0时,bi 称为纯虚数。

实数和虚数都是复数的子集。如同实数可以在数轴上表示一样复数也可以在平面上表示,复数x+yi以坐标点(x,y)来表示。表示复数的平面称为“复平面”。

复数相等

两个复数不能比较大小,但当个两个复数的实部和虚部分别相等时,即表示两个复数相等。

共轭复数

如果两个复数的实部相等,虚部互为相反数,那么这两个复数互为共轭复数。

复数的模

复数的实部与虚部的平方和的正的平方根的值称为该复数的模,数学上用与绝对值“|z|”相同的符号来表示。虽然从定义上是不相同的,但两者的物理意思都表示“到原点的距离”。

复数的四则运算

加法(减法)法则

复数的加法法则:设z1=a+bi,z2 =c+di是任意两个复数。两者和的实部是原来两个复数实部的和,它的虚部是原来两个虚部的和。两个复数的和依然是复数。

即(a+bi)±(c+di)=(a±c)+(b±d)

乘法法则

复数的乘法法则:把两个复数相乘,类似两个多项式相乘,结果中i²=-1,把实部与虚部分别合并。两个复数的积仍然是一个复数。

即(a+bi)(c+di)=(ac-bd)+(bc+ad)i

除法法则

复数除法法则:满足(c+di)(x+yi)=(a+bi)的复数x+yi(x,y∈R)叫复数a+bi除以复数c+di的商。

运算方法:可以把除法换算成乘法做,将分子分母同时乘上分母的共轭复数,再用乘法运算。

即(a+bi)/(c+di)=(a+bi)(c-di)/(c*c+d*d)=[(ac+bd)+(bc-ad)i]/(c*c+d*d)

复数的Rust代码实现

结构定义

Rust语言中,没有像python一样内置complex复数数据类型,我们可以用两个浮点数分别表示复数的实部和虚部,自定义一个结构数据类型,表示如下:

struct Complex {
    real: f64,
    imag: f64,
}

示例代码:

#[derive(Debug)]
struct Complex {real: f64,imag: f64,
}impl Complex {  fn new(real: f64, imag: f64) -> Self {Complex { real, imag }  }
}fn main() {  let z = Complex::new(3.0, 4.0);println!("{:?}", z);println!("{} + {}i", z.real, z.imag);
}

注意:#[derive(Debug)] 自动定义了复数结构的输出格式,如以上代码输出如下:

Complex { real: 3.0, imag: 4.0 }
3 + 4i

重载四则运算

复数数据结构不能直接用加减乘除来做复数运算,需要导入标准库ops的运算符:

use std::ops::{Add, Sub, Mul, Div, Neg};

Add, Sub, Mul, Div, Neg 分别表示加减乘除以及相反数,类似C++或者python语言中“重载运算符”的概念。

根据复数的运算法则,写出对应代码:

fn add(self, other: Complex) -> Complex {
    Complex {
        real: self.real + other.real,
        imag: self.imag + other.imag,
    }  
}  

fn sub(self, other: Complex) -> Complex {
    Complex {  
        real: self.real - other.real,
        imag: self.imag - other.imag,
    }  

fn mul(self, other: Complex) -> Complex {  
    let real = self.real * other.real - self.imag * other.imag;
    let imag = self.real * other.imag + self.imag * other.real;
    Complex { real, imag }  
}  

fn div(self, other: Complex) -> Complex {
    let real = (self.real * other.real + self.imag * other.imag) / (other.real * other.real + other.imag * other.imag);
    let imag = (self.imag * other.real - self.real * other.imag) / (other.real * other.real + other.imag * other.imag);
    Complex { real, imag }
}

fn neg(self) -> Complex {
    Complex {
        real: -self.real,
        imag: -self.imag,
    }
}

Rust 重载运算的格式,请见如下示例代码:

use std::ops::{Add, Sub, Mul, Div, Neg};#[derive(Clone, Debug, PartialEq)]
struct Complex {real: f64,imag: f64,
}impl Complex {  fn new(real: f64, imag: f64) -> Self {Complex { real, imag }  }fn conj(&self) -> Self {Complex { real: self.real, imag: -self.imag }}fn abs(&self) -> f64 {(self.real * self.real + self.imag * self.imag).sqrt()}
}fn abs(z: Complex) -> f64 {(z.real * z.real + z.imag * z.imag).sqrt()
}impl Add<Complex> for Complex {type Output = Complex;fn add(self, other: Complex) -> Complex {Complex {real: self.real + other.real,imag: self.imag + other.imag,}  }  
}  impl Sub<Complex> for Complex {type Output = Complex;fn sub(self, other: Complex) -> Complex {Complex {  real: self.real - other.real,imag: self.imag - other.imag,}  } 
}  impl Mul<Complex> for Complex {type Output = Complex;  fn mul(self, other: Complex) -> Complex {  let real = self.real * other.real - self.imag * other.imag;let imag = self.real * other.imag + self.imag * other.real;Complex { real, imag }  }  
}impl Div<Complex> for Complex {type Output = Complex;fn div(self, other: Complex) -> Complex {let real = (self.real * other.real + self.imag * other.imag) / (other.real * other.real + other.imag * other.imag);let imag = (self.imag * other.real - self.real * other.imag) / (other.real * other.real + other.imag * other.imag);Complex { real, imag }}
}  impl Neg for Complex {type Output = Complex;fn neg(self) -> Complex {Complex {real: -self.real,imag: -self.imag,}}
}fn main() {  let z1 = Complex::new(2.0, 3.0);let z2 = Complex::new(3.0, 4.0);let z3 = Complex::new(3.0, -4.0);// 复数的四则运算let complex_add = z1.clone() + z2.clone();println!("{:?} + {:?} = {:?}", z1, z2, complex_add);let complex_sub = z1.clone() - z2.clone();println!("{:?} - {:?} = {:?}", z1, z2, complex_sub);let complex_mul = z1.clone() * z2.clone();println!("{:?} * {:?} = {:?}", z1, z2, complex_mul);let complex_div = z2.clone() / z3.clone();println!("{:?} / {:?} = {:?}", z1, z2, complex_div);// 对比两个复数是否相等println!("{:?}", z1 == z2);// 共轭复数println!("{:?}", z2 == z3.conj());// 复数的相反数println!("{:?}", z2 == -z3.clone() + Complex::new(6.0,0.0));// 复数的模println!("{}", z1.abs());println!("{}", z2.abs());println!("{}", abs(z3));
}

输出:

Complex { real: 2.0, imag: 3.0 } + Complex { real: 3.0, imag: 4.0 } = Complex { real: 5.0, imag: 7.0 }
Complex { real: 2.0, imag: 3.0 } - Complex { real: 3.0, imag: 4.0 } = Complex { real: -1.0, imag: -1.0 }
Complex { real: 2.0, imag: 3.0 } * Complex { real: 3.0, imag: 4.0 } = Complex { real: -6.0, imag: 17.0 }
Complex { real: 2.0, imag: 3.0 } / Complex { real: 3.0, imag: 4.0 } = Complex { real: -0.28, imag: 0.96 }
false
true
true
3.605551275463989
5
5

示例代码中,同时还定义了复数的模 abs(),共轭复数 conj()。

两个复数的相等比较 z1 == z2,需要 #[derive(PartialEq)] 支持。

自定义 trait Display

复数结构的原始 Debug trait 表达的输出格式比较繁复,如:

Complex { real: 2.0, imag: 3.0 } + Complex { real: 3.0, imag: 4.0 } = Complex { real: 5.0, imag: 7.0 }

想要输出和数学中相同的表达(如 a + bi),需要自定义一个 Display trait,代码如下:

impl std::fmt::Display for Complex {
    fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        if self.imag == 0.0 {
            formatter.write_str(&format!("{}", self.real))
        } else {
            let (abs, sign) = if self.imag > 0.0 {  
                (self.imag, "+" )
            } else {
                (-self.imag, "-" )
            };
            if abs == 1.0 {
                formatter.write_str(&format!("({} {} i)", self.real, sign))
            } else {
                formatter.write_str(&format!("({} {} {}i)", self.real, sign, abs))
            }
        }
    }
}

输出格式分三种情况:虚部为0,正数和负数。另外当虚部绝对值为1时省略1仅输出i虚数单位。

完整代码如下:

use std::ops::{Add, Sub, Mul, Div, Neg};#[derive(Clone, PartialEq)]
struct Complex {real: f64,imag: f64,
}impl std::fmt::Display for Complex {fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {if self.imag == 0.0 {formatter.write_str(&format!("{}", self.real))} else {let (abs, sign) = if self.imag > 0.0 {  (self.imag, "+" )} else {(-self.imag, "-" )};if abs == 1.0 {formatter.write_str(&format!("({} {} i)", self.real, sign))} else {formatter.write_str(&format!("({} {} {}i)", self.real, sign, abs))}}}
}impl Complex {  fn new(real: f64, imag: f64) -> Self {Complex { real, imag }  }fn conj(&self) -> Self {Complex { real: self.real, imag: -self.imag }}fn abs(&self) -> f64 {(self.real * self.real + self.imag * self.imag).sqrt()}
}fn abs(z: Complex) -> f64 {(z.real * z.real + z.imag * z.imag).sqrt()
}impl Add<Complex> for Complex {type Output = Complex;fn add(self, other: Complex) -> Complex {Complex {real: self.real + other.real,imag: self.imag + other.imag,}  }  
}  impl Sub<Complex> for Complex {type Output = Complex;fn sub(self, other: Complex) -> Complex {Complex {  real: self.real - other.real,imag: self.imag - other.imag,}  } 
}  impl Mul<Complex> for Complex {type Output = Complex;  fn mul(self, other: Complex) -> Complex {  let real = self.real * other.real - self.imag * other.imag;let imag = self.real * other.imag + self.imag * other.real;Complex { real, imag }  }  
}impl Div<Complex> for Complex {type Output = Complex;fn div(self, other: Complex) -> Complex {let real = (self.real * other.real + self.imag * other.imag) / (other.real * other.real + other.imag * other.imag);let imag = (self.imag * other.real - self.real * other.imag) / (other.real * other.real + other.imag * other.imag);Complex { real, imag }}
}  impl Neg for Complex {type Output = Complex;fn neg(self) -> Complex {Complex {real: -self.real,imag: -self.imag,}}
}fn main() {let z1 = Complex::new(2.0, 3.0);let z2 = Complex::new(3.0, 4.0);let z3 = Complex::new(3.0, -4.0);// 复数的四则运算let complex_add = z1.clone() + z2.clone();println!("{} + {} = {}", z1, z2, complex_add);let z = Complex::new(1.5, 0.5);println!("{} + {} = {}", z, z, z.clone() + z.clone());let complex_sub = z1.clone() - z2.clone();println!("{} - {} = {}", z1, z2, complex_sub);let complex_sub = z1.clone() - z1.clone();println!("{} - {} = {}", z1, z1, complex_sub);let complex_mul = z1.clone() * z2.clone();println!("{} * {} = {}", z1, z2, complex_mul);let complex_mul = z2.clone() * z3.clone();println!("{} * {} = {}", z2, z3, complex_mul);let complex_div = z2.clone() / z3.clone();println!("{} / {} = {}", z1, z2, complex_div);let complex_div = Complex::new(1.0,0.0) / z2.clone();println!("1 / {} = {}", z2, complex_div);// 对比两个复数是否相等println!("{:?}", z1 == z2);// 共轭复数println!("{:?}", z2 == z3.conj());// 复数的相反数println!("{:?}", z2 == -z3.clone() + Complex::new(6.0,0.0));// 复数的模println!("{}", z1.abs());println!("{}", z2.abs());println!("{}", abs(z3));
}

输出:

(2 + 3i) + (3 + 4i) = (5 + 7i)
(1.5 + 0.5i) + (1.5 + 0.5i) = (3 + i)
(2 + 3i) - (3 + 4i) = (-1 - i)
(2 + 3i) - (2 + 3i) = 0
(2 + 3i) * (3 + 4i) = (-6 + 17i)
(3 + 4i) * (3 - 4i) = 25
(2 + 3i) / (3 + 4i) = (-0.28 + 0.96i)
1 / (3 + 4i) = (0.12 - 0.16i)
false
true
true
3.605551275463989
5
5


小结

如此,复数的四则运算基本都实现了,当然复数还有三角表示式和指数表示式,根据它们的数学定义写出相当代码应该不是很难。有了复数三角式,就能方便地定义出复数的开方运算,有空可以写写这方面的代码。

本文完

相关文章:

Rust 重载运算符|复数结构的“加减乘除”四则运算

复数 基本概念 复数定义 由实数部分和虚数部分所组成的数&#xff0c;形如a&#xff0b;bi 。 其中a、b为实数&#xff0c;i 为“虚数单位”&#xff0c;i -1&#xff0c;即虚数单位的平方等于-1。 a、b分别叫做复数a&#xff0b;bi的实部和虚部。 当b0时&#xff0c;a&…...

Oracle删除表空间

1.检查表空间状态 SELECT tablespace_name, status FROM dba_tablespaces;备注&#xff1a;tablespace_name表示删除表空间的名称&#xff0c;status为表空间的状态。如果状态为ONLINE&#xff0c;表示表空间当前正在使用&#xff0c;不能被删除。 2.关闭表空间 ALTER TABLE…...

Mysql - 配置Mysql主从复制-keepalived高可用-读写分离集群

目录 高可用&#xff1a; 为什么需要高可用呢&#xff1f; 高可用的主要作用&#xff1a; keepalived是什么&#xff1f;它用在哪里&#xff1f; 什么是VRRP协议&#xff0c;它的作用是什么&#xff1f; 搭建一个基于keepalived的高可用Mysql主从复制读写分离集群 一、项…...

Qt QLineEdit输入时限制,采用正则表达式

QLineEdit 正则 序言使用方法正则表达式使用例子 序言 老是有人在群里问这个&#xff0c;所以我干脆写一篇方便予人查看&#xff0c;很简单的小功能。 使用方法 Qt5 #include <QRegExpValidator> //#include "qvalidator.h"ui->lineEdit->setValida…...

【CSS】文本效果

文本溢出、整字换行、换行规则以及书写模式 代码&#xff1a; <style> p.test1 {white-space: nowrap; width: 200px; border: 1px solid #000000;overflow: hidden;text-overflow: clip; }p.test2 {white-space: nowrap; width: 200px; border: 1px solid #000000;ove…...

Django快速上手,写一个简单的页面,快来看看吧~

还没有安装Django&#xff0c;以及不会创建Django项目的小伙伴&#xff0c;可以先看看博主这篇文章&#xff1a;http://t.csdn.cn/Ly7yM 目录 1、项目创建完成后&#xff0c;需要注意的点&#xff1a; 2、创建app 3、app的各个目录的作用 4、快速上手 4.1、注册app 4.2、U…...

【Express.js】数据库初始化

数据库初始化 在软件开发阶段和测试阶段&#xff0c;为了方便调试&#xff0c;我们通常会进行一系列的数据库初始化操作&#xff0c;比如重置数据表&#xff0c;插入记录等等&#xff0c;或者在部署阶段进行数据初始化的操作 根据前面章节介绍过的 knex.js 和 sequelize.js&…...

【数理知识】三维空间旋转矩阵的欧拉角表示法,四元数表示法,两者之间的转换,Matlab 代码实现

序号内容1【数理知识】自由度 degree of freedom 及自由度的计算方法2【数理知识】刚体 rigid body 及刚体的运动3【数理知识】刚体基本运动&#xff0c;平动&#xff0c;转动4【数理知识】向量数乘&#xff0c;内积&#xff0c;外积&#xff0c;matlab代码实现5【数理知识】最…...

【业务功能篇63】Springboot聊聊 过滤器和拦截器

过滤器的场景&#xff1a;过滤器通常用于对数据或资源进行筛选、修改或转换的场景。例如&#xff0c;在一个电子商务网站中&#xff0c;用户进行商品搜索时&#xff0c;你可以使用过滤器来过滤特定的商品类别、价格范围或其他条件&#xff0c;以便用户仅看到符合筛选条件的结果…...

提高学生学习效率的模拟考试系统

在如今竞争激烈的社会环境下&#xff0c;提高学生的学习效率显得尤为重要。为了帮助学生评估自己的学习水平并提供有针对性的学习建议&#xff0c;开发一款模拟考试系统是非常必要的。 一、学生信息录入 模拟考试系统首先需要学生信息录入功能。学生可以通过一个简单的表单填…...

解决QWebEngineView在linux下加载本地html失败的问题

通常我们使用QWebEngineView加载本地html文件时&#xff0c;是通过 void load(const QUrl &url) void setUrl(const QUrl &url) 两个函数&#xff0c;传入html的相对或绝对路径&#xff0c;进行加载。 而在linux(uos x86)下运行时&#xff0c;却发现加载失败&#xf…...

如何使用Redis实现内容推送功能

导读 在日常使用中&#xff0c;我们经常能看见内容推送功能。 常见的场景有&#xff0c;比如你在bilibili关注了某个up主&#xff0c;当up主发布视频后&#xff0c;就会推送到你的收件箱或者是动态中&#xff0c;让粉丝能够及时得知所关注的人发布了内容。 又比如朋友圈&…...

怎么对视频进行压缩?

怎么对视频进行压缩&#xff1f;视频压缩&#xff0c;我们都知道是将视频文件进行压缩变小的过程&#xff0c;是我们日常办公中较为常用的手段。现如今&#xff0c;在视频技术不断发展与创新的基础上&#xff0c;视频分辨率也在不断提高&#xff0c;进而导致文件占有量也非常大…...

redisson配置类---SpringBoot集成、redis单机和集群模式配置

1项目配置文件&#xff1a; 1.1&#xff1a;pom.xml <dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.17.7</version></dependency> 1.2 application.yml配置…...

瓴羊发布All in One 产品,零售SaaS的尽头是DaaS?

“打破烟囱、化繁为简&#xff0c;让丰富的能力、数据和智能All in One”&#xff0c;这是瓴羊新发布的产品瓴羊One承担的使命&#xff0c;也意味着瓴羊DaaS事业迈入了一个新阶段。 成立伊始&#xff0c;瓴羊就打出了“Not SaaS&#xff0c;But DaaS”旗号&#xff0c;将自己的…...

win10中Docker安装、构建镜像、创建容器、Vscode连接实例

Docker方便一键构建项目所需的运行环境&#xff1a;首先构建镜像(Image)。然后镜像实例化成为容器(Container)&#xff0c;构成项目的运行环境。最后Vscode连接容器&#xff0c;方便我们在本地进行开发。下面以一个简单的例子介绍在win10中实现&#xff1a;Docker安装、构建镜像…...

贝锐蒲公英:快速搭建连锁门店监控体系,赋能企业高效管理

随着国民生活水平的提高和零售场景的变革&#xff0c;消费者对于餐饮类目的消费支出不断增加&#xff0c;线下社区生鲜商超作为下沉市场最主要的消费场景之一&#xff0c;蕴藏着巨大价值机会。 对于线下连锁生鲜超市而言&#xff0c;连锁门店多、员工多&#xff0c;门店管理时会…...

c++ WinInet InternetOpenUrl下载中文文件

windows自带的WinInet,几个函数就可以实现http文件下载, 且可获取文件大小,进度条等。 在用WinInet下载文件时,遇到个问题, 如果是中文,下载下来的文件大小为0 英文文件正常,为什么呢? bool WWWFileBuffer(const char* host, const char* path, char* outBuffer, in…...

算法通过村第三关-数组青铜笔记|单调数组

文章目录 前言单调数组问题搜索插入位置&#xff1a;数组合并问题&#xff1a;总结 前言 提示&#xff1a;本份真诚面对自己、坦然无碍面对他人&#xff0c;就是优雅。 数组中的比较经典性问题: 单调数组问题数组合并问题 单调数组问题 参考例子&#xff1a;896. 单调数列…...

Springboot MultipartFile文件上传与下载

yml文件配置是否可以上传及上传附件大小 servlet:multipart:# 允许文件上传enabled: true# 单个文件大小max-file-size: 20MB# 设置总上传的文件大小max-request-size: 50MB /*** param files* param request* Description 上传文件* Throws* Return java.util.List* Date 202…...

基于大模型的 UI 自动化系统

基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

前端倒计时误差!

提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

如何在看板中体现优先级变化

在看板中有效体现优先级变化的关键措施包括&#xff1a;采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中&#xff0c;设置任务排序规则尤其重要&#xff0c;因为它让看板视觉上直观地体…...

YSYX学习记录(八)

C语言&#xff0c;练习0&#xff1a; 先创建一个文件夹&#xff0c;我用的是物理机&#xff1a; 安装build-essential 练习1&#xff1a; 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件&#xff0c;随机修改或删除一部分&#xff0c;之后…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现

摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序&#xff0c;以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务&#xff0c;提供稳定高效的数据处理与业务逻辑支持&#xff1b;利用 uniapp 实现跨平台前…...

C++.OpenGL (10/64)基础光照(Basic Lighting)

基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

腾讯云V3签名

想要接入腾讯云的Api&#xff0c;必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口&#xff0c;但总是卡在签名这一步&#xff0c;最后放弃选择SDK&#xff0c;这次终于自己代码实现。 可能腾讯云翻新了接口文档&#xff0c;现在阅读起来&#xff0c;清晰了很多&…...

Golang——7、包与接口详解

包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...

数学建模-滑翔伞伞翼面积的设计,运动状态计算和优化 !

我们考虑滑翔伞的伞翼面积设计问题以及运动状态描述。滑翔伞的性能主要取决于伞翼面积、气动特性以及飞行员的重量。我们的目标是建立数学模型来描述滑翔伞的运动状态,并优化伞翼面积的设计。 一、问题分析 滑翔伞在飞行过程中受到重力、升力和阻力的作用。升力和阻力与伞翼面…...

SpringAI实战:ChatModel智能对话全解

一、引言&#xff1a;Spring AI 与 Chat Model 的核心价值 &#x1f680; 在 Java 生态中集成大模型能力&#xff0c;Spring AI 提供了高效的解决方案 &#x1f916;。其中 Chat Model 作为核心交互组件&#xff0c;通过标准化接口简化了与大语言模型&#xff08;LLM&#xff0…...