• warning: integer overflow in expression [Woverflow]


    [root@centos7 ~]# gcc main.c -o main
    main.c: In function ‘main’:
    main.c:9:27: warning: integer overflow in expression [-Woverflow]
         u_int64_t total = 2000*10000000;
                               ^
    [root@centos7 ~]# cat main.c 
    #include <unistd.h>
    #include <stdio.h>
    #include <sys/types.h>
    
    
    int main(int argc,char* argv[])
    {
        //u_int64_t total = 0xFFFFFFFFFFFFFFFF;
        u_int64_t total = 2000*10000000;
        //__uint128_t = 2000*10000000;
        printf("%d, %lu \n",sizeof(u_int64_t), total);
        printf("%d \n",htons(56710));
        return 0;
    }
    每个值都是integer, 但是相乘的值超过了integer最大值(2147483647), 所以编译出错。

    解决方案

    //将相乘的第一个数转成long即可。

     
    [root@centos7 ~]# gcc main.c -o main
    [root@centos7 ~]# ./main 
    8, 20000000000 
    34525 
    [root@centos7 ~]# cat main.c 
    #include <unistd.h>
    #include <stdio.h>
    #include <sys/types.h>
    
    
    int main(int argc,char* argv[])
    {
        //u_int64_t total = 0xFFFFFFFFFFFFFFFF;
        u_int64_t total = 2000*10000000L;
        //__uint128_t = 2000*10000000;
        printf("%d, %lu \n",sizeof(u_int64_t), total);
        printf("%d \n",htons(56710));
        return 0;
    }
    [root@centos7 ~]# gcc main.c -o main
    [root@centos7 ~]# ./main 
    8, 2000000000 
    8 
    [root@centos7 ~]# cat main.c 
    #include <unistd.h>
    #include <stdio.h>
    #include <sys/types.h>
    
    
    int main(int argc,char* argv[])
    {
        u_int64_t a =200;
        u_int64_t b =10000000;
        u_int64_t total = a*b;
        printf("%d, %lu \n",sizeof(u_int64_t), total);
        printf("%d \n",sizeof(double));
        return 0;
    }
    [root@centos7 ~]# gcc main.c -o main
    [root@centos7 ~]# ./main 
    8, 2000000000 
    8 16
    [root@centos7 ~]# cat main.c 
    #include <unistd.h>
    #include <stdio.h>
    #include <sys/types.h>
    
    
    int main(int argc,char* argv[])
    {
        u_int64_t a =200;
        u_int64_t b =10000000;
        u_int64_t total = a*b;
        printf("%d, %lu \n",sizeof(u_int64_t), total);
        printf("%d %d\n",sizeof(double), sizeof(long double));
        return 0;
    }

    在存储时,系统将实型数据分成小数部分和指数部分两个部分、分别存储。
    如 3.14159 在内存中的存放形式如下:

    0.314159  101

    算6个有效位

    这个决定了精度:

    float:有效位6-7位
    double:15-16
    long double:18-19
    当要表示一个精确的数字时候非常重要
    否则可能丢失精度。

    例子:

    float a = 123456789;
    float b = 1234567890;
    float c = 12345678900;

    printf("\n%f\n",a);
    printf("\n%f\n",b);
    printf("\n%f\n",c);

    输出:
    123456792.000000

    1234567936.000000

    12345678848.000000
    只有前面7位是精确的后面的数据就未必了。
    -----------------------------------
    C语言浮点类型有效位(float, double,long double)

    #include <stdio.h>
    
    int main(void)
    {
        float aboat = 32000.0;
        double abet = 5.32e-5;
        long double dip = 5.32e-5;
    
        printf("%f can be written %e\n", aboat, aboat);
        printf("%f can be written %e\n", abet, abet);
        printf("%lf can be written %le\n", dip, dip);
    
        return 0;
    }
    Output:
    
    32000.000000 can be written 3.200000e+004
    0.000053 can be written 5.320000e-005
    -1950228512509697500000000000000000000000000000000000000000000000000000000000000
    000000000000000000000000000000000000000000000000000000000000000000000000.000000
    can be written 2.725000e+002
    Press [Enter] to close the terminal ...

    果断的出错了…

    那么,double内存中占8Byte,64bit,__int64也占8Byte,64bit,按理讲__int64标识double的整数部分应该绰绰有余啊,怎么就出错了呢…

    那么我们看下
    DBL_MAX:1.7976931348623158e+308
    INT64_MAX:9223372036854775807

    差这么多,不科学啊,找资料:

    https://en.wikipedia.org/wiki/Floating-point_arithmetic
    http://blog.csdn.net/tercel_zhang/article/details/52537726
    https://wenku.baidu.com/view/437c821152d380eb62946d1f.html
    http://www.cnblogs.com/fandong90/p/5397260.html
    http://www.fmddlmyy.cn/text60.html
    http://blog.csdn.net/gjw198276/article/details/6956244

    找了很多,这几篇讲的比较透彻,对解决这一问题有帮助

    别急,慢慢读,原来double的解释方式和平常见到的整形表示方式并不一样,它在内存中采用了二进制的科学计数法。
    IEEE关于浮点数的协定

    double包含64个bit
    第0位符号位,
    第1位至12位标识指数位
    第13至64位表示尾数

    正因为这样,所以他可以表示远超于±2^63之外的数;但这也带来了精度的问题,它并不能完整的标识范围内的每个具体数值,会有误差的存在;它表示的是一个可接受的范围。

    [root@centos7 ~]# gcc main.c -o main
    [root@centos7 ~]# ./main 
    8, 2000000000 , 0.000000000 
    8 16
    [root@centos7 ~]# cat main.c 
    #include <unistd.h>
    #include <stdio.h>
    #include <sys/types.h>
    
    
    int main(int argc,char* argv[])
    {
        u_int64_t a =200;
        u_int64_t b =10000000;
        u_int64_t total = a*b;
        long double db = (long double)total;
        printf("%d, %lu , %.9lf \n",sizeof(u_int64_t), total, db);
        printf("%d %d\n",sizeof(double), sizeof(long double));
        return 0;
    }
    __div64_32函数
    uint32_t __attribute__((weak)) __div64_32(uint64_t *n, uint32_t base)
    {
        uint64_t rem = *n;
        uint64_t b = base;
        uint64_t res, d = 1;
        uint32_t high = rem >> 32;
    
        /* Reduce the thing a bit first */
        res = 0;
        if (high >= base) {
            high /= base;
            res = (uint64_t) high << 32;
            rem -= (uint64_t) (high*base) << 32;
        }
    
        while ((int64_t)b > 0 && b < rem) {
            b = b+b;
            d = d+d;
        }
    
        do {
            if (rem >= b) {
                rem -= b;
                res += d;
            }
            b >>= 1;
            d >>= 1;
        } while (d);
    
        *n = res;
        return rem;
    }
    - -do_div
    //进制之间的相应转换
    # define do_div(n,base) ({                        \
        unsigned int __base = (base);                    \
        unsigned int __rem;    \
        //这一句的作用是为了消去警告,因为定义了n变量而没有使用到它,会报警
        (void)(((typeof((n)) *)0) == ((unsigned long long *)0));    \ 
        
        if (((n) >> 32) == 0) {                        \//32位4字节
            __rem = (unsigned int)(n) % __base;            \//对应的base进制位
            (n) = (unsigned int)(n) / __base;            \
        } else                                \
            __rem = __div64_32(&(n), __base);            \//64转32
        __rem;                                \
     })
     
  • 相关阅读:
    BZOJ 4278: [ONTAK2015]Tasowanie 后缀数组 + 贪心 + 细节
    BZOJ 1692: [Usaco2007 Dec]队列变换 后缀数组 + 贪心
    luogu P2852 [USACO06DEC]牛奶模式Milk Patterns 后缀数组 + Height数组 + 二分答案 + 扫描
    BZOJ2251 [2010Beijing Wc]外星联络 后缀数组 + Height数组
    [NOI2015]软件包管理器 树链剖分 + 线段树
    BZOJ [POI2004]PRZ 状压DP + 二进制 + 骚操作
    GIL与异步回调
    Event事件
    进程池与线程池
    队列
  • 原文地址:https://www.cnblogs.com/dream397/p/16286060.html
Copyright © 2020-2023  润新知