二进制 正负数加减法 计算INT_MIN - 1=INT_MAX

首先得知道,在java中,int类型占4个字节,1个字节等于8位二进制,所以int类型32位,范围是-2147483648到2147483647,

因为1000 0000, 0000 0000, 0000 0000, 0000 0000这个是-2^31=-2147483648,所以负数多一个。

然后,因为计算机CPU的运算器中只有加法器,所以减法要转化成加法来计算,所以引入了补码。

补码可以解决两同号数相减或两异号数相加的问题。

举个例子,A表示十进制数“+6”,B表示十进制数“-8”,如果把这两个数的原码直接相加,那么

    0000 0110 

+ 1000 1000

————————

    1000 1110                     

结果为-14,很明显是错的。

如果把这两个数的补码相加,那么

    0000 0110     “+6”补码

+  1111 1000      “-8”补码

————————

    1111 1110       “-2”补码

结果是-2的补码,结果是正确的。

要理解上面的补码运算,得先知道一下3点:

1、正数的原码 反码 补码完全相同。

2、负数的反码是将原码按位取反,补码=反码+1。

3、补码转原码和原码转补码的方法是一样的。

最后根据上面的计算方法,计算INT_MIN - 1的结果,看是不是等于 INT_MAX。


     1000 0000, 0000 0000, 0000 0000, 0000 0000     “-2147483648”补码

+   1111 1111,1111 1111, 1111 1111,1111 1111       “-1”补码

————————————————————————

   1 0111 1111,1111 1111, 1111 1111,1111 1111       

很明显,运算溢出了。舍去溢出的最高位,最后运算的结果是0111 1111,1111 1111, 1111 1111,1111 1111。

又因为正数的原码 反码 补码完全相同。所以0111 1111,1111 1111, 1111 1111,1111 1111就是“2147483647”补码、源码= INT_MAX。

所以,综上所述:INT_MIN - 1的结果等于 INT_MAX。





#include <stdint.h> #include <limits.h> // 定义S24Q7定点数类型 typedef int32_t s24q7_t; #define FRAC_BITS 7 // 小数部分位数 #define FIXED_SCALE (1 << FRAC_BITS) // 缩放因子 (128) #define INV_SCALE (1.0f / FIXED_SCALE) // 逆缩放因子 (1/128) // ======================== 基础转换函数 ======================== // 浮点转定点 #define float_to_s24q7(f) ((s24q7_t)((f) * FIXED_SCALE)) // 定点转浮点 #define s24q7_to_float(q) ((float)(q) * INV_SCALE) // 定点转整数(截断) #define s24q7_to_int(q) ((int)((q) >> FRAC_BITS)) // 整数转定点 #define int_to_s24q7(i) ((s24q7_t)((i) << FRAC_BITS)) // ======================== 算术运算 ======================== // 法 #define s24q7_add(a, b) ((a) + (b)) // 减法 #define s24q7_sub(a, b) ((a) - (b)) // 绝对值 #define s24q7_abs(x) ((x) < 0 ? -(x) : (x)) // ======================== 优化乘法实现 ======================== static s24q7_t s24q7_mul(s24q7_t a, s24q7_t b) { // 分解操作数为高低16位(带符号扩展) int32_t a_hi = a >> 16; // 高16位(带符号) int32_t a_lo = (int16_t)(a); // 低16位(带符号扩展) int32_t b_hi = b >> 16; int32_t b_lo = (int16_t)(b); // 计算部分乘积 int32_t p0 = a_lo * b_lo; // 低x低 int32_t p1 = a_lo * b_hi; // 低x高 int32_t p2 = a_hi * b_lo; // 高x低 int32_t p3 = a_hi * b_hi; // 高x高 // 组合结果(带舍入) // 公式: (p3<<32) + (p2<<16) + (p1<<16) + p0 int32_t result = ((p3 << (32 - FRAC_BITS)) + (p2 << 16) + (p1 << 16) + p0); // 添舍入因子 (0.5 LSB) const int32_t round = 1 << (FRAC_BITS - 1); result = (result + (result < 0 ? -round : round)) >> FRAC_BITS; // 饱和处理 if (result > INT32_MAX) return INT32_MAX; if (result < INT32_MIN) return INT32_MIN; return (s24q7_t)result; } // ======================== 优化除法实现 ======================== static s24q7_t s24q7_div(s24q7_t a, s24q7_t b) { if (b == 0) return (a >= 0) ? INT32_MAX : INT32_MIN; // 计算符号 int sign = (a ^ b) < 0 ? -1 : 1; uint32_t abs_a = s24q7_abs(a); uint32_t abs_b = s24q7_abs(b); // 预缩放被除数 (a * 128) uint32_t scaled_a = abs_a << FRAC_BITS; // 计算商 (scaled_a / b) 并添舍入因子 (b/2) uint32_t quotient = (scaled_a + (abs_b >> 1)) / abs_b; // 应用符号和饱和处理 int32_t result = sign * (int32_t)quotient; if (result > INT32_MAX) return INT32_MAX; if (result < INT32_MIN) return INT32_MIN; return (s24q7_t)result; } // ======================== 宏封装运算 ======================== #define s24q7_mul(a, b) s24q7_mul(a, b) #define s24q7_div(a, b) s24q7_div(a, b) int main() { // 转换测试 float f = 50.0f; float u = 8888.0; s24q7_t fixed_f = float_to_s24q7(f); s24q7_t fixed_u = float_to_s24q7(u); printf("浮点数 %.5f → 定点数: 0x%08X\n", f, fixed_f); printf("定点数 0x%08X → 浮点数(宏): %.5f\n", fixed_f, s24q7_to_float(fixed_f)); printf("定点数 0x%08X → 浮点数(宏): %.5f\n", fixed_u, s24q7_to_float(fixed_u)); printf("\n运算演示 (5.8 和3333.5):\n"); printf("法: %.3f\n", s24q7_to_float(s24q7_add(fixed_f,fixed_u))); printf("减法: %.3f\n", s24q7_to_float(s24q7_sub(fixed_f,fixed_u))); printf("乘法: %.3f (饱和值)\n", s24q7_to_float(s24q7_mul(fixed_f,fixed_u))); printf("除法: %.8f\n", s24q7_to_float(s24q7_div(fixed_f,fixed_u))); return 0; } 优化代码,通过预放缩法提高除法的精度;再给一个实现方案:应为我最后的输出结果是一个不大于1的带符号小数,所以能否根据这一特殊情况设计一个算法
最新发布
07-27
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值