High precision arithmetric in Python and/or C/C++?

2019-02-16 01:26发布

Abstract: Which Python package or C-Library is the best option for very high precision arithmetic operations?

I have some functions which convert fractional days (0.0-0.99999..) to a human-readible format (hours, minutes, seconds; but more importantly: milliseconds, microsecond, nanoseconds).

Conversion is done by these functions: (note that I haven't implemented timezone correction yet)

d = lambda x: decimal.Decimal(str(x))
cdef object fractional2hms(double fractional, double timezone):
    cdef object total, hms, ms_mult
    cdef int i
    hms = [0,0,0,0,0,0]
    ms_mult = (d(3600000000000), d(60000000000), d(1000000000), d(1000000), d(1000), d(1))
    # hms = [0,0,0,0,0]

    total = d(fractional) * d(86400000000000)
    for i in range(len(ms_mult)):
        hms[i] = (total - (total % ms_mult[i])) / ms_mult[i]
        total = d(total % ms_mult[i])

    return ([int(x) for x in hms])

And to fractional:

def to_fractional(self):
        output = (self.hour / d(24.0)) + (self.minute / d(1440.0))
        output += (self.second / d(86400.0)) + (self.millisecond / d(86400000.0))
        output += self.microsecond / d(86400000000.0)
        output += self.nanosecond * (d(8.64) * d(10)**d(-9))
        return output

My results of a back-and-forth conversion are inaccurate, however:

jdatetime.DayTime.fromfractional(d(0.567784356873)).to_fractional()
Decimal('0.56779150214342592592592592592592592592592592592592592592592592592592592592592592592592592592592592592592592592592')
# Difference in-out: Decimal('0.000007145270')

When I change d() to return a regular Python float:

# Difference in-out: 7.1452704258900823e-06 (same)

My question is therefore: Which Python package or C-library is able to do this more accurately?

2条回答
爱情/是我丢掉的垃圾
2楼-- · 2019-02-16 01:44

The difference is due to a bug in your code, not due to any accuracy issue. The line

output += self.nanosecond * (d(8.64) * d(10)**d(-9))

should be something like

output += self.nanosecond / d(86400000000000)

Furthermore, it is a Bad Idea to use floating point literals in your code and convert them to Decimal. This will first round the literal number to floating point accuracy. The later conversion to Decimal can't restore the lost accuracy. Try

d = decimal.Decimal

and use only integer literals (just remove the .0 part).

查看更多
Deceive 欺骗
3楼-- · 2019-02-16 01:52

CTRL-F "Libraries" there: Arbitrary-precision_arithmetic

EDIT: Extracting from the link libraries for c++ and python only (and removing some, that don't have floating numbers, but only integers)

python

1) mpmath


c++

1) apfloat

2) base one number class

3) bigfloat

4) lidia

5) mapm

6) MIRACL

7) NTL

8) ttmath

查看更多
登录 后发表回答