浮点数的绝对值

现在计算机中的浮点数基本都是IEEE 754格式的,那么如何求一个浮点数的绝对值呢?

有人想到了:

float x;

if(x < 0)
    x = -x;
嗯,不错,这样也能得到结果。今天我来提供另外一种方法,当然,方法不是我原创,我主要是解释其中的原因。

float x;
*((int *) &x)) &= 0x7fffffff;

double x;
*(((int *) &x) +1) &= 0x7fffffff;

double x;
*((long long int *) &x)) &= 0x7fffffffffffffff;
上面是三个代码片段,它们分别可以求float、double、double的绝对值。按我们一般的想法,第一个和第三个很好理解,就是利用了指针的相互转换将符号位置0,但是,第二个呢?还是用程序来解释最好了。

#include <stdio.h>

int main(void)
{
    double x;
    x = -1.2;
    long long int *pt = (long long int)&x;
    printf("%p: %x ", (unsigned char *)pt,*(unsigned char *)pt);
    printf("%p: %x ", ((unsigned char *)pt+1),*((unsigned char *)pt+1));
    printf("%p: %x ", ((unsigned char *)pt+2),*((unsigned char *)pt+2));
    printf("%p: %x\n", ((unsigned char *)pt+3),*((unsigned char *)pt+3));
    printf("%p: %x ", ((unsigned char *)pt+4),*((unsigned char *)pt+4));
    printf("%p: %x ", ((unsigned char *)pt+5),*((unsigned char *)pt+5));
    printf("%p: %x ", ((unsigned char *)pt+6),*((unsigned char *)pt+6));
    printf("%p: %x\n", ((unsigned char *)pt+7),*((unsigned char *)pt+7));
    printf("\n");  
        
    *(((int *) &x) +1) &= 0x7fffffff;
    pt = (long long int)&x;
    printf("%p: %x ", (unsigned char *)pt,*(unsigned char *)pt);
    printf("%p: %x ", ((unsigned char *)pt+1),*((unsigned char *)pt+1));
    printf("%p: %x ", ((unsigned char *)pt+2),*((unsigned char *)pt+2));
    printf("%p: %x\n", ((unsigned char *)pt+3),*((unsigned char *)pt+3));
    printf("%p: %x ", ((unsigned char *)pt+4),*((unsigned char *)pt+4));
    printf("%p: %x ", ((unsigned char *)pt+5),*((unsigned char *)pt+5));
    printf("%p: %x ", ((unsigned char *)pt+6),*((unsigned char *)pt+6));
    printf("%p: %x\n", ((unsigned char *)pt+7),*((unsigned char *)pt+7));
    printf("\n");

    printf("%p\n", &x);
    printf("%p\n\n", (int *)&x+1);  

    printf("%f\n", x);

    return 0;
}
这是一段完整的C语言程序,先将double值赋为一个负数,再利用指针的转换获得各个字节的值同时打印出地址和值,执行
*(((int *) &x) +1) &= 0x7fffffff;

后,再打印出各个字节的地址和值,最后打印出double值。下面是运行结果。

0xbfdf1330: 33 0xbfdf1331: 33 0xbfdf1332: 33 0xbfdf1333: 33
0xbfdf1334: 33 0xbfdf1335: 33 0xbfdf1336: f3 0xbfdf1337: bf

0xbfdf1330: 33 0xbfdf1331: 33 0xbfdf1332: 33 0xbfdf1333: 33
0xbfdf1334: 33 0xbfdf1335: 33 0xbfdf1336: f3 0xbfdf1337: 3f

0xbfdf1330
0xbfdf1334

1.200000


可以看到,它确实可以将double类型的值求绝对值。再看看上面的地址和相应的值,发现就最后一个字节的第一个位变成了0,也就是说,是最后一个字节的第一个位和0x7ffffff的第一个位相与。看到这里可以知道,该表达式之所以难以理解是由于大小端的问题。

因此,可以得到原因:

double类型的符号位为第一个字节的第一个位,但是类似intel的小端存储方式会对字节按照相反的方向存放,也就是最后一个字节的第一个位,因此,

*(((int *) &x) +1) &= 0x7fffffff;
中的+1操作可以定位到后面4个字节,然后0x7fffffff也是按照这种方式存放的,它的最后一个字节的第一个位就是符号位0,刚好相与就得出结果。


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值