当前位置: 首页 > 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…...

JVM垃圾回收机制全解析

Java虚拟机&#xff08;JVM&#xff09;中的垃圾收集器&#xff08;Garbage Collector&#xff0c;简称GC&#xff09;是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象&#xff0c;从而释放内存空间&#xff0c;避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

2021-03-15 iview一些问题

1.iview 在使用tree组件时&#xff0c;发现没有set类的方法&#xff0c;只有get&#xff0c;那么要改变tree值&#xff0c;只能遍历treeData&#xff0c;递归修改treeData的checked&#xff0c;发现无法更改&#xff0c;原因在于check模式下&#xff0c;子元素的勾选状态跟父节…...

解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错

出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上&#xff0c;所以报错&#xff0c;到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本&#xff0c;cu、torch、cp 的版本一定要对…...

零基础设计模式——行为型模式 - 责任链模式

第四部分&#xff1a;行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习&#xff01;行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想&#xff1a;使多个对象都有机会处…...

Java数值运算常见陷阱与规避方法

整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...

在 Spring Boot 项目里,MYSQL中json类型字段使用

前言&#xff1a; 因为程序特殊需求导致&#xff0c;需要mysql数据库存储json类型数据&#xff0c;因此记录一下使用流程 1.java实体中新增字段 private List<User> users 2.增加mybatis-plus注解 TableField(typeHandler FastjsonTypeHandler.class) private Lis…...

vue3 daterange正则踩坑

<el-form-item label"空置时间" prop"vacantTime"> <el-date-picker v-model"form.vacantTime" type"daterange" start-placeholder"开始日期" end-placeholder"结束日期" clearable :editable"fal…...

Windows电脑能装鸿蒙吗_Windows电脑体验鸿蒙电脑操作系统教程

鸿蒙电脑版操作系统来了&#xff0c;很多小伙伴想体验鸿蒙电脑版操作系统&#xff0c;可惜&#xff0c;鸿蒙系统并不支持你正在使用的传统的电脑来安装。不过可以通过可以使用华为官方提供的虚拟机&#xff0c;来体验大家心心念念的鸿蒙系统啦&#xff01;注意&#xff1a;虚拟…...

2025年低延迟业务DDoS防护全攻略:高可用架构与实战方案

一、延迟敏感行业面临的DDoS攻击新挑战 2025年&#xff0c;金融交易、实时竞技游戏、工业物联网等低延迟业务成为DDoS攻击的首要目标。攻击呈现三大特征&#xff1a; AI驱动的自适应攻击&#xff1a;攻击流量模拟真实用户行为&#xff0c;差异率低至0.5%&#xff0c;传统规则引…...

门静脉高压——表现

一、门静脉高压表现 00:01 1. 门静脉构成 00:13 组成结构&#xff1a;由肠系膜上静脉和脾静脉汇合构成&#xff0c;是肝脏血液供应的主要来源。淤血后果&#xff1a;门静脉淤血会同时导致脾静脉和肠系膜上静脉淤血&#xff0c;引发后续系列症状。 2. 脾大和脾功能亢进 00:46 …...