在IEEE 754标准中
在IEEE 754标准中,规定了浮点数的二进制表达方式:x = (-1)^s * (
1 + M) *2^e。其中s是符号位,M是尾数,e是指数。尾数M是一个[
0, 1)范围内的二进制表示的小数。以32位浮点为例,如果只有normal形式的话,0表示为所有位数全
0,则最小的非零正数将是尾数最后一位为1的数字,就是(1+2^(-23))*2^(-127),而次小的数字为(1+2^(-22))*2^(-127),这两个数字的差距为2^(-23)*2^(-127)= 2^(-150),然而最小的数字和0之间的差距有(1+2^(-23))*2^(-127),约等于2^(-127),也就是说,数字在渐渐减少到0的过程中突然降到了
0。为了减少0与最小数字和最小数字与次小数字之间步长的突然下跌,subnormal规定:当指数位全0的时候,指数表示为-126而不是-127(和指数为最低位为1一致)。然而公式改成(-1)^s *
M * 2^e, M不再+
1,这样最小的数字就变成2^(-23)*2^(-126),次小的数字变成2^(-22)*2^(-126),每两个相邻subnormal数字之差都是2^(-23)*2^(-126),避免了突然降到
0。在这种状态下,这个浮点数就处于了Subnormal状态,处于这种状态下的浮点数表示精度比Normal状态下的精度低一点。我们用一个示例来演示一下什么是Subnormal状态的浮点数:
fn main() {
// 变量 small 初始化为一个非常小的浮点数
let mut small = std::f32::EPSILON;
// 不断循环,让 small 越来越趋近于
0,直到最后等于0的状态
while small > 0.0 {
small = small / 2.0;
println!("{} {:?}", small, small.classify());
}
}
编译,执行,发现循环几十次之后,数值就小到了无法在32bit范围内合理表达的程度,最终收敛到了
0,在后面表示非常小的数值的时候,浮点数就已经进入了Subnormal状态。
为了防止老年痴呆
为了防止老年痴呆,
有的人,选择打麻将;
有的人,选择打扑克;
而我,选择了写代码。
上回说到,一个字符串的整型的乘法算法,但是如果是带小数的乘法算法是如何计算的呢?
我是回忆了小学老师是如何教我们乘法的,但是整型的乘法我会,带小数点的是怎么做的呢?
不仅我忘了,我还特意问了好几个同事,感觉都不知道怎么计算。
后来灵机一动,搞懂了,先计算出小数点的尾数,然后忽略小数点用整型计算,结果之后把小数点给加上去。
那么实现方案就来了。
public static String mul(String s1, String s2) {
int decimalLen = 0;
String[] s1s = s1.split(&34;);
String s1I = s1s[0];
String s1D = &34;;
if (s1s.length > 1) {
s1D = s1s[1];
}
String[] s2s = s2.split(&34;);
String s2I = s2s[0];
String s2D = &34;;
if (s2s.length > 1) {
s2D = s2s[1];
}
//计算小数的位数
decimalLen = s1D.length() + s2D.length();
//合并为整型
s1 = s1I + s1D;
s2 = s2I + s2D;
//整型相乘,看上次的方法
String result = mulInt(s1, s2);
//赋小数点
if (decimalLen > 0) {
result = new StringBuilder(result).insert(result.length() - decimalLen, &34;).toString();
}
return result;
}
不知道各位码农,是否明白了呢?
关注【我是Java程序猿】,每天学一点,进步快一点。
Java服务端研发岗
Java服务端研发岗,今天面试拼多多,那个主管一上来就给了我几道微积分的高等数学题。毕业后数学就不碰了,实在做不来。主管说再给我一次机会,就详细问了我浮点数表示法IEEE754相关的东西,我只记得是大学本科时计算机组成原理的东西,貌似就是用来表示浮点数的一些规则,具体的东西答不上来。那个主管叹了口气,说:微积分你不会,那么我们的砍一刀项目你怎么来设计每一刀的量?浮点数你不会,那么如果有主播恶意拉人砍价,你怎么保证在当前计算机架构下正确地表示出几百万粉丝砍价后的小数点
我羞愧地低下头,默默离开。
------------------
从研发角度来看,是一个很好的问题,试着展开聊一下。
砍一刀的逻辑:找一个在0~∞的区间内积分为1的函数,然后每个人根据其位次取函数值即可。
再说说浮点型怎么表示,开发语言中一般的浮点型精度都在六七位(4个字节),双精度浮点型在15、6位(8个字节),如果要更高的精度,就得自己实现了。思路跟IEEE754相同,需要加大小数的表示位数,原先用52bit表示小数,现在应该改用更多的bit,相应的字节数最好扩展到16个字节甚至更多。