Is there a way to have fractions with roots? - python

Is there a way to have fractions (in python) with roots? When I write Fraction(np.sqrt(2), 2), it gives me 1/2, because Fraction takes ints as arguments. I want to have square root of 2 divided by 2, and keep the 2 under the root as to not lose precision while calculating.
Edit: I am using the package "fraction". I couldn't find "fractions" anywhere when I searched for the package to install.

Not entirely certain if the following is what you want, but, here it goes:
from fractions import Fraction as F
import numpy as np
print(F(F(np.sqrt(2)), 2).limit_denominator(max_denominator=100000))
print(5741/8119) # with max_denominator=10000
print(33461/47321)
print(np.sqrt(2)/2)
Will produce:
33461/47321
0.7071067865500678
0.7071067813444348
0.7071067811865476
Update
Irrational to rational conversion cannot possibly preserve precision. No rational fraction can ever be equal to the relevant irrational number. All we can do is get to the closest value!
As a further insight, an enhancement proposal for inclusion of irrational numbers in fractions was rejected.
EDIT
If all you want is to display it mathematically in unicode:
from pylatexenc.latex2text import LatexNodes2Text
# To convert some latex unicode input to actual latex output
in_expr_unicode = r"""$\frac{\sqrt{2}}{2}$"""
out_latex = LatexNodes2Text().latex_to_text(in_expr_unicode)
print(' The math formula: ', out_latex)
which will output:
The math formula: √(2)/2

As a comment suggested, I found sqrt in the sympy package. For example sympy.sqrt(8) produces 2*sqrt(2), so it doesn't just keep the number under the root as not to lose precision, it also lets me make operations with it and simplifies it.

Related

Python math.log and math.log10 giving different results

I was writing a code to calculate number of digits in a given whole number.
I was initially using
math.log(num,10)
but found out it was giving incorrect(approximate) value at num = 1000
math.log(1000,10)
>2.9999999999999996
I understand that the above might be due to the floating point arithmetic in computers being done differently but the same, however, works flawlessly using math.log10
math.log10(1000)
>3.0
Is it correct to assume that log10 is more accurate than log and to use it wherever log base 10 is involved instead of going with the more generalized log function?
Python's math documentation specifically says:
math.log10(x)
Return the base-10 logarithm of x. This is usually more accurate than log(x, 10).
According to the Python Math module documentation:
math.log(x,[base])
With one argument, return the natural logarithm of x (to base e).
With two arguments, return the logarithm of x to the given base, calculated as log(x)/log(base).
Whereas in the math.log10 section:
math.log10(x)
Return the base-10 logarithm of x. This is usually more accurate than log(x, 10).
It might be due to the rounding of the floating point numbers.
Because,
If I take the first method of using log(1000)/log(10), I get:
>>> log(1000)
6.907755278982137
>>> log(10)
2.302585092994046
>>> 6.907755278982137/2.302585092994046
2.9999999999999996

How to get the long version of a float?

I am trying to solve problem 26 from Project Euler and I am wondering how to show the long version of a floating-point number. For example if we have 1/19 how do we get 64, 128, or more digits of that float in python? An even more useful builtin function would be that returns the numbers after the decimal until it repeats? I know that floats technically store decimal points up until a certain point and then round of to keep things efficient, memory-wise, but is there a way to overload that until you get the repeating part of it? I would guess that such a function would give an exception to an irrational number but is there a function that works for at least rational numbers?
See the Decimal datatype.
from decimal import *
getcontext().prec = 64
print(Decimal(1) / Decimal(19))
https://docs.python.org/3/library/decimal.html

How to fix incorrect decimal places of a multiplication result

I'm having a problem with the following calculation:
>>> print(float('32.31') * 1e9)
32310000000.000004
I need this result to be 32310000000.0 (without the false decimal place). This also occurs when using a float directly:
>>> print(32.31 * 1e9)
32310000000.000004
Is there a way to avoid the false decimal place? Analysing the string and rounding to the number of decimal places is not a pefered solution.
Many thanks in advance.
NOTE: The following works fine:
>>> print(32.32 * 1e9)
32320000000.0
so I'm really happy I found the problem above during testing.
EDIT: Thank you for your quick answers! Sorry, I've missed an important point. The method must also work for when the result is less than one, e.g.:
32.31 * 1e-9
...in this case I cannot use round(32.31 * 1e-9, 1)
One way to avoid your problem is to use the decimal module, which works in base ten and thus works the way humans would work (if we were much faster).
from decimal import Decimal
value = float(Decimal('32.31') * Decimal(1e9))
This yields the value you want,
32310000000.0
Another way is to use the fractions module, which works with exact values:
from fractions import Fraction
value = float(Fraction('32.31') * Fraction(1e9))
Note that in both of these methods, we must convert 1e9 and not just the decimal value. Using 1e9 as a float converts the intermediate values to float and the approximation problem pops up again. In either method, you could leave off the final conversion to float type and just continue to work with a Decimal or Fraction value. Either of these methods is somewhat slower than using float types: you gain accuracy at the expense of speed. That speed decrease may matter in some situations.
Regarding your edit to your question: using the value 1e-9 in either of my methods will still result in what you want, namely the value 3.231e-08.
If you are just interested in printing with a single decimal place, you can use round by specifying the number after decimal you want to have, in this case 1
print(round(float('32.31') * 1e9, 1))
# 32310000000.0
This is caused by the representation limitation of the floats's binary mantissa. 32.31 cannot be represented by a division by a power of two. If you know your values will always be integers (or a known number of decimal places), you can use round() or int(round()) to circumvent the limitation.
I'm going to assume you're using Python 3.
If you only care about the result being printed, use string formatting:
print("{r:1.2f}".format(r=32.31 * 1e9))
Another way to do it is using the older formatting syntax:
print("%1.1f" % (32 * 1e9))
I prefer the first, but either will work.

Weird behaviour for Python is_integer from floor

When checking if a floor is an int, the recommend method would be is_integer:
However, I get a weird behaviour with the results of the log function:
print(log(9,3)); #2.0
print((log(9,3)).is_integer()); #True
print((log(243,3))); #5.0
print((log(243,3)).is_integer()); #False
Furthermore:
print((int) (log(9,3))); #2
print((int) (log(243,3))); #4
Is this normal?
log(243,3) simply doesn't give you exactly 5:
>>> '%.60f' % log(243,3)
'4.999999999999999111821580299874767661094665527343750000000000'
As the docs say, log(x, base) is "calculated as log(x)/log(base)". And neither log(243) nor log(3) can be represented exactly, and you get rounding errors. Sometimes you're lucky, sometimes you're not. Don't count on it.
When you want to compare float numbers, use math.isclose().
When you want to convert a float number that is close to an integer, use round().
Float numbers are too subject to error for "conventional" methods to be used. Their precision (and the precision of functions like log) is too limited, unfortunately. What looks like a 5 may not be an exact 5.
And yes: it is normal. This is not a problem with Python, but with every language I'm aware of (they all use the same underlying representation). Python offers some ways to work around float problems: decimal and fractions. Both have their own drawbacks, but sometimes they help. For example, with fractions, you can represent 1/3 without loss of precision. Similarly, with decimal, you can represent 0.1 exactly. However, you'll still have problems with log, sqrt, irrational numbers, numbers that require many digits to be represented and so on.

Python - round a float to 2 digits

I would need to have a float variable rounded to 2 significant digits and store the result into a new variable (or the same of before, it doesn't matter) but this is what happens:
>>> a
981.32000000000005
>>> b= round(a,2)
>>> b
981.32000000000005
I would need this result, but into a variable that cannot be a string since I need to insert it as a float...
>>> print b
981.32
Actually truncate would also work I don't need extreme precision in this case.
What you are trying to do is in fact impossible. That's because 981.32 is not exactly representable as a binary floating point value. The closest double precision binary floating point value is:
981.3200000000000500222085975110530853271484375
I suspect that this may come as something of a shock to you. If so, then I suggest that you read What Every Computer Scientist Should Know About Floating-Point Arithmetic.
You might choose to tackle your problem in one of the following ways:
Accept that binary floating point numbers cannot represent such values exactly, and continue to use them. Don't do any rounding at all, and keep the full value. When you wish to display the value as text, format it so that only two decimal places are emitted.
Use a data type that can represent your number exactly. That means a decimal rather than binary type. In Python you would use decimal.
Try this :
Round = lambda x, n: eval('"%.' + str(int(n)) + 'f" % ' + repr(x))
print Round(0.1, 2)
0.10
print Round(0.1, 4)
0.1000
print Round(981,32000000000005, 2)
981,32
Just indicate the number of digits you want as a second kwarg
I wrote a solution of this problem.
Plz try
from decimal import *
from autorounddecimal.core import adround,decimal_round_digit
decimal_round_digit(Decimal("981.32000000000005")) #=> Decimal("981.32")
adround(981.32000000000005) # just wrap decimal_round_digit
More detail can be found in https://github.com/niitsuma/autorounddecimal
There is a difference between the way Python prints floats and the way it stores floats. For example:
>>> a = 1.0/5.0
>>> a
0.20000000000000001
>>> print a
0.2
It's not actually possible to store an exact representation of many floats, as David Heffernan points out. It can be done if, looking at the float as a fraction, the denominator is a power of 2 (such as 1/4, 3/8, 5/64). Otherwise, due to the inherent limitations of binary, it has to make do with an approximation.
Python recognizes this, and when you use the print function, it will use the nicer representation seen above. This may make you think that Python is storing the float exactly, when in fact it is not, because it's not possible with the IEEE standard float representation. The difference in calculation is pretty insignificant, though, so for most practical purposes it isn't a problem. If you really really need those significant digits, though, use the decimal package.

Categories

Resources