车间的工人在生产出来产品后,需要完成初步的自检,并通过手机上报。在实际生产中,用户(工人)不方便进行数值的输入,因而表单中的一些项设计成 picker 模式以供选取数值。数值的取值范围,根据允许的误差范围生成。示例如下:
示例一
// 误差
0.01mm ~ 0.06mm
// picker 展示的数值
0.01, 0.02, 0.03, 0.04, 0.05, 0.06
示例二
// 误差
15mm ~ 18mm
// picker 展示的数值
15, 16, 17, 18
示例三
// 误差
1.05mm ~ 1.1mm
// picker 展示的数值
1.05, 1.06, 1.07, 1.08, 1.09, 1.1
由以上例子可以得知,取值范围的计算是根据误差范围的最小值的最小位数作为基数,从最小值(包含)逐步累加至最大值(包含)。
首先,根据最小值获取小数位的个数。
function getDecimalPlace(value) {
// 先将 Number 转换为 String
value = value + '';
// 查找小数点的位置,加 1 是为了方便计算小数点的位数。
var floatIndex = value.indexOf('.') + 1;
// 返回的结果是小数位的个数
return floatIndex ? value.length - floatIndex : 0;
}
用几个实际的数值,测试一下这个方法。
getDecimalPlace(1); //0
getDecimalPlace('1.0'); //0
getDecimalPlace('1.5'); //1
getDecimalPlace('1.23'); //2
然后,根据小数位的个数计算累加的基数。
var min = 0.01;
var max = 0.06;
var decimal = getDecimalPlace(min);
// 基数
var radixValue = Math.pow(10, -decimal);
最后,根据误差范围和基数,循环生成取值范围。
var value = min;
var range = [];
for (; value <= max; value += radixValue) {
range.push(value);
}
console.log(range);
//结果:[0.01,0.02,0.03,0.04,0.05]
从结果来看,好像哪里不对。没错,最大值 0.06 没有出现在取值范围中。
JavaScript 采用了 IEEE-754 浮点数表示法。这是一种二进制表示法,二进制浮点数表示法并不能精确表示类似 0.1 这样简单的数字。
通过一个简单的例子来验证上面这段话。
var num1 = 0.2 - 0.1;
var num2 = 0.3 - 0.2;
console.log(num1 === num2); //false
console.log(num1 === 0.1); //true
console.log(num2 === 0.1); //false
由此可知,前面计算取值范围的方法中,遇到了类似的问题。
var max = 0.06;
var value = 0.05;
console.log(value + 0.01 === max); //false
因为从 0.05 + 0.01 的结果并不等于 0.06,所以循环只执行了 5 次(而非预期的 6 次)就结束了。
在尝试修复此问题之前,先把前面的代码封装一下。
function getRange(min, max) {
var decimal = getDecimalPlace(min);
var radixValue = Math.pow(10, -decimal);
var value = min;
var range = [];
for (; value <= max; value += radixValue) {
range.push(value);
}
return range;
}
最简单粗暴的办法,就是调整循环条件,在循环结束后再将最大值添加至数组。
function getRange(min, max) {
var decimal = getDecimalPlace(min);
var radixValue = Math.pow(10, -decimal);
var value = min;
var range = [];
for (; value < max; value += radixValue) {
range.push(value);
}
range.push(max);
return range;
}
再次使用之前的数据测试:
getRange(0.01, 0.06);
//结果:[0.01,0.02,0.03,0.04,0.05,0.06]
运行结果与预期一致,问题解决。
然而,后续的测试中又出现了意外。
getRange(1.55, 1.65);
// 结果:[1.55,1.56,1.57,1.58,1.59,1.6,1.61,1.62,1.6300000000000001,1.6400000000000001,1.65]
1.6300000000000001 这样的数值,显然不是我们期望得到的。出现此现象,与之前的问题原因一致。
方案一
将参与计算的数值,先转换为整型,再进行计算。
function getRange(min, max) {
var decimal = getDecimalPlace(min);
var radixValue = Math.pow(10, -decimal);
var multi = Math.pow(10, decimal)
var value = min * multi;
var range = [];
for (; value < max * multi; value += radixValue * multi) {
range.push(value / multi);
}
range.push(max);
return range;
}
注意事项:
方案二
使用 toFixed() 方法,对浮点型进行格式化。
function getRange(min, max) {
var decimal = getDecimalPlace(min);
var radixValue = Math.pow(10, -decimal);
var value = min;
var range = [];
for (; value < max || +value.toFixed(decimal) === max; value += radixValue) {
range.push(+value.toFixed(decimal));
}
return range;
}
注意事项:
JavaScript 中浮点型精度的误差,是非常基础但是却又经常不被重视的问题。文中分享的方案,足以覆盖项目中的所有情况,但如果用在其它地方或项目中,在一些极端情况下可能会有问题。
由于 JavaScript 采用 IEEE 754 标准,数值存储为64位双精度格式,数值精度最多可以达到 53 个二进制位(1 个隐藏位与 52 个有效位)。如果数值的精度超过这个限度,第54位及后面的位就会被丢弃.
由于js的弱精度,在计算小数相加时总是会丢失精度,JS将金额数字转大写的方法封装,数字大写对照表;下面为大家整理些常用的实现方法。
isNaN()的缺点就在于 null、空格以及空串会被按照0来处理;对于空数组和只有一个数值成员的数组,isNaN返回false。校验只要是数字(包含正负整数,0以及正负浮点数)就返回true
最近遇到一个需求,需要限制文本框输入数字,而number类型的输入框有箭头,个人不是很喜欢,因此想要寻求其它途径实现。本想通过网上找个现成的插件,然而百度,谷歌一番都没有找到满意的答案,至于随手一搜出来的方案或多或少都有点缺陷。因此自己动手,丰衣足食。
最近在看计算机组成原理的浮点数部分,突然想起之前看过的一道快手面试题,为什么JS中0.1+0.2不等于0.3,应该如何解决?这里我们可以借这道题来说一下JS的精度问题
Infinity(无穷大)在 JS 中是一个特殊的数字,它的特性是:它比任何有限的数字都大,如果不知道 Infinity, 我们在一些运算操作遇到时,就会觉得很有意思。现在我们来看看 JS 中的Infinity 属性,了解用例并解决一些常见的陷阱。
这是一种通用方法,我们首先检查数字是已经是正数还是负数,如果数字是负数,那么我们将数字乘以-1以使其为正数。使用Math.abs()方法将负数转换为正数。
如果想要将一个字符串中的数字给提取出来,这要怎么做? 在JavaScript中可以使用match()方法将字符串中的数字提取到数字数组中。此方法将正则表达式作为参数,并从字符串中提取数字。使用match()方法提取数字分两种情况:
javascript如何判断一个值是否是数字?下面本篇文章就来给大家介绍一下使用javascript判断一个值是否是数字的方法,sNaN() 函数用于检查其参数是否是非数字值。如果 值x 是特殊的非数字值 NaN
JavaScript判断两个整数(a,b,a>b)的整除时,可以用Number.isInteger(a/b)或者a%b==0来进行判断,但是如果其中涉及到小数就会导致计算过程中精度丢失。
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!