Code Monkey home page Code Monkey logo

js-big-decimal's Introduction

JS Big Decimal

image
Work with large numbers on the client side with high precision
Welcome to a saner world where 0.1 + 0.2 = 0.3 and not 0.30000000000000004

GitHub Action Build Coverage Status license npm npm Github file size

Contents

Contributors Welcome!

Hi, this is a relatively simple library that solves a very common and frustrating JS issue. With my current workload, it is becoming increasingly difficult to maintain this alone. If you have some basic JS/TS working knowledge, please go thorugh the open bugs/enhancements and help clear the backlog. Thanks in advance! 😌


Installation

npm install --save js-big-decimal

Usage

Note: Usage has changed since version 1.1.4

Require in javascript as

var bigDecimal = require('js-big-decimal');

For typescript, use

import bigDecimal = require('js-big-decimal');

For web, when used with script tag, a variable on Window object is created.

<script src="node_modules/js-big-decimal/dist/web/js-big-decimal.min.js"></script>
console.log(bigDecimal.add('12', '45'));

If you are only using it on the web and do not wish to get the whole npm package, you can download the file from unpkg as follows:

<script src="https://unpkg.com/[email protected]/dist/web/js-big-decimal.min.js"></script>

Operations

bigDecimal(number)

Create a new object of type BigDecimal. Supports parameters of type number and string. If string passed cannot be parsed as a number error is thrown. It is recommended to use string as it circumvents the issue of precision with JS native float implementation and max limit for integer.

It supports exponentiation, but only with integral exponent.

var n1 = new bigDecimal(12.6789);
var n2 = new bigDecimal("12345.6789");
var n3 = new bigDecimal('12.456e3'); // 12456

getValue()

Returns the string value of the decimal.

console.log(n2.getValue()); // "12345.6789"

setValue()

Allows setting the BigDecimal to a new value.

var n = new bigDecimal('123');
n.setvalue('567');
console.log(n.getValue()); // 567

getPrettyValue(number, digits, separator)

By default this returns the number in standard number format, comma after every three digits. Both arguments, digits - the number of digits (of the integral part) to group by, and separator - the character to mark the separation. Example of this can be to format a 16 digit number as credit card.

var value = bigDecimal.getPrettyValue("12345.6789"); // value = "12,345.6789"

Alternately, use the instance property. It returns the result as string.

var n3 = n2.getPrettyValue(); // n4 = "12,345.6789"

var num = new bigDecimal(1234567890123456)
var card = num.getPrettyValue(4, '-'); // cardNumber = "1234-5678-9012-3456"

round(number, precision, roundingMode)

Returns the rounded value to the specified precision (number of digits after decimal). The default precision is set to 0 and rounding mode set to HALF_EVEN if no argument is passed.

var value = bigDecimal.round("123.678", 2); // value = "123.68"

Alternately, use the instance property. It returns the result as bigDecimal.

var n3 = n1.round(2); // n3 = new bigDecimal("12.68")
var n4 = n2.round(); // n4 = new bigDecimal("12346")

Passing in a negative argument for digits to round off to returns the nearest multiple of power of 10. If the magnitude of the argument is larger than or equal to the number of digits in the integral part of the number to round, zero is returned.

var val1 = bigDecimal.round("123.78", -2); // val1 = "100"
var val2 = bigDecimal.round("587", -1); // val2 = "590"
var val3 = bigDecimal.round("123.78", -4); // val3 = "0"

Round also supports the following rounding modes (These are same as that of Java 8):

  • CEILING - Rounding mode to round towards positive infinity.
  • DOWN - Rounding mode to round towards zero.
  • FLOOR - Rounding mode to round towards negative infinity.
  • HALF_DOWN - Rounding mode to round towards "nearest neighbor" unless both neighbors are equidistant, in which case round down.
  • HALF_EVEN - Rounding mode to round towards the "nearest neighbor" unless both neighbors are equidistant, in which case, round towards the even neighbor.
  • HALF_UP - Rounding mode to round towards "nearest neighbor" unless both neighbors are equidistant, in which case round up.
  • UNNECESSARY (!Not Implemented!)- Rounding mode to assert that the requested operation has an exact result, hence no rounding is necessary.
  • UP - Rounding mode to round away from zero.

Extensive description of the modes can be found at Rounding Modes

var num = new bigDecimal("123.657");
var numRound1 = num.round(1, bigDecimal.RoundingModes.DOWN); // "123.6"
var numRound2 = num.round(2, bigDecimal.RoundingModes.CEILING); // "123.66"

stripTrailingZero(number)

Returns the number with trailing zeroes (prefix and suffix) removed.

var n1 = bigDecimal.stripTrailingZero(300.30) // "300.3"
var n2 = bigDecimal.stripTrailingZero(-0015.1) // "-15.1"
var n3 = bigDecimal.stripTrailingZero(0.000) // by default defined as "0"

The instance returns the result as new bigDecimal

var n1 = new bigDecimal(5.100).stripTrailingZero() // bigDecimal(5.1)
var n2 = new bigDecimal(1.05).add(new bigDecimal(1.05)).stripTrailingZero() // bigDecimal(2.1)

abs(number)

Returns the absolute value of a number.

var n1 = bigDecimal.abs(12.8) // "12.8"
var n2 = bigDecimal.abs(-12.3) // "12.3"

The instance returns the result as new bigDecimal

var n1 = new bigDecimal(12.8).abs() // bigDecimal(12.8)
var n2 = new bigDecimal(-12.3).abs() // bigDecimal(-12.3)

floor(number)

Returns the whole number nearest but not greater than the input number.

var n1 = bigDecimal.floor(12.8) // "12"
var n2 = bigDecimal.floor(-12.3) // "-13"

The instance function returns the result as a new bigDecimal

var n1 = new bigDecimal(12.8).floor() // bigDecimal(12)
var n2 = bigDecimal(-12.3).floor() // bigDecimal(-13)

ceil(number)

Returns the whole number nearest but not lesser than the input number.

var n1 = bigDecimal.ceil(12.8) // "13"
var n2 = bigDecimal.ceil(-12.3) // "-12"

The instance function returns the result as a new bigDecimal

var n1 = new bigDecimal(12.8).ceil() // bigDecimal(13)
var n2 = bigDecimal(-12.3).ceil() // bigDecimal(-12)

compareTo(number1, number2)

Compare two numbers. Returns 1, 0 and -1 if number1 > number2, number1 == number2 and number1 < number2 respectively.

var value = bigDecimal.compareTo("23.678", "67.34"); // value = -1
var value = bigDecimal.compareTo("23.678", "23.6780"); // value = 0
var value = bigDecimal.compareTo("123.678", "67.34"); // value = 1

Alternately, use the instance property. It returns the result as Integer.

var n1 = new bigDecimal('1234');
var n2 = new bigDecimal('8765');
var value = n1.compareTo(n2); // value = -1

negate(number)

Returns negation of a given number.

var value = bigDecimal.negate("123.678"); // value = "-123.678";

Alternately, use the instance property. It returns the result as new bigDecimal.

var n = new bigDecimal('-1234');
var value = n.negate(); // value = new bigDecimal('1234')

add(augend, addend)

Add two numbers. Pass in negative for subtraction. Ensure parameters are strings.

var sum = bigDecimal.add("23.678", "67.34"); // sum = "91.018"
var diff = bigDecimal.add("67.34", "-23.678"); // diff = "43.662"

Alternately, use the instance property. It returns the result as new bigDecimal.

var n1 = new bigDecimal('1234');
var n2 = new bigDecimal('8765');
var sum = n1.add(n2); // sum = new bigDecimal('9999')

subtract(minuend, subtrahend)

Subtract one number from another

var diff = bigDecimal.subtract("67.34", "23.678"); // diff = "43.662"

Alternately, use the instance property. It returns the result as new bigDecimal.

var n1 = new bigDecimal('12.67');
var n2 = new bigDecimal('130.7');
var diff = n1.subtract(n2); // diff = new bigDecimal('-118.03')

multiply(multiplicand, multiplier)

Multiply two numbers. Ensure parameters are strings.

var product = bigDecimal.multiply("-0.13", "0.00130"); // product = "-0.000169"

Alternately, use the instance property. It returns the result as new bigDecimal.

var n1 = new bigDecimal('-0.13');
var n2 = new bigDecimal('0.00130');
var product = n1.multiply(n2); // product = new bigDecimal('-0.000169')

divide(dividend, divisor, precision)

Divide two numbers. Pass arguments as string if calling on bigDecimal or pass an instance of bigDecimal if calling on object. precision is an optional parameter with default value of 8.

var quotient = bigDecimal.divide('45', '4', 2); // quotient = '11.25'

Alternately, use the instance property. It returns the result as new bigDecimal.

var n1 = new bigDecimal('45');
var n2 = new bigDecimal('4');
var quotient = n1.divide(n2); // quotient = new bigDecimal('11.25')

modulus(dividend, divisor)

Get the modulus of two numbers, i.e., remainder when the dividend is divided by the divisor. Note that both divisor and dividend need to be integers.

var remainder = bigDecimal.modulus('45', '4'); // remainder = '1'

Alternately, use the instance property. It returns the result as new bigDecimal.

var n1 = new bigDecimal('45');
var n2 = new bigDecimal('4');
var remainder = n1.modulus(n2); // remainder = new bigDecimal('1')

Further, the result takes the sign of the dividend and the sign of the divisor is ignored. Note that this behaviour is the same as in Java and JavaScript.

Support the developers ❤️ ⭐ 💸

If this library helps you in your organization, you can show some love by giving the repo a star or support by making a nominal monetary contribution.

Buy Me A Coffee

js-big-decimal's People

Contributors

dependabot[bot] avatar eldereal avatar healgaren avatar insyncwithfoo avatar janeklb avatar royniladri avatar sushanto avatar sylhare avatar tgbv avatar yogski avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

js-big-decimal's Issues

divide error when i use 1e21 over number use

Describe the bug
A clear and concise description of what the bug is.

An error occurs when dividing with a number greater than 1e21.

To Reproduce
Steps to reproduce the behavior, preferably with sample code.

const data = 1e21
multiplier = new bigDecimal(Math.pow(10, 18));
console.log(data / multiplier.value)
let divideAsset = bigDecimal.divide(received.toString(), multiplier.value, 18)
console.log('divideAsset')
console.log(divideAsset)
===>
10.000000000000000000(error)

Expected behavior
A clear and concise description of what you expected to happen.
===>
1000.0000000000000000(Normal case)

Additional context
Add any other context about the problem here.

Allow extension methods

Describe the bug
I would like to create an extension method

To Reproduce

declare module 'js-big-decimal' {
}

Fails with "is a non-module entity"

Expected behavior
A clear and concise description of what you expected to happen.

Additional context
Add any other context about the problem here.

A positive bug

Describe the bug
Rounding up a negative number returns a positive value.

To Reproduce
Pick any number in this format: -x.996, -x.997, -x.998, -x.999 and rounding it HALF_UP gives a positive value.
Example:
new bigDecimal('-1.996').round(2, bigDecimal.RoundingModes.HALF_UP).getValue(); -> {value: "2.00"}
new bigDecimal('-2.997').round(2, bigDecimal.RoundingModes.HALF_UP).getValue(); -> {value: "3.00"}
etc..

Expected behavior
Rounding up a negative number returns a negative value.

Additional context
image

Function compareTo fails when comparing 0 and -0

Describe the bug
Attempting to run bigDecimal.compareTo("-0", "0") returns -1, assuming -0 is lower than 0, when they are mathematically equal. This is always true, on the cases I tested, even when applying exponentials to either of the two operands.

Package version: 2.0.4

To Reproduce
bigDecimal.compareTo("-0", "0") === -1

true

Expected behavior
One would expect that compareTo would return 0 (equal) for the operations bigDecimal.compareTo("-0", "0") and bigDecimal.compareTo("0", "-0").

Implement pow

Raise a number to another number. Both can be non integer and cases resulting in imaginary number [like bigDecimal.pow(-21, 0.5)] should throw an error.

Returning "0" in divide() is ignoring precision

Discussed in #56

Originally posted by themastermindnktp February 18, 2022
In file src/divide.ts line 17, function divide(dividend, divisor, precision), your code instantly returns "0" without processing precision. This is quite inconsistent. For example: divide("10", "2", 3) -> "5.000" while divide("0", "2", 3") -> "0".

Rounding towards 0 from a negative number persists the "-" prefix

Describe the bug
When rounding to 0 from a negative number like "-0.0000005", the result will be something like "-0.00"

To Reproduce
new bigDecimal('-0.05').round(0)
=> '-0'

Expected behavior
any 0 value should not have a negative prefix

new bigDecimal('-0.05').round(0)
=> '0'

Division not giving enough precision

Describe the bug
Division is returning 0 for very small numbers

To Reproduce
The following returns a value of 0, when it shouldn't:

var one = new bigDecimal('200000000000')
var two = new bigDecimal('17453700000.00000000')
var three = new bigDecimal('273484570903.25196072045472431920336519131248')
console.log(one.divide(two).divide(three))

Expected behavior
This should give me a more precise decimal. In particular, it would be nice to have at least 4 (non-zero) values in the form of a.xyz E -1000000 or something like that. Or, allow some way to alter the precision when doing division with very small numbers.

Additional context
No additional context.

Wrong answer calculated

Describe the bug
bigDecimal.divide('123456789.123456','.0123456',18)
returns 1000.006391940902021773
but should return 10000063919.40902021773

Decimal position is wrong.

Additional context
Using npm install in node; reports version 1.3.1
Was working on an translation of js-big-decimal to Lua (for Pico8) and my code returned the incorrect answer.
Verified my answer against js-big-decimal and realized I had perfectly implemented it, down to even this bug. 🐛

Wrong result when adding any number to -0

Describe the bug
Wrong result when adding any number to -0

To Reproduce

 const n1 = new bigDecimal('-0');
 const n2 = new bigDecimal('10');
 const diff1 = n1.add(n2);
print(diff1.getValue()); // Will print -890

Expected behavior
The result should be 10

Additional context
If the operation is adding -0 to 10 the result will be correct.

Typescript type declaration indicates that bigint is not supported

Describe the bug

Cannot use bigint values with big decimal

To Reproduce

import bigDecimal from 'js-big-decimal';

new bigDecimal(10n); // type error

Expected behavior

no type error :)

Additional context

This seems to be just a TS / typing issue -- bigint values look like they work just fine if using plain JS.

error processing an exponent, bigDecimal.round(0.00000001,8) return "0.00000000"

bigDecimal.round(0.00000001,8) return "0.000000000100000"
bigDecimal.round("1e-8",8) return "0.000000000100000"
although it should return "0.00000001"

it looks like a bug in the code

error in string:
number = '0.' + (new Array(-exponent + 1)).join('0') + mantisa;
fix:
number = '0.' + (new Array(-exponent - 1)).join('0') + mantisa;

method round buggy

method "round" returns only positive results, for example:
bigDecimal.round(-0.1234, 2); returns 0.12, but not -0.12

.toFixed() functionality replication

I'm working with this library in a project and I find it lacking the toFixed functionality, setting out a specific number of decimals is incredibly helpful, I was hoping it would be in the roadmap?

Floor returns negative 0

const bigValue = new bigDecimal(0.00001341);
const integer = bigValue.floor();

integer is now -0, instead of 0

Besides the issue, the intent is to obtain the integer part of the number. Is there a better way to achieve that?

can't find module RoundingModes

`import bigDecimal from 'js-big-decimal'

export class RunUtils {

public static scaleFloat(value: number, scale: number) {
let strValue = value.toString()
let decimalValue = new bigDecimal(strValue)
return decimalValue.round(scale, bigDecimal.RoundingModes.HALF_UP).getValue()
}
}`

then error: can't find module RoundingModes

Any method to set value to a big decimal object ?

Any method to set value to a big decimal object rather than creating a new object every time ?
For example :

const v1 = new bigDecimal(122345);
console.log(v1.getValue());  // 122345
v1.setValue(4566);
console.log(v1.getValue());  //4566

How about Math.abs

Discussed in #71

Originally posted by snowkidind August 1, 2022
i want the absolute (unsigned) value of a bigD

add function doesn't work

Describe the bug
n1.add(n2) where n1 and n2 are bigDecimal return error :

Uncaught Error: Parameter is not a number: aN.NaNNaNNaN
at webpack_modules.423.bigDecimal.validate

Comparison is returning true when it should be false

trying to do the following math: (94911150 / 94911151) == (94911151 / 94911152)

This should return false, but it appears to be returning true with this library.

var bigDecimal = require('js-big-decimal');
var Decimal = require('decimal.js');

a = new Decimal(94911150);
b = new Decimal(94911151);
c = new Decimal(94911151);
d = new Decimal(94911152);


a1 = new bigDecimal(94911150);
b1 = new bigDecimal(94911151);
c1 = new bigDecimal(94911151);
d1 = new bigDecimal(94911152);


// (94911150 / 94911151) == (94911151 / 94911152)

console.log(a1.divide(b1).compareTo(c1.divide(d1)));

console.log(a.dividedBy(b).equals(c.dividedBy(d)));
0
false

it's my understanding that compareTo returning 0 means they're equal. If you check on wolfram alpha, that isn't the case

Incorrect results from parsing an exponential form numbers

Describe the bug

Incorrect result will When parsing exponential form numbers with following patters:

  1. integer mantissa (1e0, 1e1, 1e-1) results in a number with wrong dot position.
  2. negative mantissa (-1e1, -0.0134e-2 ) results in illegal number formats.

To Reproduce
Run in a nodejs console:

> bigDecimal = require('js-big-decimal');
> new bigDecimal('1e0')
bigDecimal { value: '0.1' }
> new bigDecimal('1e1')
bigDecimal { value: '1' }
> new bigDecimal('-1e1')
bigDecimal { value: '-.1' }
> new bigDecimal('-0.0134e-2')
bigDecimal { value: '0.-00134' }

Expected behavior
Correct numbers returned.

Additional context
Tested in latest development branch.
A bug fix will submitted later.

Precision issue

Describe the bug
Invalid result using divide.

new bigDecimal("29.45").divide(new bigDecimal("646")).multiply(new bigDecimal("646")).getValue() === "29.45"; // 29.45000304
new bigDecimal("29.45").divide(new bigDecimal("646"), 16).multiply(new bigDecimal("646")).getValue() === "29.45"; // 29.4499999999999696
new bigDecimal("29.45").divide(new bigDecimal("646"), 32).multiply(new bigDecimal("646")).getValue() === "29.45"; // 29.44999999999999999999999999999696

To Reproduce

const { default: bigDecimal } = require("js-big-decimal");

console.log(new bigDecimal("29.45").divide(new bigDecimal("646")).multiply(new bigDecimal("646")).getValue()); // 29.45000304
console.log(new bigDecimal("29.45").divide(new bigDecimal("646"), 16).multiply(new bigDecimal("646")).getValue()); // 29.4499999999999696
console.log(new bigDecimal("29.45").divide(new bigDecimal("646"), 32).multiply(new bigDecimal("646")).getValue()); // 29.44999999999999999999999999999696

Expected behavior

new bigDecimal("29.45").divide(new bigDecimal("646")).multiply(new bigDecimal("646")).getValue() === "29.45"; // 29.45

Additional context
Thanks for this great lib 😄

2.00 / 0.5 = 40.00000000

Inconsistency in treating decimal digits in division:

Thus, bigDecimal.divide('2.00', '0.5') = 40.00000000
However, bigDecimal.divide('2.00', '0.50') = 4.00000000

Workaround: bigDecimal.divide( bigDecimal.round('2.00', 2), bigDecimal.round('0.5', 2)) = 4

npm

bigdecimal v.1.2.1
image

Import errors with vite project

Describe the bug
vite projects fail to consume js-big-decimal.

To Reproduce
Repro repo is here: https://github.com/NiloCK/vite-bigdecimal-import-reproduction

See the readme.

Expected behavior
In the repo, yarn dev should serve the sample app page, with the counter integer replaced by a bigDecimal.

Additional context
The vite site seems to be mistakenly importing content from the dist/node folder, instead of dist/web

There is some issue with:

  • vite's bundler
  • js-big-decimal's packaging / distribution pipeline
  • some combination of the two

Support rounding modes

It is a feature, a bug or an enhancement?
This is an enhancement

Is it duplicated?
Could be related to #11.

Description:
It would be great to support rounding modes just as BigDecimal Java Library or Decimal Python Library do: (ignore ROUND_CEILING and ROUND_FLOOR, since there are already specific methods for that)

  • ROUND_DOWN: Rounding mode to round towards zero.
  • ROUND_HALF_DOWN: Rounding mode to round towards "nearest neighbor" unless both neighbors are equidistant, in which case round down.
  • ROUND_HALF_EVEN: Rounding mode to round towards the "nearest neighbor" unless both neighbors are equidistant, in which case, round towards the even neighbor.
  • ROUND_HALF_UP: Rounding mode to round towards "nearest neighbor" unless both neighbors are equidistant, in which case round up.
  • ROUND_UNNECESSARY: Rounding mode to assert that the requested operation has an exact result, hence no rounding is necessary.
  • ROUND_UP: Rounding mode to round away from zero.

Btw, thanks for this great library 🎉

Getting imprecise result

Describe the bug
I'm getting an imprecise result after multiplying.

To Reproduce
import BigDecimal from 'js-big-decimal';
console.log(BigDecimal.multiply('11612,7833519', '10.764'));

Expected behavior
Result should be 125000, getting 124999.9999998516 like I get with plain js.

Issue in Round method

Hai there,

Could not able to round for the number 0.5 with precision 0 and Rounding Mode HALF_UP

Eg: var num = new bigDecimal("0.5");
var numRound1 = num.round(0, bigDecimal.RoundingModes.HALF_UP);
Expected output:1 but returning 0

stripTrailingZeros implement

Discussed in #55

Originally posted by uranik777 September 24, 2021
console.log( bigDecimal.add("0.0005000","1")); // 1.0005000
console.log( bigDecimal.add("0.0005000","1").stripTrailingZeros() ); // 1.0005

Import errors on server side of Nuxt

Describe the bug

There is a packaging issue in the library. For SSR apps, it works on client side but not on server side (only after the build - during dev, there is no issue).

Workaround give by Nuxt team is to "transpile" it:
nuxt/nuxt#26375

To Reproduce
https://stackblitz.com/edit/github-qytiun

Expected behavior
Module shall be properly packaged in order to allow usage without transpiling it in Nuxt.

Additional context
N/A - refer to reproduction code

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.