飞道的博客

小数型Number在web中最出色的两个应用场景

434人阅读  评论(0)

我们大概都知道的是:精确度问题不仅在前端,甚至在整个编程领域都是“由来已久”的。

前端的精确度问题大概要从 Math.floor(number) 向下取整、 Math.round(number) 四舍五入但是round函数在正数和负数表现竟然有差异为开端。

这里不得不提一句:Math.round的实现原理其实是“将参数加上0.5再向下取整”,也就是说并不是真正的“四舍五入”!

同样的还有因为二进制转换和存储问题导致的0.1+0.2!=0.3的问题。但是这不是重点:我们将以此引出它们在浏览器中的使用:


浏览器对于小数型px的解析

不知啥时候开始,喜欢上用小数值px表示宽/高/字体size,后来仔细一看,确实无意中有一些帮助:
我们会发现,同样是11.9px,在不同内核浏览器上表现是不同的:如
(IE)

(google)

这里为什么用11.9呢?因为我们应该都知道:在浏览器中中文字体“正常”显示的下限像素值是12px。这里再对比一下:
(IE)

(google)

再对比上面的两张图,我们似乎能发现:11.9在IE下被解析为11,而在像Firefox、google这种W3C标准浏览器中,其被解析为12。

这个的作用还不小 —— 有了IE和其余浏览器解析小数的不同,在一些要 考虑兼容性 的大小细节问题上,我们就完全不用hack插手,直接一段代码莽上去就OK了?(要知道:大量“冗杂”的CSS代码也是会对页面渲染有影响的!)

padding: 0 12px;
*padding: 0 11px;

直接改写为:

padding: 0 11.9px;

完美!


还有一个为我们所熟知的地方就是:toFixed() —— 校正精确度函数。

但是这个函数有一些令人哭笑不得的小坑,比如:有个别浏览器并不会对最后的值进行“四舍五入”、小数点后位数不同结果不同:

更新,有改动 ☟)
上面情况类似的还有很多,经过笔者查阅资料和实践发现:是因为Number运算转化为二进制运算,而二进制与十进制之间转化时的精度丢失导致!

在大多数时候,其实我们是要 重写 toFixed()方法的:

if(0.9.toFixed(0)!=='1'){
   
    Number.prototype.toFixed=function(n){
   
	let power=Math.pow(10,n);   //10的n次幂
	let fixed=(Math.round(this*power)/power).toString();
	if(n===0){
   
		return fixed;
	}
	if(fixed.indexOf('.')<0){
   
		fixed+='.';
	}
	let padding=n+1-(fixed.length-fixed.indexOf('.'));
	for(let i in padding){
   
		fixed+='0';
	}
	return fixed;  
    }
}

这段代码很显然并没有解决大多数运算误差(感谢评论区指出!),而经过测试,发现其根本原因是:还没有考虑到Number运算的“精度丢失”问题
问题出在上面第4行:this乘以power时发生了精度丢失,导致最后一位发生变化,而Math.round()又是依赖“加0.5再floor”的策略,导致事实上某些情况下最后一位是被丢掉而非进位!

出于这种考虑,笔者建议这里采用一个“取巧”的方式:+0.1
这样在因精度损失而整体变小的数中会补上,整体变大的数中因为round函数取整也没有什么变化。

let fixed=(Math.round(this*power+0.1)/power).toString();


撒花!


转载:https://blog.csdn.net/qq_43624878/article/details/108441209
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场