当前位置:编程学习 > C/C++ >>

浮点数的绝对值

现在计算机中的浮点数基本都是IEEE 754格式的,那么如何求一个浮点数的绝对值呢?
 
有人想到了:
 
[cpp] 
float x;  
  
if(x < 0)  
    x = -x;  
嗯,不错,这样也能得到结果。今天我来提供另外一种方法,当然,方法不是我原创,我主要是解释其中的原因。
[cpp]  
float x;  
*((int *) &x)) &= 0x7fffffff;  
  
double x;  
*(((int *) &x) +1) &= 0x7fffffff;  
  
double x;  
*((long long int *) &x)) &= 0x7fffffffffffffff;  
上面是三个代码片段,它们分别可以求float、double、double的绝对值。按我们一般的想法,第一个和第三个很好理解,就是利用了指针的相互转换将符号位置0,但是,第二个呢?还是用程序来解释最好了。
[cpp]  
#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值赋为一个负数,再利用指针的转换获得各个字节的值同时打印出地址和值,执行
[cpp]  
*(((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的小端存储方式会对字节按照相反的方向存放,也就是最后一个字节的第一个位,因此,
 
[cpp]  
*(((int *) &x) +1) &= 0x7fffffff;  
中的+1操作可以定位到后面4个字节,然后0x7fffffff也是按照这种方式存放的,它的最后一个字节的第一个位就是符号位0,刚好相与就得出结果。
 
补充:软件开发 , C++ ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,