vpiotr / decimal_for_cpp

Decimal data type for C++
270 stars 67 forks source link

Integration with Eigen #69

Open evanwporter opened 1 month ago

evanwporter commented 1 month ago

Eigen is a very popular library for linear algebra with the C++ ecosystem. Especially for users working with larger financial datasets (ie: stock prices), it would be useful to have a method for using the decimal datatype within Eigen matrices.

Eigen allows the user to define custom scalars, see here, and so if this a feature that is desired then it could be implemented as follows:

#ifdef EIGEN_DECIMAL

#include <Eigen/Core>

namespace Eigen {
    template<int Precision>
    struct NumTraits<dec::decimal<Precision>> : GenericNumTraits<dec::decimal<Precision>> {
        typedef dec::decimal<Precision> Real;
        typedef dec::decimal<Precision> NonInteger;
        typedef dec::decimal<Precision> Nested;

        static inline Real epsilon() {
            // Return a small value that represents the precision limit of the decimal type
            return dec::decimal<Precision>(0.0001); // Adjust this value according to your needs
        }

        static inline Real dummy_precision() {
            // Provide a dummy precision, typically a small value
            return dec::decimal<Precision>(0.0001); // Adjust this value according to your needs
        }

        static inline int digits10() {
            // Returns the number of base-10 digits that can be represented without loss of precision
            return Precision;
        }

        enum {
            IsInteger = 0,
            IsSigned = 1,
            IsComplex = 0,
            RequireInitialization = 1,
            ReadCost = 1,
            AddCost = 1,
            MulCost = 1
        };
    };

    namespace internal {
        // Scalar addition
        template<int Precision>
        struct scalar_sum_op<dec::decimal<Precision>, dec::decimal<Precision>> {
            EIGEN_EMPTY_STRUCT_CTOR(scalar_sum_op)
            typedef dec::decimal<Precision> result_type;
            EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
            result_type operator()(const dec::decimal<Precision>& a, const dec::decimal<Precision>& b) const {
                return a + b;
            }
        };

        // Scalar multiplication
        template<int Precision>
        struct scalar_product_op<dec::decimal<Precision>, dec::decimal<Precision>> {
            EIGEN_EMPTY_STRUCT_CTOR(scalar_product_op)
            typedef dec::decimal<Precision> result_type;
            EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
            result_type operator()(const dec::decimal<Precision>& a, const dec::decimal<Precision>& b) const {
                return a * b;
            }
        };

        // Scalar quotient
        template<int Precision>
        struct scalar_quotient_op<dec::decimal<Precision>, dec::decimal<Precision>> {
            EIGEN_EMPTY_STRUCT_CTOR(scalar_quotient_op)
            typedef dec::decimal<Precision> result_type;
            EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
            result_type operator()(const dec::decimal<Precision>& a, const dec::decimal<Precision>& b) const {
                return a / b;
            }
        };

        // Scalar min
        template<int Precision>
        struct scalar_min_op<dec::decimal<Precision>, dec::decimal<Precision>> {
            EIGEN_EMPTY_STRUCT_CTOR(scalar_min_op)
            typedef dec::decimal<Precision> result_type;
            EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
            result_type operator()(const dec::decimal<Precision>& a, const dec::decimal<Precision>& b) const {
                return std::min(a, b);
            }
        };

        // Scalar max
        template<int Precision>
        struct scalar_max_op<dec::decimal<Precision>, dec::decimal<Precision>> {
            EIGEN_EMPTY_STRUCT_CTOR(scalar_max_op)
            typedef dec::decimal<Precision> result_type;
            EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
            result_type operator()(const dec::decimal<Precision>& a, const dec::decimal<Precision>& b) const {
                return std::max(a, b);
            }
        };
    }
}

#endif

More thought will have to be put into how to best implement this and this would obviously increase the complexity of the overall project. Given this I think the best option here is leave this issue as it is now, keeping it as a reference for other users in the future trying to implement this library into Eigen

vpiotr commented 1 month ago

It's not an issue and even not a potential feature for decimal library - clearly this code is independent part which can be distributed alone. Please create a gist or github repo for this and link here.