Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pretty Printing Fractional Exponential Units #60

Open
jdreaver opened this issue Sep 6, 2013 · 3 comments
Open

Pretty Printing Fractional Exponential Units #60

jdreaver opened this issue Sep 6, 2013 · 3 comments

Comments

@jdreaver
Copy link
Contributor

jdreaver commented Sep 6, 2013

I have found what I think is a bug, and an opportunity to both fix the bug and enhance Pint.

Whenever a quantity is defined with a fractional exponent in a unit, the exponent is converted to a decimal representation, which is all well and good. However, when pretty printing, the decimal point is not superscripted with the rest of the exponent. For example:

>>> x = ureg['s**(3/2)']

>>> x.units  # 3/2 converted to 1.5
<UnitsContainer({'second': 1.5})>

>>> "{:P~}".format(x)  # Exponent becomes ¹.⁵
'1.0 s¹.⁵'

A solution could be to keep fractional representations in fractional form, and use the unicode fraction slash character (U+2044 = ⁄ ) to compose arbitrary fractions with subscript and superscript numbers. It would be nice for the above example to evaluate to:

>>> "{:P~}".format(x)
'1.0 s³⁄₂'

The ³⁄₂ is a superscript 3, a fraction slash, and a subscript 2.

I don't know how feasible this is. Certainly, getting the decimal in the exponent would be great, but I don't know of a superscript decimal unicode character. I also don't know if storing fractions would be too much trouble for the rest of the system.

I can try to tackle this myself unless someone has an easy solution.

@hgrecco
Copy link
Owner

hgrecco commented Sep 7, 2013

an opportunity to both fix the bug and enhance Pint.

This is always a good combination!

The problem as I see it is that 3/2 for Python 3 is a float, not a fraction. To have a fraction we will need to do something like:

>>> from fractions import Fraction
>>> q  = ureg.meter ** Fraction(3,2)

which, by the way, is now also converted to float internally:

>>> q
<Quantity(1.0, 'meter ** 1.5')>

I see two ways to implement your suggestion, and maybe we want to implement both.

1.- Change the formatting part

We can get the exponents and try to convert them from float to fraction.

>>> Fraction.from_float(1.5)
Fraction(3, 2)

The good part: it will be transparent to the user.
The bad part: it will add some complexity to the formatting code to decide when we want to do this.

2.- Allow any scalar numeric type for the exponents

The good part: will allow the user to make some calculations more accurate. In fact, this is why the implementation Pi Theorem works so well in Pint: we use Fraction as the type to avoid precision problems associated with floats.
The bad part: User will have to define the quantity with a fractional exponent so it could be nicely printed. Additionally, when you give the freedom to use any scalar numerical type you might hit some errors like this:

>>> decimal.Decimal(0.1) + 1.
Traceback (most recent call last):
[...]
TypeError: unsupported operand type(s) for +: 'Decimal' and 'float'

We will need to guard for those.

As I said, maybe the way is to implement both.

@jules-ch
Copy link
Collaborator

jules-ch commented May 25, 2021

@hgrecco

I think to move forward we need to maybe only allow integer or Fraction as power in units.
This is critical if we want to allow fractional exponent units.

Operations on integer & Fraction are easily supported using python.
Other numerical type could be casted to Fraction.

I think it deserves an issue on its own to work on.

About this issue, we can easily support it if we encounter Fraction, it will display '3/2' and we can add pretty print after that in the dedicated function.

@hgrecco
Copy link
Owner

hgrecco commented May 25, 2021

I do agree that we need an issue on its own. In particular, I think it is worth discussing if we should enable a plugable architecture (like non_int_type or similar)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants