Skip to content

A Java library that abstracts the mathematical operations on real decimal numbers represented in computer memory as floating-point binary numbers or arbitrary-precision decimal numbers.

License

Notifications You must be signed in to change notification settings

invision-trading/num

Repository files navigation

Num

Maven Central Version javadoc GitHub License

A Java library that abstracts the mathematical operations on real decimal numbers represented in computer memory as floating-point binary numbers (Double) or arbitrary-precision decimal numbers (BigDecimal).

Installation

For build.gradle.kts:

implementation("trade.invision", "num", "1.11.0")

For build.gradle:

implementation group: 'trade.invision', name: 'num', version: '1.11.0'

For pom.xml:

<dependency>
    <groupId>trade.invision</groupId>
    <artifactId>num</artifactId>
    <version>1.11.0</version>
</dependency>

Motivation

IEEE 754 floating-point binary numbers cannot accurately represent non-integer real decimal numbers in computer memory and FPUs. In applications that require accurate mathematical operations with non-integer (fractional) decimal numbers, such as finance programs involving money transactions and currency, using arbitrary-precision decimal numbers is best practice. Using floating-point numbers (e.g. float or double) to represent currency can lead to undesirable inequality calculations, rounding errors, and precision loss. Thankfully, Java provides the BigDecimal class for working with arbitrary-precision decimal numbers, though it has some quirks and doesn't provide many of the functions that the Math class has for float and double types. Additionally, mathematical operations on BigDecimal objects can be significantly slower than the equivalent mathematical operations on floating-point numbers. This can be problematic in applications such as quantitative finance and algorithmic trading programs where fast execution time of mathematical operations on currency values is more desirable and the tradeoff of worse accuracy and lower precision is worth it. Using integer types as a fixed-point number to represent a currency's minor unit is another approach, but it can be unintuitive to work with and is still subject to precision loss. The side effects of using floating-point numbers for currency may be negligible in certain contexts, such as working with relatively low precision numbers (like stock prices) or measurements (like technical indicators). So, using floating-point numbers for currency values isn't always a bad idea. Even Microsoft Excel, a program widely used in finance, uses floating-point numbers. You can really go back-and-forth on the tradeoffs between floating-point, fixed-point, and arbitrary-precision numbers. Enter, the Num interface: an intuitive interface that allows you to focus on using currency values in your application without worrying about the underlying number representation and easily switch between various number representations at runtime.

The Num Interface

Num, short for "number", is an interface for performing mathematical operations on real decimal numbers. Implementations wrap a Number instance so that performing mathematical operations on floating-point binary numbers (Double via DoubleNum) or arbitrary-precision decimal numbers (BigDecimal via DecimalNum) is simple. Object instances of this interface are immutable. All methods in this interface return non-null values or throw a RuntimeException (usually an ArithmeticException). All implementations of this interface are interoperable with each other. Operations involving different implementations will result in a Num that trends towards an increase in precision. For example, subtracting a DecimalNum from a DoubleNum will result in a DecimalNum. For another example, subtracting a DecimalNum with a context precision of 16 from a DecimalNum with a context precision of 32 will result in a DecimalNum with a context precision of 32. Mathematical operations that result in NaN, +Infinity, -Infinity, or ArithmeticException will yield NaNNum.

Usage

To create a DoubleNum, provide an existing Number (byte, short, int, long, float, double), BigDecimal, String, or Num to the DoubleNum.doubleNum() static method. Statically importing doubleNum() is preferred as your code will likely look cleaner. Creating a DecimalNum is similar to DoubleNum, but requires you to specify a precision and rounding mode via MathContext. Use DecimalNum.decimalNum(String, MathContext) or use one of the convenience methods, such as decimalNum64() which provides approximately the same precision as double, allowing up to 16 significant figures of precision and the same rounding policy as double. Again, statically importing decimalNum() is preferred as your code will likely look cleaner.

You can create a NumFactory instance to abstract the Num creation process by using one of the NumFactory creation methods available in DoubleNum or DecimalNum (e.g. DecimalNum.decimalNum64Factory()). The NumFactory defines the underlying number representation for new Num instances, so you can create a Num from an existing Number, BigDecimal, String, or Num by simply using NumFactory.of(...).

For mathematical operations that have well-known abbreviations, such as log for logarithm or atanh for inverseHyperbolicTangent, the Num interface provides methods for such abbreviations, also known as shorthand methods. The shorthand methods should be preferred to the full name of the mathematical operation; the full name exists for completeness and as a reference for the shorthand.

Check out the Javadoc for all classes and method signatures, but here's a quick reference:

Acknowledgement

This library's Num interface was inspired by the Num interface of the excellent ta4j library. There are several improvements and additions that this library's Num interface provides:

  • Interoperability between DoubleNum and DecimalNum.
  • Several more mathematical operations (e.g. trigonometry functions) via Math in DoubleNum and via big-math in DecimalNum.
  • No default precision for DecimalNum (see ta4j issue).
  • Configurable epsilon for tolerant comparison operations (see ta4j DoubleNum).
  • Number used instead of primitive overloads.
  • Documentation improvements.

Big thanks to Eric Obermühlner for the excellent big-math library.

Maintained by Invision

This project is maintained by Invision. Invision enables you to automate and test your investment and trading strategies across billions of data points in seconds using quantitative finance and algorithmic trading programs you build on our code or no-code platform.

About

A Java library that abstracts the mathematical operations on real decimal numbers represented in computer memory as floating-point binary numbers or arbitrary-precision decimal numbers.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages