js精度计算

JavaScript035

js精度计算,第1张

在新公司的第一个项目是区块链相关的管理后台和交易所,其中就涉及了很多的计算问题。而JavaScript因为存在计算的精度问题,所以直接计算就可能会导致各种各样的bug,为了解决这个问题,就要使用BigNumber.js这个库。

至于为什么JavaScript会有精度问题呢,可以看 这里 。简单来说就是因为: JavaScript中所有的数字(包括整数和小数)都只有一种类型–Number。它的实现遵循IEEE 754标准,使用64位固定长度来表示,也就是标准的double双精度浮点数。它的优点是可以归一化处理整数和小数,节省储存空间。而实际计算的时候会转换成二进制计算再转成十进制。进制转换之后会很长,舍去一部分,计算再转回来,就有了精度误差。

BigNumber.js是一个用于任意精度计算的js库。可以在  官方文档  的console中测试使用。也可以通过npm install bignumber.js --save来安装。然后 import BigNumber from 'bignumber.js' 来引入使用。他的大概原理是将所有数字当做字符串,重新实现了计算逻辑。缺点是性能比原生的差很多。

现在 TC39 已经有一个 Stage 3 的提案 proposal bigint,大数问题有望彻底解决。在浏览器正式支持前,可以使用 Babel 7.0 来实现,它的内部是自动转换成 big-integer 来计算,要注意的是这样能保持精度但运算效率会降低。

具体用法可以参考以下资料:

官方文档

bignumber.js使用记录

BigNumber 讲解

就不再敖述了,下边随便写点常用的方法:

// 转为 bignumberconstx=newBigNumber('123456789.123456789')// 转为 普通数字x.toNumber()// 格式化(小数点)x.toFormat()// '123,456,789.123456789'x.toFormat(3)// '123,456,789.123'// 计算x.plus(0.1)// 加法x.minus(0.1)// 减法x.times(0.1)// 乘法x.div(0.1)// 除法x.mod(3)// 取模/取余// 比较大小x.eq(y)// isEqualTo 的简写,是否相等x.gt(y)// isGreaterThan 的简写,是否大于x.gte(y)// isGreaterThanOrEqualTo 的简写,是否大于等于x.lt(y)// isLessThan 的简写,是否小于x.lte(y)// isLessThanOrEqualTo 的简写,是否小于等于// 取非,改变数字的正负号x.negated()

从版本

8.5.0

开始,Node.js

开始支持原生

ES

模块,可以通过命令行选项打开该功能。新功能很大程度上得归功于

Bradley

Farias。

1.演示

这个示例的代码目录结构如下:

esm-demo/

lib.mjs

main.mjs

lib.mjs:

export

function

add(x,

y)

{

return

x

+

y

}

main.mjs:

import

{add}

from

'./lib.mjs'

console.log('Result:

'+add(2,

3))

运行演示:

$

node

--experimental-modules

main.mjs

Result:

5

2.清单:需要注意的事情

ES

模块:

·不能动态导入模块。但是

动态import()

的相关工作正在进行中,应该很快就能提供支持。

·没有元变量,如

__dirname

__filename。但是,有一个的类似功能的提案:“import.meta”。看起来可能是这样:

console.log(import.meta.url)

·现在所有模块标识符都是

URL(这部分在

Node.js

是新增的):

·文件

-

带文件扩展名的相对路径:

../util/tools.mjs

·库

-

没有文件扩展名,也没有路径

lodash

·如何更好地使

npm

库在浏览器中也可用(不使用

bundler)仍有待观察。一种可能性是引入

RequireJS

风格的配置数据,将路径映射到实际路径。目前,在浏览器中使用

bare

path

的模块标识符是非法的。

CJS

模块的互操作性

你可以导入

CJS

模块,但它们总是只有默认的导出

-

module.exports

的值。让

CJS

模块支持命名导出已经在做了,但可能需要一段时间。如果你能帮忙,可以来做。

import

fs1

from

'fs'

console.log(Object.keys(fs1).length)

//

86

import

*

as

fs2

from

'fs'

console.log(Object.keys(fs2))

//

['default']

·

不能在

ES

模块中使用

require()。主要原因是:

· 路径解析工作稍有不同:ESM

不支持

NODE_PATH

require.extensions。而且,它的标识符始终是

URL

也会导致一些细微差异。

·

ES

模块始终以异步方式加载,这确保了与

Web

的最大兼容性。这种加载风格并不能通过

require()

混合使用同步加载

CJS

模块。

·

禁止同步模块加载也可以为

Top-level

await

导入

ES

模块保留后路(一个当前正在考虑的功能)。

3.早期版本的

Node.js

上的

ES

模块

如果要在

8.5.0

之前的

Node.js

版本上使用

ES

模块,请参阅

John-David

Dalton

@std/esm。

提示:如果不启用任何可解锁的额外功能,将在

Node.js

保持

100%

兼容原生

ES

模块.

FAQ

什么时候可以不带命令行选项使用ES

模块?

目前的计划是在

Node.js

10

LTS

中默认可使用

ES

模块。

进一步阅读

有关

Node.js

和浏览器中

ES

模块的更多信息:

·

“Making

transpiled

ES

modules

more

spec-compliant”

[using

ES

modules

natively

vs.

transpiling

them

via

Babel]

·

“Module

specifiers:

what's

new

with

ES

modules?”

[Why

.mjs?

How

are

module

specifiers

resolved?

Etc.]

·

“Modules”

[in-depth

chapter

on

ES

modules

in

“Exploring

ES6”]

即将到来的

ECMAScript

提案:

·

博客:

“ES

proposal:

import()

dynamically

importing

ES

modules”

·

提案:

“import.meta”

总结

以上就是小编给大家带来的在

Node.js

中使用原生

ES

模块方法解析的全部内容,希望对大家有所帮助。如果您有什么问题,可以给我留言。感谢大家对本站的支持。