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


小结

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

本文完

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

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

相关文章

利用python实现批量登录网络设备进行日常巡检

利用python实现批量登录网络设备 实现ensp与物理机互通ensp 配置配置网络设备远程登录 用python实现批量登录常见问题 通过阅读本文可以学习自动化运维相关知识&#xff0c;本文章代码可以直接使用&#xff0c;通过批量登录功能后&#xff0c;可以按照自己意愿进行功能更改与完…

OpenCV图像处理——边缘检测

目录 原理Sobel检测算子方法应用 Laplacian算子Canny边缘检测原理 原理 Sobel检测算子 方法 应用 sobel_x_or_ycv.Sobel(src,ddepth,dx,dy,dst,ksize,scale,delta,borderType)import numpy as np import cv2 as cv import matplotlib.pyplot as pltimgcv.imread(./汪学长的随堂…

无需停服!PostgreSQL数据迁移工具-NineData

PostgreSQL 是一种备受开发者和企业青睐的关系型数据库&#xff0c;其丰富的数据类型、地理空间负载和强大的扩展能力等特性使其备受欢迎。然而&#xff0c;在企业使用 PostgreSQL 承载应用的过程中&#xff0c;由于业务需要上云、跨云、下云、跨机房迁移、跨地域迁移、数据库版…

云上社群学习系统部分接口设计详解

目录 一、项目简介 二、技术选型 三、数据库设计 四、接口设计及思考 回复帖子部分 4.1 回复帖子 4.1.1.1 实现逻辑 4.1.1.2创建Service接⼝ 4.1.1.3 实现Service接⼝ 4.1.1.4 实现Controller 4.1.1.5 测试接口 4.1.1.6 实现前端页面 4.2 点赞帖子 4.2.1.1 参数要求…

【数据结构】堆的实现,堆排序以及TOP-K问题

目录 1.堆的概念及结构 2.堆的实现 2.1初始化堆 2.2销毁堆 2.3取堆顶元素 2.4返回堆的大小 2.5判断是否为空 2.6打印堆 2.7插入元素 2.8堆的向上调整 2.9弹出元素 2.10堆的向下调整 3. 建堆时间复杂度 4. 堆的应用 4.1 堆排序 4.2 TOP-K问题 1.堆的概念及结构 …

【Spring】统一事件的处理(拦截器、统一异常处理、统一数据格式返回)

文章目录 前言一、Spring 拦截器1.1 用户登录权限校验案例1.1.1 最初的用户登录验证1.1.2 使用 Spring AOP 实现登录验证的问题 1.2 Spring 拦截器的使用1.2.1 Spring 拦截器概念与使用步骤1.2.2 使用拦截器实现对用户登录权限的校验 1.3 拦截器实现原理1.4 Spring 拦截器和 Sp…

响应式设计是什么?怎么学习? - 易智编译EaseEditing

响应式设计是一种用于创建能够适应不同设备和屏幕尺寸的网站和应用程序的设计方法。它的目标是确保网站在各种设备上都能提供良好的用户体验&#xff0c;无论是在大屏幕的桌面电脑上还是在小屏幕的移动设备上。 在响应式设计中&#xff0c;页面的布局、字体、图像和其他元素会…

读《芯片浪潮》,学习台积电张忠谋的管理之道

大家知道&#xff0c;台积电一个公司就占据了全球晶圆代工市场一半的份额。 5纳米及以下最先进工艺的芯片&#xff0c;台积电可占到惊人的90%以上的市场。全球最新最强的智能手机、笔记本电脑的核心计算芯片都必须仰仗台积电一个企业的供应。 换一个说法&#xff0c;如果没有…

每天一道leetcode:剑指 Offer 12. 矩阵中的路径(中等DFS深度优先遍历)

今日份题目&#xff1a; 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 单词必须按照字母顺序&#xff0c;通过相邻的单元格内的字母构成&#xff0c;其中“相邻”单元…

62、华为昇腾开发板Atlas 200I DK A2配置mmpose的hrnet模型推理python/c++

基本思想&#xff1a;适配mmpose模型&#xff0c;记录一下流水帐&#xff0c;环境配置和模型来自&#xff0c;请查看参考链接。 链接: https://pan.baidu.com/s/1IkiwuZf1anyKX1sZkYmD1g?pwdi51s 提取码: i51s 一、转模型 (base) rootdavinci-mini:~/sxj731533730# atc --mo…

docker pull 设置代理 centos

On CentOS the configuration file for Docker is at: /etc/sysconfig/docker 用 root 权限打开 text editor sudo gedit 注意 加引号 Adding the below line helped me to get the Docker daemon working behind a proxy server: HTTP_PROXY“http://<proxy_host>:&…

C++ 动态规划经典案例解析之最长公共子序列(LCS)_窥探递归和动态规划的一致性

1. 前言 动态规划处理字符相关案例中&#xff0c;求最长公共子序列以及求最短编辑距离&#xff0c;算是经典中的经典案例。 讲解此类问题的算法在网上一抓应用一大把&#xff0c;即便如此&#xff0c;还是忍不住有写此文的想法。毕竟理解、看懂都不算是真正掌握&#xff0c;唯…

浅谈统一权限管理服务的设计与开发

作者 | 天地练心 导读 本文详细探讨了统一权限管理服务&#xff08;MPS&#xff09;的设计与开发&#xff0c;针对企业内部多平台权限管理混乱的问题&#xff0c;提出了一套综合RBAC、ACL、DAC权限模型的解决方案。文章从需求分析、技术选型、功能设计等方面全面介绍了MPS的构建…

阿里云ACP知识点

前言&#xff1a;记录ACP错题 1、在创建阿里云ECS时&#xff0c;每台服务器必须要包含_______用来存储操作系统和核心配置。 系统盘&#xff08;不是实例&#xff0c;实例是一个虚拟的计算环境&#xff0c;由CPU、内存、系统盘和运行的操作系统组成&#xff1b;ESC实例作为云…

2023国赛数学建模E题思路分析

文章目录 0 赛题思路1 竞赛信息2 竞赛时间3 建模常见问题类型3.1 分类问题3.2 优化问题3.3 预测问题3.4 评价问题 4 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 竞赛信息 全国大学生数学建模…

纯js点击按钮切换首页部分页面

像我这种大数据的&#xff0c;不会前端的&#xff0c;懒得学框架&#xff0c;现在有gpt了&#xff0c;前端对于我来说&#xff0c;用原生的更加友好&#xff0c;毕竟算法gpt都能优化。 首页我有个页面&#xff0c;然后我现在想点击gm替换上面的统计&#xff0c;点击用户替换回…

Flask Web开发实战(狼书)| 笔记第1、2章

前言 2023-8-11 以前对网站开发萌生了想法&#xff0c;又有些急于求成&#xff0c;在B站照着视频敲了一个基于flask的博客系统。但对于程序的代码难免有些囫囵吞枣&#xff0c;存在许多模糊或不太理解的地方&#xff0c;只会照葫芦画瓢。 而当自己想开发一个什么网站的时&…

SpringCloud微服务之间如何进行用户信息传递(涉及:Gateway、OpenFeign组件)

目录 1、想达到的效果2、用户信息在微服务之间传递的两种途径3、用RuoYi-Cloud为例进行演示说明&#xff08;1&#xff09;网关将用户信息写在请求头中&#xff08;2&#xff09;业务微服务之间通过OpenFeign进行调用&#xff0c;并且将用户信息写在OpenFeign准备的请求头中&am…

Qt+C++自定义控件仪表盘动画仿真

程序示例精选 QtC自定义控件仪表盘动画仿真 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对<<QtC自定义控件仪表盘动画仿真>>编写代码&#xff0c;代码整洁&#xff0c;规则&…

浅谈SMT行业MES系统生产管理的特点

一、SMT生产车间在电子制造中起重要作用的部分&#xff0c;主要具备以下生产特点&#xff1a; 1.高密度和高速度&#xff1a; SMT生产车间中的电子元器件一般来说较为精小&#xff0c;且被紧密地排列在PCB上。这就要求SMT生产车间的机械设备具备高精度和高速度&#xff0c;确保…