float 的取值范围问题
1.试问取值范围是只取指数部分吗,小数位不理会吗2.请问能详细解说取值范围数字如何得来,指数位有8位,所以0和1排列组合2^8=256,到这后面我就不懂了,还有最后为什么是-2^128 ~ +2^128,也即-3.40E+38 ~ +3.40E+38.. 那个2怎么来的,能詳細介紹取值範圍的算式嗎,感謝
计算机内核是玩二进制的 数学劝退{:10_266:}{:10_266:} 有大佬能夠解答嗎 浮点数在机内用指数型式表示,分解为:数符,尾数,指数符,指数四部分。
数符占 1 位二进制,表示数的正负。
指数符占 1 位二进制,表示指数的正负。
尾数表示浮点数有效数字,0.xxxxxxx, 但不存开头的 0 和点。
指数存指数的有效数字。
指数占多少位,尾数占多少位,由计算机系统决定。 看下面的内容之前,你要先看过这篇文章或者类似的文章
浮点数在计算机中的存储方式:https://www.cnblogs.com/wuyuan2011woaini/p/4105765.html
float类型的浮点数的存储格式使用的是 IEEE 的 R32.24 标准
就是 1位符号位,8位指数位,23位尾数位
那么如何得到最大值呢?
在计算机中不是1就是0
1 大于 0
全 1 就是最大了
那就这样
0 11111111 11111111111111111111111 # 最大
符号位是0,表示这是一个正数
“元数据+127:大概是指“指数”从00000000开始(表示-127)至11111111(表示+128)”
就是说指数部分的这个 11111111,表示的其实是 128
“任何一个数的科学计数法表示都为1. xxx * 2n ,尾数部分就可以表示为xxxx,由于第一位都是1嘛,干嘛还要表示呀?所以将小数点前面的1省略。”
所以上面那个值就可以写成这样
1.11111111111111111111111 * 2^128 # 小数点后面有23个1
这个写法可能不方便理解,不方便之后的计算,换成下面这样的写法,不使用科学记数法
# 24个1,105个0
111111111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
这个就是最大值,但是这是二进制形式的,要转换成十进制才更方便理解
怎么转呢?这就是另外一个问题了
二进制转十进制,自己百度
但是嘛,就是你会转换,这个规模的数字也不应该人工进行转换
现在用我们的python来转换
$ cat main.py
#!/usr/bin/env python
#coding=utf-8
#number = '1110'
number = '111111111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
number_len = len(number)
result = 0
for i in range(number_len):
if number == '1':
result += 2**i
print(result)
print(f'{result:e}')
$ ./main.py
680564693277057719623408366969033850880
6.805647e+38
$
这么一长串的二进制转成十进制是 680564693277057719623408366969033850880
科学记数法表示成 6.805647e+38
这个明显不是最大值,因为你题目中说最大值是 3.40E+38 (-3.40E+38 ~ +3.40E+38)
问题的原因是浮点数中有两个特殊值 INF 和 NAN
确实是两个,IND其实就是NAN,他们是一回事,不同的环境可能会选NAN,也可能选IND
不管怎么说,他们是完全一样的,都是一回事
INF IND NAN 参考下面的文章
https://www.cnblogs.com/Malphite/p/12068991.html
https://www.thinbug.com/q/15288406
“
阶码全1,尾数全0表示无穷大INF。例如1.0/0.0
阶码全1,尾数非全0的表示无效数NaN。例如:求负数的平方根,例如0.0/0.0。
”
也就是说 指数部分不能全1,全1已经给这两个特殊值占用了
那就让 11111111 减 1,就是去掉这两个特殊值后的最大值
0 11111110 11111111111111111111111 # 最大
没错,这里是127,之前是128
1.11111111111111111111111 * 2^127 # 小数点后面有23个1
# 24个1,104个0
111111111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
现在,再让咱们的python算一下这个十进制是多少
$ cat main.py
#!/usr/bin/env python
#coding=utf-8
#number = '1110'
number = '11111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
number_len = len(number)
result = 0
for i in range(number_len):
if number == '1':
result += 2**i
print(result)
print(f'{result:e}')
$ ./main.py
340282346638528859811704183484516925440
3.402823e+38
$
这一次算出的结果是 340282346638528859811704183484516925440
科学记数法表示成 3.402823e+38
这个就是float的最大值
最小值?
简单,前面加上一个负号就是了
所以float的取值范围就是
-340282346638528859811704183484516925440 ~ 340282346638528859811704183484516925440
科学记数法就表示成
-3.402823e+38 ~ 3.402823e+38
这里用C语言验证一下,发现没有问题
$ cat main.c
#include <stdio.h>
#include <stdint.h>
void binary(char *buff, const void *data, size_t size) {
uint8_t byte = *(const uint8_t *)(data + size - 1);
for(size_t mask = 0x80; mask; mask >>= 1) {
*buff++ = mask & byte ? '1': '0';
}
if(size == 1) {*buff = '\0'; return;}
*buff++ = '_'; binary(buff, data, size - 1);
}
int main(void) {
char buff;
float data = 340282346638528859811704183484516925440.0;
binary(buff, &data, sizeof(data));
printf("float:\t%s\n", buff);
return 0;
}
$ gcc-debug -o main main.c
$ ./main
float: 01111111_01111111_11111111_11111111
$
页:
[1]