如何在没有*或-运算符的情况下取反C中的正整数?

如何解决如何在没有*或-运算符的情况下取反C中的正整数?

您好,我正在尝试为我的实验室编写一个函数,该函数要求我用受限运算符取正数。允许的运算符为:! ~ & ^ | + <<>>

我最初的方法是使用加法符xx + x加倍,然后从x中减去该值以得到相反的值,但是由于操作员的限制而受到限制。我对C还是很陌生,并且想学习,如果有人可以为我提供执行此操作背后的想法,我将不胜感激。

解决方法

这可能不是您的讲师想要看到的,但是它可以工作并且确实做到了,与~运算符不同,它不依赖于实现(信号幅度,1补码或2补码)并且可以不会造成UB。我发布此解决方案是因为它满足要求,但又丑陋又缓慢,因为我认为任务很愚蠢(任务导致的功能只能在使用2补码的系统上运行,我敢打赌讲师会提出一个只能解决问题的解决方案在2补码系统上。

#include <limits.h>

//Returns the negative value of n,//n has to be positive. Negative values of n cause UB.
int makeNegative(int n)
{
    int i=INT_MIN;
    while(i+n) //continue till i+n is 0,no need for the < operator
    {
        i++;
    }
    return i;
}

如果您希望在n为负数时不导致UB的代码,则可以检查n的负值:

#include <limits.h>

int isNegative(int n)
{
    int i=INT_MIN;
    while(i)
    {
        i++;
        if(n==INT_MAX) //when n reaches INT_MAX,it was positive
        {              //we need to check for it before increment
          return 0;    //increment a int of value INT_MAX would cause UB 
        }
        n++;
        if(!n) //n is 0 means n was negative before
        {
          return 1;
        }
    }
    return 0;
}

//Returns the negative value of n i n is positive
//returns n in any other case
int makeNegative(int n)
{
    if(isNegative(n))
    {
        return n;
    }
    int i=INT_MIN;
    while(i+n) //continue till i+n is 0,no need for the < operator
    {
        i++;
    }
    return i;
}

2-补码系统

正如其他人已经指出的那样,这是您的教练可能想要看到的:n=(~n)+1;。这仅在使用2补码时有效,并且会导致INT_MIN产生UB。

假设我们在变量1中存储了数字n。现在我们要取反n。然后,我们必须反转变量,这意味着我们翻转每一位,然后添加+1。这是一个int8_t的示例。

Value | Bit pattern |
    1 |  0b00000001 | n is set to 1
   -2 |  0b11111110 | We inverted n
   -1 |  0b11111111 | We added 1 to n

2补码系统的优点是,我们可以为值使用所有可能的位模式,并且对于大多数操作,我们可以对signedunsigned变量使用相同的逻辑。对于无符号变量,0b11111111的二进制值为0xFF==255。 C标准要求无符号整数环绕。如果我们将0xFF存储在uint8_t变量中并添加1,则结果将无法存储在uint8_t中并回绕为0。意味着0b11111111+1==0 。如前所述,我们可以将值-1存储在int8_t中作为位模式0b11111111。在这里我们也得到0b11111111+1==0 => -1+1==0

2-补码系统的一个特征是负值比正值多一个。 INT8_MIN<-INT8_MAXINT8_MIN具有位模式0b10000000,如果将其反转,则会得到位模式0b01111111==INT8_MAX。现在,当我们添加1时,就会发生溢出,并且溢出会导致有符号变量的UB *。因此,对n=(~n)+1;进行签名时,语句n可能导致UB。对于n=-nn=n*-1n=n/-1也是如此,因为当n具有我们无法取反的最低值时,它们全部失效。

*当您告诉编译器对符号变量使用环绕(gcc上的-fwrapv)时,它将再次导致INT8_MIN

,

这是您可能希望产生的经典解决方案:

int negate_positive_number(int n) {
    return ~n + 1;
}

此代码的问题是它仅适用于2的补码系统。这不是一个真正的问题,因为您今天可能不会遇到其他架构。

但是C标准支持带符号整数的其他表示形式:

  • 符号/幅值,其中负值设置了相同的值位,但设置了符号位,
  • 一个补数,其中负值的所有位都与正值的表示相反。

在这两个历史古怪的地方,0有2种可能的表示形式,其中一种可能是陷阱值。

这是适用于所有3种架构的原始解决方案:2的补码,符号/幅度和1的补码系统:有点晦涩但更便携:

#include <limits.h>

int negate_positive_number(int n) {
    return (n ^ INT_MIN ^ INT_MAX) + (1 & (INT_MIN + INT_MAX));
}

它使用+^&以及<limits.h>中的定义,可能是超限。我假设也允许使用括号。

,

2个补语

int minus(int x)
{
    return ~x + 1;
}

测试:

https://godbolt.org/z/c89GWT

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

相关推荐


使用本地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-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res