无符号整数的上溢和下溢

如何解决无符号整数的上溢和下溢

假设,我正在尝试减去2个无符号整数:

247 = 1111 0111
135 = 1000 0111

如果我们减去这两个二进制数字,我们将得出= 0111 0000

这是下溢吗,因为我们现在只需要7位?或如何运作?

解决方法

只要c = a - b大于b,就会发生无符号减法a中的下溢。

但是,这有点像是循环定义,因为有多少种机器执行a < b比较是通过使用环绕算术减去操作数,然后根据两个操作数和结果检测溢出。 / p>

还要注意,在C语言中我们不会谈论“溢出”,因为没有错误条件:C无符号整数提供了通常在硬件中发现的环绕算法。

因此,考虑到我们具有环绕算法,我们可以检测出减法是否发生了环绕(或溢出,取决于角度)。

我们需要的是abc中的最高有效位。我们称它们为ABC。根据这些,溢出V的计算如下:

A B C | V
------+--
0 0 0 | 0
0 0 1 | 1
0 1 0 | 1
0 1 1 | 1
1 0 0 | 0
1 0 1 | 0
1 1 0 | 0
1 1 1 | 1

这简化为

A'B + A'C + BC

换句话说,无符号减法c = a - b中的溢出发生在以下情况:

  1. a的msb为0,b的msb为1;
  2. a的msb为0,而c的msb为1;
  3. b的msb为1,而c的msb也为1。

减去247-135 = 112显然不会溢出,因为247大于135。应用上面的规则,A = 1,B = 0和C =0。表的1 1 0行具有0 in V栏:无溢出。

,

通常,“下溢”是指计算的理想数学结果低于该类型可以表示的结果。如果在无符号算术中从5中减去7,则理想的数学结果将为-2,但无符号类型不能表示-2,因此运算会下溢。或者,在可以表示从-128到+127的数字的八位带符号类型中,从-100减去100理想情况下会产生-200,但这不能用该类型表示,因此操作会下溢。

在C中,无符号算术被称为不会下溢或上溢,因为C标准定义了使用模算术而不是实数算术执行的操作。例如,使用32位无符号算术,从5中减去7将产生4,294,967,294(以十六进制表示,FFFFFFFE 16 ),因为它包装了模2 32 = 4,296。尽管如此,人们在讨论这些操作时仍可能使用术语“下溢”或“上溢”,意在指数学问题,而不是定义的C行为。

换句话说,对于您用于算术的任何类型,该类型都可以表示一些下限 L 和一些上限 U 。如果运算的理想数学结果小于 L ,则运算会下溢。如果某个操作的理想数学结果大于 U ,则该操作会溢出。 “下溢”和“上溢”表示操作已超出该类型的范围。 “溢出”也可以用来指代该类型的任何边界,包括低端。

这并不意味着需要更少的位来表示结果。从11110111 2 中减去10000111 2 时,结果01110000 2 = 1110000 2 在范围内,因此没有上溢或下溢。它需要更少的比特来表示这一事实是不相关的。

(注意:对于整数运算,相对于绝对界限 L U 定义“下溢”或“上溢”。对于浮点运算,这些术语含义有些不同:可以相对于结果的大小(忽略符号)来定义它们,而相对于格式的有限非零范围来定义它们。浮点格式可以表示0,然后从0到格式可以表示的最小非零数字之间的某些结果,即使在技术上处于可表示数字范围(从0到无穷大)内,也被认为是下溢。同样,某些结果超出最大可表示有限数,即使它们在可表示范围内,也被认为是溢出的,因为它们小于无穷大。)

,

长话短说,这就是当你有:

unsigned char n = 255; /* highest possible value for an unsigned char */

n = n + 1; /* now n is "overflowing" (although the terminology is not correct) to 0 */
printf("overflow: 255 + 1 = %u\n",n);
   
n = n - 1; /* n will now "underflow" from 0 to 255; */
printf("underflow: 0 - 1 = %u\n",n);
   
n *= 2; /* n will now be (255 * 2) % 256 = 254; 
        /* when the result is too high,modulo with 2 to the power of 8 is used */ 
        /* for an 8 bit variable such as unsigned char; */
printf("large overflow: 255 * 2 = %u\n",n);   
   
n = n * (-2) + 100; /* n should now be -408 which is 104 in terms of unsigned char. */
                       /* (Logic is this: 408 % 256 = 152; 256 - 152 = 104) */
printf("large underflow: 255 * 2 = %u\n",n);

结果是(使用 gcc 11.1 编译,标志 -Wall -Wextra -std=c99):

overflow: 255 + 1 = 0
underflow: 0 - 1 = 255
large overflow: 255 * 2 = 254
large underflow: 255 * 2 = 104

现在是科学版本:上面的评论仅代表正在发生的事情的数学模型。为了更好地了解实际发生的情况,适用以下规则:

  1. 整数提升:

小于 int 的整数类型在操作时被提升 对他们进行。如果原始类型的所有值都可以 表示为 int,较小类型的值被转换为 一个整数;否则,它被转换为一个无符号整数。

所以当计算机执行 n = 255; n = n + 1; 时,内存中实际发生的事情是这样的: 首先,右侧被评估为一个 int(有符号),因为根据整数提升规则,结果适合一个有符号 int。所以表达式的右边变成了二进制:0b00000000000000000000000011111111 + 0b00000000000000000000000000000001 = 0b00000000000000000000000100000000(一个 32 位整数)。

  1. 截断

32 位 int 在被赋值时丢失了最高有效的 24 位 回到 8 位数字。

所以,当 0b00000000000000000000000100000000 赋给变量 n 时,它是一个无符号字符,32 位值被截断为 8 位值(只复制最右边的 8 位)=> n变成 0b00000000

每次操作都会发生同样的事情。右侧的表达式计算为有符号整数,然后将其截断为 8 位。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-