机器码 真数 原码 反码 补码 float的内存表示

#include<stdio.h>

int main(int argc, char** argv)
{
    printf("sizeof(int): %d\n", sizeof(int));
    /*********
    hex格式表示的整数是补码
    http://www.cnblogs.com/zhangziqiu/archive/2011/03/30/ComputerCode.html
    为简洁,计算机没有减法、只有加法; 反码解决减法问题;补码在反码基础上解决0的符号问题(然后用-0表示-128)
    正数的反码是其本身      负数的反码是在其原码的基础上, 符号位不变,其余各个位取反.
    正数的补码就是其本身    负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)
    [+1] = [00000001]原 = [00000001]反 = [00000001]补
    [-1] = [10000001]原 = [11111110]反 = [11111111]补
    因为机器使用补码, 所以对于编程中常用到的32位int类型, 可以表示范围是: [-231, 231-1] 因为第一位表示的是符号位.而使用补码表示时又可以多保存一个最小值
    ********/
    printf("0xFFFFFFFF:\t%d 0x%X\n", 0xFFFFFFFF, 0xFFFFFFFF);
    printf("0x7FFFFFFF:\t%d 0x%X\n", 0x7FFFFFFF, 0x7FFFFFFF);
    printf("-0x7FFFFFFF:\t%d 0x%X\n", -0x7FFFFFFF, -0x7FFFFFFF);
    
    return 0;
}


[root@test-22 leetcode]# !g++
g++ -o inttest inttest.cpp ; ./inttest 
sizeof(int): 4
0xFFFFFFFF:     -1 0xFFFFFFFF
0x7FFFFFFF:     2147483647 0x7FFFFFFF
-0x7FFFFFFF:    -2147483647 0x80000001


https://github.com/xiarendeniao/utils/blob/master/c/verfloat.cpp

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>

typedef int64_t int64;
typedef int32_t int32;
typedef int16_t int16;
typedef int8_t int8;
typedef uint64_t uint64;
typedef uint32_t uint32;
typedef uint16_t uint16;
typedef uint8_t uint8;
typedef uint32_t DWORD;

/*
1.int32表示范围和机器码(补码) bin()函数用于验证补码表示形式

    int32 [-2^31,2^31-1] [-2147483648,2147483647]
    -2147483648正数部分超出31bit的表示范围,机器表示形式是-0(10000000 00000000 00000000 00000000)
    所以不能用“符号位不变、其余按照正数的二进制形式按位取反再加1”获取-2147483648的补码 

2.大头小头(大端序/小端序) big endian / little endian (以下以int32举例)

    机器数(补码)只是为了方便运算所约定的计算机底层的数字表示形式,不等同于内存布局,内存布局和大头小头相关
    dec(10)   = bin(0b00000000 00000000 00000000 00001010)    = hex(0xA)            hex是补码的十六进制
    dec(-10)  = bin(0b11111111 11111111 11111111 11111011)    = hex(0xA)
    dec(-1)   = bin(0x11111111 11111111 11111111 11111111)    = hex(0xFFFFFFFF)

    
    在big endian机器的内存布局(数字的高位部分放在低地址处、低位部分放在高地址处) membin()函数用于验证数字在内存中的形式
    dec(10)     00000000 00000000 00000000 00001010 即 00 00 00 0A
    dec(-10)    11111111 11111111 11111111 11111011 即 FF FF FF FB
    dec(-1)     11111111 11111111 11111111 11111111 即 FF FF FF FF

    在little endian机器的内存布局(数字的高位部分放在高地址处、低位部分放在低地址处)
    dec(10)     00001010 00000000 00000000 00000000 即 0A 00 00 00
    dec(-10)    11111011 11111111 11111111 11111011 即 FB FF FF FF
    dec(-1)     11111111 11111111 11111111 11111111 即 FF FF FF FF
*/

char* positive2bin(const int in, char* binstr, bool filling = true)
{  
    assert(in >= 0);
    char* out = binstr;
    char t[33];
    char* tp = t;  
    int r = in; 

    while(r >= 1) {  
        *tp++ = r%2 + 48;  
        r /= 2;  
    }
    *tp-- = '\0';
    assert(tp-t == strlen(t)-1);
    //fprintf(stderr, "Positive2bin:%12d 0b%s %dbits\n", in, t, strlen(t)); 
    if (filling) for (int i = 0; i < 32-(tp-t+1); i++) *out++ = '0';
    while (tp >= t) *out++ = *tp--; //BUG: while(*out++ = *tp--);
    *out = '\0';
    
    assert(out-binstr == strlen(binstr));
    //fprintf(stderr, "--------2bin:%12d 0b%s %dbits\n", in, binstr, strlen(binstr)); 
    return binstr;
} 

char* bin(const int in, char* binstr)
{
    if (in >= 0) return positive2bin(in, binstr);
    positive2bin(-in, binstr);
    //按位取反
    *binstr = '1';
    char* p = binstr + 1;
    while ( *p != '\0') {
        if (*p == '0') *p = '1';
        else *p = '0';
        p++;
    }
    p--;
    //fprintf(stderr, "-----reverse:%12d 0b%s %dbits\n", in, binstr, strlen(binstr));
    //+1
    while (p > binstr) {
        if (*p == '0') {
            *p = '1';
            break;
        } else {
            *p = '0';
            p--;
        }
    }
    if (p == binstr) 
        fprintf(stderr, "overflow: %d\n", in);
    return binstr;
}

char* membin(const uint32* in, char* binstr)
{
    char* bp = binstr;
    char byte[9] = {0};
    uint8* p = (uint8*)in;
    for (int i = 0; i < 4; i++, p++) {
        //printf("fetched byte %d\n", (uint32)*p);
        positive2bin(*p, byte, false);
        char* tp = byte;
        for (int i = 0; i < 8-strlen(byte); i++) *bp++ = '0';
        while (*tp != '\0') *bp++ = *tp++;
    }
    *bp = '\0';
    //fprintf(stderr, "------v2-bin:%12d 0b%s %dbits\n", in, binstr, strlen(binstr));
    return binstr;
}

//验证补码的表示形式跟内存数据存放(big/little endian)
void verf_bin()
{
    char buff[128] = {0};
    char binstr[33] = {0};
    uint32 in;

begin:
    printf("please input > ");  
    scanf("%s", buff);
    if (buff[0] == '0' && (buff[1] == 'x' || buff[1] == 'X'))
        sscanf(buff, "%x", &in);
    else
        sscanf(buff, "%d", &in);

    if (in != 0x80000000U) //-2147483648,int32的最小值
        fprintf(stderr, "positive2bin:%12d 0x%08x 0b%s bin %f\n", in, in, bin((int32)in, binstr), *(float*)&in);

    fprintf(stderr, "memory--2bin:%12d 0x%08x 0b%s mem %f\n", in, in, membin((uint32*)&in, binstr), *(float*)&in);

    goto begin;  
}

int main(int argc, char** argv)
{
    char binstr[33] = {0};

    uint32 a = 0x7f700001U;
    printf("0x%8x 0b%s %f\n", a, bin((int)a,binstr), *(float*)&a);


    //https://android.googlesource.com/platform/dalvik.git/+/f6c387128427e121477c1b32ad35cdcaa5101ba3/libcore/luni/src/main/native/java_lang_Float.c
    //java源码中把所有nan替换成同一个,这样便于做比较
    uint32 nan = 0x7fc00000;
    printf("+float标准的nan 0x%8x 0b%s %f\n", nan, bin((int)nan,binstr), *(float*)&nan);

    uint32 b = 0x7f800001U;
    printf("+float最小的nan 0x%8x 0b%s %f\n", b, bin((int)b,binstr), *(float*)&b);

    uint32 c = 0x7fffffffU;
    printf("+float最大的nan 0x%8x 0b%s %f\n", c, bin((int)c,binstr), *(float*)&c);

    uint32 d = 0xff800001U;
    printf("-float最大的nan 0x%8x 0b%s %f\n", d, bin((int)d,binstr), *(float*)&d);

    uint32 e = 0xffffffffU;
    printf("-float最小的nan 0x%8x 0b%s %f\n", e, bin((int)e,binstr), *(float*)&e);

    verf_bin();
    return 0;
}

/*
[root@test-22 c++-study]# g++ verfloat.cpp -o verfloat; ./verfloat 
0x7f700001 0b01111111011100000000000000000001 319014739270789413148584118414533984256.000000
+float最小的nan 0x7f800001 0b01111111100000000000000000000001 nan
+float最大的nan 0x7fffffff 0b01111111111111111111111111111111 nan
-float最大的nan 0xff800001 0b11111111100000000000000000000001 nan
-float最小的nan 0xffffffff 0b11111111111111111111111111111111 nan
please input > 0x40000001U
positive2bin:  1073741825 0x40000001 0b01000000000000000000000000000001 bin 2.000000
memory--2bin:  1073741825 0x40000001 0b00000001000000000000000001000000 mem 2.000000
please input > 0x7f000001U
positive2bin:  2130706433 0x7f000001 0b01111111000000000000000000000001 bin 170141203742878835383357727663135391744.000000
memory--2bin:  2130706433 0x7f000001 0b00000001000000000000000001111111 mem 170141203742878835383357727663135391744.000000
please input > 0x00000001U
positive2bin:           1 0x00000001 0b00000000000000000000000000000001 bin 0.000000
memory--2bin:           1 0x00000001 0b00000001000000000000000000000000 mem 0.000000
please input > 0x007fffffU
positive2bin:     8388607 0x007fffff 0b00000000011111111111111111111111 bin 0.000000
memory--2bin:     8388607 0x007fffff 0b11111111111111110111111100000000 mem 0.000000
please input > 0x3f800000U
positive2bin:  1065353216 0x3f800000 0b00111111100000000000000000000000 bin 1.000000
memory--2bin:  1065353216 0x3f800000 0b00000000000000001000000000111111 mem 1.000000
*/


/*
    1.NaN
        https://android.googlesource.com/platform/dalvik.git/+/f6c387128427e121477c1b32ad35cdcaa5101ba3/libcore/luni/src/main/native/java_lang_Float.c
        上述URL中NAN的判定规则:指数为无效值
        
    1.xxxx * 2^n            符号    指数(n,+/-)                         尾数(1.xxxx..)
    float(32)               1       8                                   23
                                    ...
    0x7f800001U             0       111 1111 1                          000 0000 0000 0000 0000 0001    nan
    0x7fffffffU             0       111 1111 1                          111 1111 1111 1111 1111 1111    nan
    0xff800001U             1       111 1111 1                          000 0000 0000 0000 0000 0001    nan
    0xffffffffU             1       111 1111 1                          111 1111 1111 1111 1111 1111    nan
    0x7fc00000U             0       111 1111 1                          100 0000 0000 0000 0000 0000    nan
    
    0x40000001U             0       100 0000 0                          000 0000 0000 0000 0000 0001    
    0x7f000001U             0       111 1111 0                          000 0000 0000 0000 0000 0001    
    0x00000001U             0       000 0000 0                          000 0000 0000 0000 0000 0001    -> 指数000 0000 0表示的是-127
    0x007fffffU             0       000 0000 0                          111 1111 1111 1111 1111 1111    
    0x3f800000U             0       011 1111 1                          000 0000 0000 0000 0000 0000    -> 指数011 1111 1表示的是0,尾数全零表示的是1(尾数最高位被约定省略了)
    
                                    [-2^7,2^7-1]
                                    [-128,127](转正:约定+127后存入指数区间,即,127左移一位)
                                    [-1,254]
                                    [?,1111 1110] -1怎么存? -> 应该是舍掉了吧,指数为0(即1.xxx * 2^-127)时浮点的值已经趋近于0了
                                    
    double(64)              1       11                                  52
                                    [-2^10,2^10-1]
                                    [-1024,1023]
                                    [-1,2046](转正:约定+1023后存入指数区间,即,1023左移一位)
                                    
    0x7ff8000000000000ULL   0       111 1111 1111                       1000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
*/



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值