如果使用舍入,有人会不会遇到对浮点数进行简单算术运算的错误结果?

时间:2018-11-13 13:33:46

标签: javascript math floating-point

请注意:我要说的数字是货币,因此小数部分的位数不能超过两位。

我已经用两种算法测试了4个库(Decimal.js,Numeral.js,Big.js和Math.js)和一个简单的简单javascript实现功能(使用Math.round来切除小数部分)。操作:

  • 0.55 * 100 => 55 //却给出55.00000000000001
  • 0.2 + 0.1 => 0.3 //但它给出的是0.30000000000000004

测试脚本(节点v10.4.1,Ubuntu 16.04LTS)

const { Decimal } = require('decimal.js')
const numeral = require('numeral')
const Big = require('big.js')
const math = require('mathjs')

const assert = require('assert')

function roundMultiply () {
  return Math.round(0.55 * 100)
}

function roundAdd () {
  return Math.round((0.2 + 0.1) * 100) / 100
}


function decimalMultiply () {
  return new Decimal(0.55).mul(new Decimal(100))
}

function decimalAdd () {
  return new Decimal(0.2).add(new Decimal(0.1))
}


function numeralMultiply () {
  return numeral(0.55).multiply(100).value()
}

function numeralAdd () {
  return numeral(0.2).add(0.1).value()
}


function bigJsMultiply () {
  return +(new Big(0.55).times(100))
}

function bigJsAdd () {
  return +(new Big(0.2).add(0.1))
}


function mathJsMultiply () {
  return math.number(math.multiply(math.fraction(0.55), 100))
}

function mathJsAdd () {
  return math.number(math.add(math.fraction(0.2), math.fraction(0.1)))
}

function test (fun, funName) {
  console.time(funName)

  for (let i = 0; i < 100000; i++) {
    fun()
  }

  console.timeEnd(funName)
}

console.log('test multiplication results...')

assert(String(roundMultiply()) === '55')
assert(String(decimalMultiply()) === '55')
assert(String(numeralMultiply()) === '55')
assert(String(bigJsMultiply()) === '55')
assert(String(mathJsMultiply()) === '55')

console.log('test multiplication performance...')

test(roundMultiply, 'roundMultiply')
test(decimalMultiply, 'decimalMultiply')
test(numeralMultiply, 'withNumeral')
test(bigJsMultiply, 'withBigJs')
test(mathJsMultiply, 'mathJsMultiply')

console.log('test adding results...')

assert(String(roundAdd()) === '0.3')
assert(String(decimalAdd()) === '0.3')
assert(String(numeralAdd()) === '0.3')
assert(String(bigJsAdd()) === '0.3')
assert(String(mathJsAdd()) === '0.3')

console.log('test adding performance...')

test(roundAdd, 'roundAdd')
test(decimalAdd, 'decimalAdd')
test(numeralAdd, 'numeralAdd')
test(bigJsAdd, 'bigJsAdd')
test(mathJsAdd, 'mathJsAdd')

结果

roundMultiply: 2.673ms
withBigJs: 123.759ms
decimalMultiply: 172.068ms
withNumeral: 206.626ms
mathJsMultiply: 255.870ms

roundAdd: 2.317ms
mathJsAdd: 68.212ms
numeralAdd: 139.752ms
decimalAdd: 184.210ms
bigJsAdd: 222.685ms

如您所见,roundAddroundMultiply远远领先于所有其他功能。

我的主要问题:是否存在小数部分最多为两位数的操作数,并且这样的操作数在执行简单的算术运算(+,-,*,/)时会给出错误的答案使用Math.round时的结果?因为我看不出有任何理由需要考虑它们的性能而使用其中任何一个(或其他库)。

0 个答案:

没有答案