【C语言的小角落】--- 深度理解取余/取模运算

 Welcome to 9ilk's Code World

       

(๑•́ ₃ •̀๑) 个人主页:       9ilk

(๑•́ ₃ •̀๑) 文章专栏:     C语言的小角落 


本篇博客我们来深度理解取余/取模,以及它们在不同语言中出现不同现象的原因。


🏠 关于取整

🎵 向0取整

#include <stdio.h>
#include <windows.h>
int main()
{//本质是向0取整int i = -2.9;int j = 2.9;printf("%d\n", i); //结果是:-2printf("%d\n", j); //结果是:2int a = 5;int b = -5;printf("%d %d",a/2,b/2);system("pause");return 0;
}

测试结果:

我们发现测试结果中浮点数取整都是往0方向取整的:

其实在C库中有个trunc取整函数,也是向0取整:

🎵 向-∞取整

#include <stdio.h>
#include <math.h> //因为使用了floor函数,需要添加该头文件
#include <windows.h>
int main()
{//本质是向-∞取整,注意输出格式要不然看不到结果printf("%.1f\n", floor(-2.9)); //-3printf("%.1f\n", floor(-2.1)); //-3printf("%.1f\n", floor(2.9)); //2printf("%.1f\n", floor(2.1)); //2system("pause");return 0;
}

测试结果:

我们发现当调用floor函数取整时是结果都变小,往-∞方向取整

🎵 向+∞取整

#include <stdio.h>
#include <math.h>
#include <windows.h>
int main()
{//本质是向+∞取整,注意输出格式要不然看不到结果printf("%.1f\n", ceil(-2.9)); //-2printf("%.1f\n", ceil(-2.1)); //-2printf("%.1f\n", ceil(2.9)); //3printf("%.1f\n", ceil(2.1)); //3system("pause");return 0;
}

测试结果:

我们发现调用ceil函数时取整是结果都变大,往+∞方向取整

🎵 四舍五入取整

#include <stdio.h>
#include <math.h>
#include <windows.h>
int main()
{//本质是四舍五入printf("%.1f\n", round(2.1));printf("%.1f\n", round(2.9));printf("%.1f\n", round(-2.1));printf("%.1f\n", round(-2.9));system("pause");return 0;
}

测试结果:

round()函数采用的取整方式就是我们四舍五入取整,逢五进一。

🎵 多种取整方式汇总

#
include <stdio.h>
#include <math.h>
#include <windows.h>
int main()
{const char * format = "%.1f \t%.1f \t%.1f \t%.1f \t%.1f\n";printf("value\tround\tfloor\tceil\ttrunc\n");printf("-----\t-----\t-----\t----\t-----\n");printf(format, 2.3, round(2.3), floor(2.3), ceil(2.3), trunc(2.3));printf(format, 3.8, round(3.8), floor(3.8), ceil(3.8), trunc(3.8));printf(format, 5.5, round(5.5), floor(5.5), ceil(5.5), trunc(5.5));printf(format, -2.3, round(-2.3), floor(-2.3), ceil(-2.3), trunc(-2.3));printf(format, -3.8, round(-3.8), floor(-3.8), ceil(-3.8), trunc(-3.8));printf(format, -5.5, round(-5.5), floor(-5.5), ceil(-5.5), trunc(-5.5));system("pause");return 0;
}

测试结果:

总结一下:

  • 浮点数(整数/整数),是有很多的取整方式的。常见的是向上取整,向下取整,向0取整,四舍五入取整,其中C语言默认是向0取整
  • 从汇总例子看,相同的浮点数采用不同的取整方案也可能得到相同的整数
  • 取整方案的使用取决于你的具体场景,比如每台服务器能处理 5 个任务,18 个任务需要 ⌈18/5⌉=4 台服务器,用向上取整预留足够的额外资源。

🏠 关于取模

🎵 取模初步概念

如果a和d是两个自然数,d非零,可以证明存在两个唯一的整数 q 和 r,满足 a = q*d + r 0 ≤ r < d。其中,q被称为商,r 被称为余数。

#include <stdio.h>
#include <windows.h>
int main()
{int a = 10;int d = 3;printf("%d\n", a%d); //结果是1system("pause");return 0;
}

测试结果:

测试结果是符合我们给的定义的,因为a=10,d=3,q=3,r=1(其中 0<= r < d),因此a = q*d + r -> 10 = 3*3 +1。

如果是以下测试代码呢?

🎵 取模修订定义

  • C语言 vs2019
#include<stdio.h>
#include<windows.h>
#include<math.h>int main()
{int a = -10;int d = 3;//printf("%d\n", a/d); //C语言中是-3,很好理解printf("%d\n", a % d);return 0;
}

测试结果:

  • Python 3.10.12 

很显然,上面关于取模的定义,并不能满足语言上的取模运算 : 在C语言测试环境下,10%3得到的余数不满足r>0的要求。因此大家对取模有了一个修订版定义:

如果a和d是两个自然数,d非零,可以证明存在两个唯一的整数 q 和 r,满足 a = q*d + r , q 为整数,且0 ≤ |r|< |d|。其中,q 被称为商,r 被称为余数。

对于C:-10 = (-3) * 3 + (-1) ,其中0 < |-1| <  3

对于Python:-10 = (?) * 3 + 2,可以推导出其q应该为-4才能满足定义。

  • 在不同语言中,同一个计算表达式,负数“取模”结果是不同的,我们可以称之为正余数负余数

Q:为什么会出现正余数和负余数?

答:具体余数r的大小,本质是取决于商q的。而商,取决于除法计算时的取整规则!因此本质是处理商时的取整方式不同,导致了得到的具体余数不同!

🏠 取模 vs 取余

取模和取余两者并不能严格等价(但是大部分情况下是能等价的),取余或者取模,都应该要算出商,然后才能得出余数。在计算机科学中,我们规定的取余和取模本质上它们的取整方式不同

  • 取余:尽可能让商,进行向0取整。
  • 取模:尽可能让商,进行向-∞取整。

因此我们可以推导出:

1. 对任何一个大于0的数(正数),对其进行0向取整和-∞取整,取整方向一致(方向都指向横向数轴左边),此时取模等于取余

2. 对任何一个小于0的数(负数),对其进行0向取整和-∞取整,取整方向相反(0向取整指向右,负无穷取整指向左),此时取模不等于取余

🎵 同符号运算

  • C语言
#include <stdio.h>
#include <windows.h>
int main()
{printf("被除数和除数都是正数:\n");printf("%d\n", 10 / 3);printf("%d\n", 10 % 3);printf("被除数和除数都是负数:\n");printf("%d\n", -10 / -3);printf("%d\n", -10 % -3);system("pause");return 0;
}

测试结果:

  • Python 3.10.12
print(10//3)
print(10%3)
print(-10//-3)
print(-10%-3)
注意:python中 / 默认是浮点数除法,//才是整数除法,并进行-∞取整

测试结果:

通过不同环境对比,我们发现当同符号数据相除时,它们的商一定是正数(正数vs正整数),即大于0!因此,在对其商进行取整时,取模等价于取余

  • 结论:参与相除的两个数据,如果同符号,取模等价于取余!

🎵 不同符号运算

  • C语言
#include <windows.h>
#include<stdio.h>
int main()
{printf("%d\n", -10 / 3); //结果:-3printf("%d\n\n", -10 % 3); //结果:-1 为什么? -10=(-3)*3+(-1)printf("%d\n", 10 / -3); //结果:-3printf("%d\n\n", 10 % -3); //结果:1 为什么?10=(-3)*(-3)+1system("pause");return 0;
}

测试结果:

不同符号,余数求法可以参照之前定义,在C中余数符号和被除数相同,那在Python环境呢?

  • Python 3.10.12

我们发现在Python中余数符号和除数相同,为什么和C语言会产生不同?

理解:

1. a = q*d + r (q为商,r为余数)变换成 r = a - q*d = a + (-q*d)。

2. 我们知道对于x =  y + z这样的表达式,x的符号与|y|和|z|中较大的一致;因此r也就是余数的符号就取决于|a|和|-q*d|谁大,被除数a是固定的,那么就取决于商q的取整方式!

3. C是向0取整,因此商q本身绝对值是减小的,此时由于本来0<|r|<|d|,那此时就是|a|大,即余数符号由被除数决定。(简单理解,略有不严谨)

4. Python是向-∞取整,因此商q本身绝对值是增大的,此时大概就是|-q*d|大一些,即余数符号由除数d决定。

结论:如果参与取余的两个数据符号不同,在C语言中(或其他采用0向取整的语言),余数符号与被除数相同;而采用负无穷取整的语言,余数和除数相同。

🏠 总结

1. 浮点数(或者整数相除),是有很多的取整方式的。

2. 取模修正定义:如果a和d是两个自然数,d非零,可以证明存在两个唯一的整数 q 和 r,满足 a = q*d + r , q 为整数,且0 ≤ |r| < |d|。其中,q 被称为商,r 被称为余数。

3. 在不同语言,同一个计算表达式,“取模”结果是不同的。我们可以称之为分别叫做正余数和负余数;具体余数r的大小,本质是取决于商q的。而商,又取决于除法计算的时候的取整规则

4. 取余vs取模: 取余尽可能让商,进行向0取整取模尽可能让商,向-∞方向取整;对于正数取模等价取余,对于负数,取模与取余不等价

5. 如果参与取余的两个数据符号不同,在C语言中(或其他采用0向取整的语言),余数符号与被除数相同;而采用负无穷取整的语言,余数符号和除数相同


完。

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

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

相关文章

快速上手LangChain(三)构建检索增强生成(RAG)应用

文章目录 快速上手LangChain(三)构建检索增强生成(RAG)应用概述索引阿里嵌入模型 Embedding检索和生成RAG应用(demo:根据我的博客主页,分析一下我的技术栈)快速上手LangChain(三)构建检索增强生成(RAG)应用 langchain官方文档:https://python.langchain.ac.cn/do…

Spring源码分析之事件机制——观察者模式(二)

目录 获取监听器的入口方法 实际检索监听器的核心方法 监听器类型检查方法 监听器的注册过程 监听器的存储结构 过程总结 Spring源码分析之事件机制——观察者模式&#xff08;一&#xff09;-CSDN博客 Spring源码分析之事件机制——观察者模式&#xff08;二&#xff…

redux react-redux @reduxjs/toolkit

redux团队先后推出了redux、react-redux、reduxjs/toolkit&#xff0c;这三个库的api各有不同。本篇文章就来梳理一下当我们需要在项目中集成redux&#xff0c;从直接使用redux&#xff0c;到使用react-redux&#xff0c;再到react-redux和reduxjs/toolkit配合使用&#xff0c;…

OpenHarmony通过挂载镜像来修改镜像内容,RK3566鸿蒙开发板演示

在测试XTS时会遇到修改产品属性、SElinux权限、等一些内容&#xff0c;修改源码再编译很费时。今天为大家介绍一个便捷的方法&#xff0c;让OpenHarmony通过挂载镜像来修改镜像内容&#xff01;触觉智能Purple Pi OH鸿蒙开发板演示。搭载了瑞芯微RK3566四核处理器&#xff0c;树…

网安数学基础期末复习

目录 整除同余同余方程群和环 整除 a的显然因数/平凡因数1&#xff0c;a整除的传递性和组合性 若 a ∣ b , b ∣ a a|b,b|a a∣b,b∣a 则 a b a\pm b ab欧几里得带余除法 公因数和最大公因数在整除里的定义&#xff0c;最大公因数为1则两数互质&#xff0c;注意公因数有正…

NSGA-II(非支配排序遗传算法II)详解与实现

NSGA-II(非支配排序遗传算法II)详解与实现 1. 算法简介 NSGA-II(Non-dominated Sorting Genetic Algorithm II)是一种高效的多目标优化算法&#xff0c;由Deb等人在2002年提出。它主要解决多个目标之间相互冲突的优化问题。 1.1 核心特点 快速非支配排序 时间复杂度&#xf…

Fabric环境部署

官方下载文档&#xff1a;A Blockchain Platform for the Enterprise — Hyperledger Fabric Docs main documentation 1.1 创建工作目录 将Fabric代码按照GO语言的推荐方式进行存放&#xff0c;创建目录结构并切换到该目录下。具体命令如下&#xff1a; mkdir -p ~/go/src/g…

回归预测 | MATLAB实现CNN-SVM多输入单输出回归预测

回归预测 | MATLAB实现CNN-SVM多输入单输出回归预测 目录 回归预测 | MATLAB实现CNN-SVM多输入单输出回归预测预测效果基本介绍模型架构程序设计参考资料 预测效果 基本介绍 CNN-SVM多输入单输出回归预测是一种结合卷积神经网络&#xff08;CNN&#xff09;和支持向量机&#…

SOLIDWORKS Composer在产品设计、制造与销售中的应用

SOLIDWORKS Composer是一款专为技术团队设计的高效沟通工具&#xff0c;广泛应用于产品设计、制造、销售及售后等领域。它能从复杂的CAD数据中提取关键信息&#xff0c;轻松转化为高质量的产品文档、交互式3D动画及说明视频&#xff0c;显著提升产品沟通效率。 Composer擅长制…

【数据结构Ⅰ复习题】

如有错误欢迎指正&#xff0c;题目根据教材----------严蔚敏数据结构&#xff08;c语言版 第2版&#xff09;人民邮电电子版 数据结构Ⅰ复习题 一、填空题1&#xff0e;算法应该具备的5个重要特性有___有穷性___、确定性、可行性、输入和输出。2&#xff0e;非空单链表L中*p是头…

flutter 专题二十四 Flutter 响应式状态管理框架GetX

一、状态管理框架对比 在Flutter的状态管理框架中&#xff0c;主流的状态管理框架有四个&#xff1a;GetX&#xff08;又称为Get&#xff09;、BLoC、MobX、Provider。 Provider 其中&#xff0c;Provider是Flutter社区提供的一种状态管理工具&#xff0c;本质上是对Inherit…

禁用div的写法(自定义disabled)Vue3

因为div 元素本身没有 disabled 属性&#xff0c;所以需要根据JavaScript中的变量、通过动态绑定 class &#xff08;Vue的:class&#xff09;来改变样式。 需要一个变量 isDivDisabled import { ref } from vue; let isDivDisabled ref(false);当 isDivDisabled true &…

大模型系列——旋转位置编码和长度外推

绝对位置编码 旋转位置编码 论文中有个很直观的图片展示了旋转变换的过程&#xff1a; 对于“我”对应的d维向量&#xff0c; 拆分成d/2组以后&#xff0c;每组对应一个角度&#xff0c;若1对应的向量为(x1,x2)&#xff0c;应用旋转位置编码&#xff0c;相当于这个分量旋转了m…

路径规划 | 基于极光PLO优化算法的三维路径规划Matlab程序

效果一览 基本介绍 研究内容 极光优化算法&#xff08;PLO&#xff09;的深入理解&#xff1a; 研究极光优化算法的基本原理&#xff0c;包括模拟带电粒子在地球磁场中的旋转运动、极光椭圆区域内的行走以及粒子间的碰撞等。 分析PLO算法的全局搜索能力和局部开发能力&#xf…

MATLAB画柱状图

一、代码 clear; clc; figure(position,[150,100,900,550])%确定图片的位置和大小&#xff0c;[x y width height] %准备数据 Y1[0.53,7.9,8.3;0.52,6.8,9.2;0.52,5.9,8.6;2.8,5.8,7.9;3.9,5.2,7.8;1.8,5.8,8.4]; % withoutNHC X11:6; %画出4组柱状图&#xff0c;宽度1 h1…

[实用指南]如何将视频从iPhone传输到iPad

概括 将视频从 iPhone 传输到 iPad 时遇到问题&#xff1f;您可能知道一种方法&#xff0c;但不知道如何操作。此外&#xff0c;您要传输的视频越大&#xff0c;完成任务就越困难。那么如何将视频从 iPhone 传输到 iPad&#xff0c;特别是当您需要发送大视频文件时&#xff1f…

Git命令行的使用

目录 一、什么是Git 1、本地仓库 vs 远端仓库 本地仓库 远端仓库 2、.git vs .gitignore .git .gitignore 二、使用Git命令 1、安装git 2、git首次使用需要配置用户邮箱和用户名 3、上传目录/文件到远端仓库步骤 1&#xff09;创建放置文件的目录 2&#xff09;cd…

黑马JavaWeb开发跟学(十五).Maven高级

黑马JavaWeb开发跟学.十五.Maven高级 Maven高级1. 分模块设计与开发1.1 介绍1.2 实践1.2.1 分析1.2.2 实现 1.3 总结 2. 继承与聚合2.1 继承2.1.1 继承关系2.1.1.1 思路分析2.1.1.2 实现 2.1.2 版本锁定2.1.2.1 场景2.1.2.2 介绍2.1.2.3 实现2.1.2.4 属性配置 2.2 聚合2.2.1 介…

十二、Vue 路由

文章目录 一、简介二、安装与基本配置安装 Vue Router创建路由实例在应用中使用路由实例三、路由组件与视图路由组件的定义与使用四、动态路由动态路由参数的定义与获取动态路由的应用场景五、嵌套路由嵌套路由的概念与配置嵌套路由的应用场景六、路由导航<router - link>…

AE RFG 1251 Generator User Manual

AE RFG 1251 Generator User Manual