/JSBD

a jsbi style BigDecimal polyfill

Primary LanguageTypeScriptMIT LicenseMIT

JSBD

npm version Coverage Badge

a JSBI style polyfill for BigDecimal

This is a polyfill for BigDecimal , which implement tc39-bigDecimal proposal https://github.com/tc39/proposal-decimal

And some result of the method referred Java.math.BigDecimal

typescript and 100% case coverage

babel plugin

https://github.com/yukinotech/babel-plugin-transform-jsbd-to-bigdecimal

convert JSBD to native BigDecimal syntax, when it is able to use native BigDecimal syntax in browser.

install

// use npm
npm install jsbd
// or use yarn
yarn add jsbd

usage

JSBD.BigDecimal

use JSBD.BigDecimal to init a BigDecimal object

import JSBD from 'jsbd'

let a = JSBD.BigDecimal(3) // returns 3m
let b = JSBD.BigDecimal('345') // returns 345m
let c = JSBD.BigDecimal('115e-10') // returns 0.0000000115m
let d = JSBD.BigDecimal(2545562323242232323n) // results 2545562323242232323m
let e = JSBD.BigDecimal(true) // Throws TypeError
let f = JSBD.BigDecimal(false) // Throws TypeError
let g = JSBD.BigDecimal(null) // Throws TypeError
let h = JSBD.BigDecimal(undefined) // Throws TypeError
let i = JSBD.BigDecimal(0.1) // returns 0.1m

JSBD.round(value [, options])

This is the function to be used when there's need to round BigDecimals in some specific way. It rounds the BigDecimal passed as parameter, taking in consideration options.

  • value: A BigDecimal value. If the value is from another type, it throws TypeError.
  • options: It is an object indicating how the round operation should be performed. It is an object that can contain roundingMode and maximumFractionDigits properties.
    • maximumFractionDigits: This options indicates the maximum of factional digits the rounding operation should preserve. If it is undefined, round operations returns value.
    • roundingMode: This option indicates which algorithm is used to round the given BigDecimal. Each possible option is described below.
      • down: round towards zero.
      • half down: round towards "nearest neighbor". If both neighbors are equidistant, it rounds down.
      • half up: round towards "nearest neighbor". If both neighbors are equidistant, it rounds up.
      • half even: round towards the "nearest neighbor". If both neighbors are equidistant, it rounds towards the even neighbor.
      • up: round away from zero.
let a = JSBD.round(0.53m, { roundingMode: 'half up', maximumFractionDigits: 1 })
assert(a, 0.5m)

a = JSBD.round(0.53m, { roundingMode: 'half down', maximumFractionDigits: 1 })
assert(a, 0.5m)

a = JSBD.round(0.53m, { roundingMode: 'half even', maximumFractionDigits: 1 })
assert(a, 0.5m)

a = JSBD.round(0.31m, { roundingMode: 'down', maximumFractionDigits: 1 })
assert(a, 0.3m)

a = JSBD.round(0.31m, { roundingMode: 'up', maximumFractionDigits: 1 })
assert(a, 0.4m)

JSBD.add(lhs, rhs [, options])

This function can be used as an alternative to + binary operator that allows rounding the result after the calculation. It adds rhs and lhs and returns the result of such operation, applying the rounding rules based on options object, if given. options is an options bag that configures the rounding of this operation.

  • lhs: A BigDecimal value. If the value is from another type, it throws TypeError.
  • rhs: A BigDecimal value. If the value is from another type, it throws TypeError.
  • options: It is an object indicating how the round operation should be performed. It's the same options bag object described on JSBD.round. If it's not given, no rounding operation will be applied, and the exact result will be returned.
let a = JSBD.BigDecimal('1.25')
let b = JSBD.BigDecimal('644e-2')
// 1.25 + 6.44 = 7.69
JSBD.add(a, b).toString()
// '7.69'

JSBD.subtract(lhs, rhs [, options])

This function can be used as an alternative to - binary operator that allows rounding the result after the calculation. It subtracts rhs from lhs and returns the result of such operation, applying the rounding based on options object, if given. options is an options bag that configures the rounding of this operation.

  • lhs: A BigDecimal value. If the value is from another type, it throws TypeError.
  • rhs: A BigDecimal value. If the value is from another type, it throws TypeError.
  • options: It is an object indicating how the round operation should be performed. It's the same options bag object described on JSBD.round. If it's not given, no rounding operation will be applied, and the exact result will be returned.
let a = JSBD.BigDecimal('1.25')
let b = JSBD.BigDecimal('644e-2')
// 1.25 - 6.44 = -5.19
JSBD.subtract(a, b).toString()
// '-5.19'

JSBD.multiply(lhs, rhs [, options])

This function can be used as an alternative to * binary operator that allows rounding the result after the calculation. It multiplies rhs by lhs and returns the result of such operation applying the rounding based on options object, if given. options is an options bag that configures the rounding of this operation.

  • lhs: A BigDecimal value. If the value is from another type, it throws TypeError.
  • rhs: A BigDecimal value. If the value is from another type, it throws TypeError.
  • options: It is an object indicating how the round operation should be performed. It's the same options bag object described on JSBD.round. If it's not given, no rounding operation will be applied, and the exact result will be returned.
let a = JSBD.BigDecimal('12')
let b = JSBD.BigDecimal('1.2')
// 12 * 1.2 = 14.4
JSBD.multiply(a, b).toString()
// '14.4'

JSBD.divide(lhs, rhs, options)

This function is the main way to apply division using BigDecimals. It divides lhs by rhs and returns the result of such operation applying the rounding based on options object. options is an options bag that configures the rounding of this operation.

  • lhs: A BigDecimal value. If the value is from another type, it throws TypeError.
  • rhs: A BigDecimal value. If the value is from another type, it throws TypeError.
  • options: It is an object indicating how the round operation should be performed. It's the same options bag object described on JSBD.round. If it's not given, no rounding operation will be applied, and the exact result will be returned. If the result can't be represented (due to a non-terminating decimal expansion), it throws TypeError.

Different from other arithmetic operations on BigDecimal constructors, we require options for division because this is the only operation where some results can't be represented as a BigDecimal value (e.g. when we divide 1m by 3m) if we don't round. With the requirement to describe how we should round the result, it's then possible to return a correct result for any given input.

let a = JSBD.BigDecimal('0.2')
let b = JSBD.BigDecimal('3')

// 0.2 / 3 = 0.0067
JSBD.divide(a, b, {
  maximumFractionDigits: 4,
  roundingMode: 'half even',
}).toString()
// '0.0067'

JSBD.remainder(lhs, rhs [, options])

This function can be used as an alternative to % binary operator that allows rounding the result after the calculation. It returns the reminder of dividing lhs by rhs, applying the rounding based on options object, if given. options is an options bag that configures the rounding of this operation.

  • lhs: A BigDecimal value. If the value is from another type, it throws TypeError.
  • rhs: A BigDecimal value. If the value is from another type, it throws TypeError.
  • options: It is an object indicating how the round operation should be performed. It's the same options bag object described on JSBD.round. If it's not given, no rounding operation will be applied, and the exact result will be returned.
let a = JSBD.BigDecimal('2')
let b = JSBD.BigDecimal('0.3')

// 2 % 0.3 => 0.2
JSBD.remainder(a, b).toString() // '0.2'

JSBD.pow(number, power [, options])

This function returns the power of number by power, applying the rounding based on options object, if given. options is an options bag that configures the rounding of this operation. power needs to be a positive integer.

  • number: A BigDecimal value. If the value is from another type, it throws TypeError.
  • power: A positive integer Number value. If the value is from another type or not a positive integer, it throws RangeError.
  • options: It is an object indicating how the round operation should be performed. It's the same options bag object described on JSBD.round. If it's not given, no rounding operation will be applied, and the exact result will be returned.
let a = JSBD.BigDecimal('0.2')
let b = 3
// '0.2^3 === 0.008'
JSBD.pow(a, b).toString()

JSBD.equal(lhs, rhs)

It returns true if lhs has the same value of rhs. Otherwise, returns false.

lhs and rhs should be BigDecimal instance

let a = JSBD.BigDecimal('0.2')
let b = JSBD.BigDecimal('2e-1')
// 'a === b
JSBD.equal(a, b) // 'true'

JSBD.notEqual(lhs, rhs)

It returns false if lhs has the same value and type of rhs. Otherwise, returns true.

lhs and rhs should be BigDecimal instance

let a = JSBD.BigDecimal('0.2')
let b = JSBD.BigDecimal('0.5')
// 'a !== b'
JSBD.notEqual(a, b) // 'true'

JSBD.lessThan(lhs, rhs)

It returns true if the value of lhs is lesser than the value of rhs. Otherwise it returns false.

lhs and rhs should be BigDecimal instance

let a = JSBD.BigDecimal('0.2')
let b = JSBD.BigDecimal('0.5')
// a < b
JSBD.lessThan(a, b) // 'true'

JSBD.greaterThan(lhs, rhs)

It returns true if the value of lhs is greater than the value of rhs. Otherwise it returns false.

lhs and rhs should be BigDecimal instance

let a = JSBD.BigDecimal('0.9')
let b = JSBD.BigDecimal('0.5')
// a > b
JSBD.greaterThan(a, b) // 'true'

JSBD.lessThanOrEqual(lhs, rhs)

It returns true if the value of lhs is lesser or equal than the value of rhs. Otherwise, it returns false.

lhs and rhs should be BigDecimal instance

let a = JSBD.BigDecimal('0.1')
let b = JSBD.BigDecimal('0.4')
// a <= b
JSBD.lessThanOrEqual(a, b) // 'true'

JSBD.greaterThanOrEqual(lhs, rhs)

It returns true if the value of lhs is greater or equal than the value of rhs. Otherwise, it returns false.

lhs and rhs should be BigDecimal instance

let a = JSBD.BigDecimal('0.5')
let b = JSBD.BigDecimal('0.4')
// a >= b
JSBD.greaterThanOrEqual(a, b) // 'true'

BigDecimal prototype

BigDecimal.prototype includes utility methods used to help manipulation of BigDecimal values.

BigDecimal.prototype.toString()

This method returns a string that represents the BigDecimal value.

let v = JSBD.BigDecimal('0.55')
console.log(v.toString()) // prints "0.55"

BigDecimal.prototype.toFixed([digits])

This function returns a string that represents fixed-point notation of the BigDecimal value. There is an optional parameter digits that defines the number of digits after decimal point. It follows the same semantics of Number.prototype.toFixed.

let v = JSBD.BigDecimal('100.456')
console.log(v.toFixed(2)) // prints 100.46
let v = JSBD.BigDecimal('0')
console.log(v.toFixed(2)) // prints 0.00

BigDecimal.prototype.toExponential([fractionDigits])

This methods returns a string of the BigDecimal in exponential representation. It takes an optional parameter fractionDigits that defines the number of digits after decimal point. It follows the same semantics of Number.prototype.toExponential.

let v = JSBD.BigDecimal('1010')
console.log(v.toExponential(2)) // prints 1.01e+3

BigDecimal.prototype.toPrecision([precision])

This function returns a string that represents the BigDecimal in the specified precision. It follows the same semantics of Number.prototype.toPrecision.

let v = JSBD.BigDecimal('111.22')
console.log(v.toPrecision()) // prints 111.22
console.log(v.toPrecision(4)) // 111.2
console.log(v.toPrecision(2)) //1.1e+2

for developer

since test use es module in node , better use node >= 14

yarn install
// change source code and add test case
yarn test