专栏首页杨飞@益术JavaScript中科学计数法的问题

JavaScript中科学计数法的问题

JavaScript 中经常会碰到数值计算问题,偶尔会在不经意间报一个不是bug的bug。今天来说说一个特殊的例子。我以0.0011BTC 价格买入 0.0002CZR 计算出了的金额是 0.00000022BTC,而 JavaScript 计算出来的金额是 2.2e-7 。值是对的,只是用了科学计数法,也是数值类型。但是问题来了,一般用户用户看不懂 2.2e-7,那么就把它转换成 0.00000022 吧。然而问题了,我用尽办法,怎么样都无法将 2.2e-7 转换成直观的 0.00000022。或许你会嘲笑我,告诉我直接用 .toFixed() 方法。但是新问题又来了, .toFixed() 会保留足够的小数位,比如:2e-7.toFixed(8) 得到的值是 0.000000202e2.toFixed(8)得到的值是 200.00000000。最后的 0 让我感到多余…

问题分析

问题还是要解决,只能深入了解 JavaScript 中科学计数法相关的知识。对于极大或者极小的数,可以用科学计数法 e来表示的浮点数值来表示。科学计数法允许字母eE 的后面,跟着一个整数,表示这个数值的指数部分。

以下两种情况,JavaScript 会自动将数值转为科学计数法表示

(1) 小于1且小数点后面带有6个0以上的浮点数值:

JavaScript 代码:

0.0000003 // 3e-7
0.00000033 // 3.3e-7
0.000003 // 0.000003

(2) 整数位数字多于21位:

JavaScript 代码:

1234567890123456789012 //1.2345678901234568e+21
1234567890123456789012.1 //1.2345678901234568e+21
123456789012345678901 //123456789012345680000

解决思路

首先看看整数位数字多于21位的情况,其实这个一般不会碰到,整数位数字多于21位已经超出了 JavaScript 精确整数范围 ?9007199254740992 至 9007199254740992 (即正负2的53次方)。如果你需要可以是使用 bignumber.js。一般情况你可以使用.toString() 将科学计数法的数字转化为直观的数字表示,例如:

JavaScript 代码:

""+1.401e10 // "14010000000"
1.401e10.toString(10) // "14010000000"

小于1且小数点后面带有6个0以上的浮点数值自动转化为科学计数法,要想转换成直观的数字表示就没那么容易了,我尝试了几种办法:

JavaScript 代码:

""+3.3e-7 //"3.3e-7"
3.3e-7.toString(10) //"3.3e-7"

都没达到我的预期。

解决问题

精度计算的时候我们通常会使用 .toFixed() 方法,Number.toFixed(digits) 方法使用定点表示法来格式化一个数,会对结果进行四舍五入。参数 digits 表示小数点后数字的个数,一般介于 0 到 20 (包括)之间。例如:

JavaScript 代码:

3.3e-7.toFixed(8); // "0.00000033"
3e-7.toFixed(8); // "0.00000030"

一般情况下,我们的需求小数位数是固定的,所以这个基本可以满足我们的需求。但是有些人可能不喜欢 0.00000030 这种形式,认为最后的 0 是多余的。所以索性就改进了一下:

JavaScript 代码:

function toNumberStr(num,digits) {
// 正则匹配小数科学记数法
if (/^(\d+(?:\.\d+)?)(e)([\-]?\d+)$/.test(num)) {
// 正则匹配小数点最末尾的0
var temp=/^(\d{1,}(?:,\d{3})*\.(?:0*[1-9]+)?)(0*)?$/.exec(num.toFixed(digits)) ;
if(temp){
return temp[1];
}else{
return num.toFixed(digits)
}
}else{
return ""+num
}
}
 
toNumberStr(3.3e-7,8) // "0.00000033"
toNumberStr(3e-7,8) // "0.0000003"
toNumberStr(1.401e10,8) // "14010000000"
toNumberStr(0.0004,8) // "0.0004"

这个方法基本满足了我的需求,但是总是觉得一点累赘,后面那个参数意思也不够明确,所以发到微信群请大家帮忙优化。特别感谢网友 @caikan 提供的方法:

JavaScript 代码:

function toNonExponential(num) {
var m = num.toExponential().match(/\d(?:\.(\d*))?e([+-]\d+)/);
return num.toFixed(Math.max(0, (m[1] || '').length - m[2]));
}
toNonExponential(3.3e-7) // "0.00000033"
toNonExponential(3e-7) // "0.0000003"
toNonExponential(1.401e10) // "14010000000"
toNonExponential(0.0004) // "0.0004"

解析一下:

.toExponential()将数字转化为科学记数法表示,匹配正则表达式/\d(?:\.(\d*))?e([+-]\d+)/,获取科学记数法中小数点后的字符及幂指数(e 后面的值),这样可以确定数字是几位小数。再用toFixed()转换成数值表示。

转自:https://www.html.cn/archives/9318

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • JAVA递归

         //斐波那契      // num 第几个数      // search(num - 1)临近的第一个+move(num - 2)临近的...

    用户2192970
  • 高效开发Android App的10个建议

    假如要Google Play上做一个最失败的案例,那最好的秘诀就是界面奇慢无比、耗电、耗内存。接下来就会得到用户的消极评论,最后名声也就臭了。即使你的应用设计...

    用户2192970
  • JAVA金额转换,阿拉伯数字的金额转…

         return sb.reverse().toString().replaceAll("零[拾佰仟]","零").replaceAll("零+万","...

    用户2192970
  • CentOS7上安装 JDK8 Hadoop Hive

    下载:https://pan.baidu.com/s/17ZDrs9n3geawFZZltvsbTQ 提取码: ph6v

    hankleo
  • 算法导论第十一章 散列表

    一、散列表的概念 本章介绍了散列表(or hash table)的概念、散列函数的设计及哈希冲突的处理。散列表(为了形象描述,我们通常叫槽)从表意上看是一种数...

    猿大白
  • NDK 开发中的几个重要知识点

    在 Native 层中通过 JNI 可以自由地访问 Java 对象,访问 Java 对象一般分为 3 步。

    字节流动
  • HTML教程-各窗口间相互操作(Frame Target)

    文章来源:山西之窗由Frames分出来的几个窗口的内容并不是静止不变的,往往一个窗口的内容随着...

    Java架构师必看
  • Falcosidekick + Kubeless = Kubernetes响应引擎

    两年前,我们向你们展示了一个基于 Falco 的 Kubernetes 响应引擎(Kubernetes Response Engine)。其想法是触发无 Kub...

    CNCF
  • R语言数据可视化分析案例:探索BRFSS数据

    描述如何收集样本中的观测值,以及此数据收集方法对推断范围(可概括性/因果关系)的影响。http://www.cdc.gov/brfss/,以及下面的“有关数据的...

    拓端
  • GIF格式解析

    Oceanlong

扫码关注云+社区

领取腾讯云代金券