classification
Title: Add mathematical functions as wrappers to decimal.Decimal methods
Type: enhancement Stage: resolved
Components: Library (Lib) Versions: Python 3.10
process
Status: closed Resolution: rejected
Dependencies: Superseder:
Assigned To: Nosy List: Jean Abou Samra, Jean_Abou_Samra, facundobatista, mark.dickinson, rhettinger, skrah, terry.reedy
Priority: normal Keywords:

Created on 2020-07-16 14:13 by Jean Abou Samra, last changed 2020-07-18 07:48 by Jean_Abou_Samra. This issue is now closed.

Messages (7)
msg373754 - (view) Author: Jean Abou Samra (Jean Abou Samra) Date: 2020-07-16 14:13
Common mathematical functions such as sqrt(), exp(), etc. are available for decimal numbers as methods of decimal.Decimal instances (like https://docs.python.org/3/library/decimal.html#decimal.Decimal.exp). This does not pair well with the math and cmath modules as well as NumPy and SymPy which all define these as functions. It also makes it harder to switch to decimals instead of floats when you realize that your program lacks arithmetic precision.

It would be nice to have functions in the decimal module that called the corresponding methods. This would unify the interface with other modules while keeping backwards compatibility and preserving the possibility to subclass Decimal.
msg373778 - (view) Author: Stefan Krah (skrah) * (Python committer) Date: 2020-07-16 22:19
The top level decimal.py that dispatches to either _decimal or
_pydecimal is pure Python.  So perhaps these applications could
add these methods themselves:


>>> import decimal
>>> def exp(x):
...     return x.exp()
... 
>>> decimal.exp = exp
>>> 
>>> from decimal import *
>>> exp(Decimal(2))
Decimal('7.389056098930650227230427461')


As you see, it is no big deal, but it feels a bit odd to have
some methods like exp() and sqrt() exposed in the top level.


We already have:

  Decimal.exp()

And:

  >>> c = getcontext()
  >>> c.exp(Decimal(2))
  Decimal('7.389056098930650227230427461')
msg373785 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2020-07-17 00:51
I concur with Stefan.  This would mostly be a waste.

Also, the APIs aren't completely harmonious because the Decimal methods accept an optional context object.
msg373833 - (view) Author: Jean Abou Samra (Jean_Abou_Samra) Date: 2020-07-17 15:04
I would argue that given a function,

from math import *

def naive_calc_pi(n=100):
    u = sqrt(8)
    v = 4
    for _ in range(n):
        v = 2*u*v/(u + v)
        u = sqrt(u*v)
    return u

when you realize that floats have limited precision (happened to me several times while being taught and teaching Python), you could just replace

from math import *

with

from decimal import *

and use it, instead of the current

from decimal import Decimal as D

def sqrt(x):
    return D(x).sqrt()

Of course, you can define these, but as I repeatedly ended up doing this, I just thought I'd bring the idea upstream.

Another, perhaps more important argument is readability. We all think in terms of functions: log(x), not x.log(). I find it a significant fact that NumPy has both numpy.dot(A, B) and numpy.ndarray.dot(self, B), but the former is generally preferred (the method's documentation points to the function and the first dozen Google search results for "numpy dot product" yield the function). It makes expressions resemble what we are used to: compare

(a + b).tan().log() = (a.tan() + b.tan()).sqrt()/(1 - a.tan()*b.tan()).sqrt()
with
sqrt(tan(a + b)) = sqrt(tan(a) + tan(b))/sqrt(1 - tan(a)*tan(b))

> Also, the APIs aren't completely harmonious because the Decimal methods accept an optional context object.

I don't see a problem with the functions also accepting this parameter. (np.sin() has many parameters after all.)

Overall, I think this modest addition would bring an improvement in the usability of the decimal module. I can make a PR.
msg373867 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2020-07-18 01:11
FWIW, I don't really buy into the use case.  In my experience a nest of existing functions that are designed for floats will somewhere being using a float constant like 0.5, e, pi, or tau.  So, just feeding in a decimal input isn't sufficient to get it to work.  Also, for your idea to work, the function couldn't explicitly reference math.exp(x); instead, it must just use exp() so that you could substitute, "from decimal import exp" for "from math import exp". 

Also, this proposal would be a limited utility because most of the functions in the math module don't have an existing equivalent in the decimal methods.  The inconvenient fact is that the decimal module wasn't designed to be a drop-in substitute for floats — it's principal design objectives were somewhat different.
msg373873 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2020-07-18 06:14
Jean, I sympathize a bit with your wish, but decimal was designed for business,  not science.  Sqrt, exp, and 3 versions of log are the only math methods, and they happen to be the ones with some use in business calculations and statistics.  Extended math-science use needs a module that would wrap these methos and either include math module functions or decimal implementations thereof.  This might be candidate for pypi as well as someone's private collection.
msg373883 - (view) Author: Jean Abou Samra (Jean_Abou_Samra) Date: 2020-07-18 07:48
Okay, understood, thanks for your detailed explanations.
History
Date User Action Args
2020-07-18 07:48:17Jean_Abou_Samrasetmessages: + msg373883
2020-07-18 06:14:50terry.reedysetstatus: open -> closed

nosy: + terry.reedy
messages: + msg373873

resolution: rejected
stage: resolved
2020-07-18 01:11:36rhettingersetmessages: + msg373867
2020-07-17 15:04:41Jean_Abou_Samrasetnosy: + Jean_Abou_Samra
messages: + msg373833
2020-07-17 00:51:15rhettingersetmessages: + msg373785
2020-07-16 22:19:57skrahsetmessages: + msg373778
2020-07-16 14:14:17Jean Abou Samrasettitle: Add mathematical functions as wrapper to decimal.Decimal methods -> Add mathematical functions as wrappers to decimal.Decimal methods
2020-07-16 14:13:33Jean Abou Samracreate