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;                                \
 })
 

 

posted on 2022-05-18 19:44  tycoon3  阅读(575)  评论(0)    收藏  举报

导航