I am trying to do some arithmetic with gmpy2 in python. Unfortunately I don't
know what are the types of returned values of this arithmetics. For example:
x=float(gmpy2.comb(100,50))/gmpy2.comb(200,100)
print x
print isinstance(x, (int, long, float, complex))
gives me:
1.114224180581451e-30
False
I couldn't find any helpful information when I Googled a bit.
Is there a way that I can get an object type in python in general?
Otherwise, what is the exact type of this value? Is it an mpz?
And the last question, when I do arithmetic with mpz values and for
example float, will it always cast the type to mpz?
P.S. I don't know if mpz is a correct term I am using here! I would be also happy
if somebody with high reputation adds gmpy to tags in stackoverflow to make them
questions more accessible to the people who know gmpy.
I don't know about gmpy2 but you can find the type of an object in Python using x.__class__.
With new-style classes you can also use type(x).
gmpy2 introduces several new data types: mpz, mpq, mpfr, and mpc. They are analogous to Python's int/long, fractions.Fraction, float and complex types. So division involving an mpz will normally result in an mpfr.
In your example, you create an mpz, convert it to a float, and then divide it by an mpz. When performing the division, gmpy2 converts the float to an mpfr and then performs the division. If you want a float result, you should apply float() to the entire result and not just gmpy2.comb(100,50). Note the differences in the parenthesis.
>>> float(gmpy2.comb(100,50))/gmpy2.comb(200,100)
mpfr('1.114224180581451e-30')
>>> float(gmpy2.comb(100,50)/gmpy2.comb(200,100))
1.114224180581451e-30
Why the conversion from float to mpfr? The mpfr data type can support much higher precision and has a significantly wider range that a float. As long as the precision of mpfr is greater than or equal to the precision of a float (i.e. 53), then the conversion is lossless.
Disclaimer: I maintain gmpy and gmpy2.
Related
I'm trying to use python to investigate the effect of C++ truncating doubles to floats.
In C++ I have relativistic energies and momenta which are cast to floats, and I'm trying to work out whether at these energies saving them as doubles would actually result in any improved precision in the difference between energy and momentum.
I chose python because it seemed like a quick and easy way to look at this with some test energies, but now I realise that the difference between C++ 32 bit floats and 64 bit doubles isn't reflect in python.
I haven't yet found a simple way of taking a number and reducing the number of bits used to store it in python. Please can someone enlighten me?
I'd suggest using Numpy as well. It exposes various data types including C style floats and doubles.
Other useful tools are the C++17 style hex encoding and the decimal module for getting accurate decimal expansions.
For example:
import numpy as np
from decimal import Decimal
for ftype in (np.float32, np.float64):
v = np.exp(ftype(1))
pyf = float(v)
print(f"{v.dtype} {v:20} {pyf.hex()} {Decimal(pyf)}")
giving
float32 2.7182819843292236 0x1.5bf0aa0000000p+1 2.7182819843292236328125
float64 2.718281828459045 0x1.5bf0a8b145769p+1 2.718281828459045090795598298427648842334747314453125
Unfortunately the hex-encoding is a bit verbose for float32s (i.e. the zeros are redundant), and the decimal module doesn't know about Numpy floats, so you need to convert it to a Python-native float first. But given that binary32's can be directly converted to binary64's this doesn't seem too bad.
Just thought, that it sounds like you might want these written out to a file. If so, Numpy scalars (and ndarrays) support the buffer protocol, which means you can just write them out or use bytes(v) to get the underlying bytes.
Why does Python return True when I compare int and float objects which have the same value?
For example:
>>> 5*2 == 5.0*2.0
True
It's not as simple as a type conversion.
10 == 10.0 delegates to the arguments' __eq__ methods, trying (10).__eq__(10.0) first, and then (10.0).__eq__(10) if the first call returns NotImplemented. It makes no attempt to convert types. (Technically, the method lookup uses a special routine that bypasses instance __dict__ entries and __getattribute__/__getattr__ overrides, so it's not quite equivalent to calling the methods yourself.)
int.__eq__ has no idea how to handle a float:
>>> (10).__eq__(10.0)
NotImplemented
but float.__eq__ knows how to handle ints:
>>> (10.0).__eq__(10)
True
float.__eq__ isn't just performing a cast internally, either. It has over 100 lines of code to handle float/int comparison without the rounding error an unchecked cast could introduce. (Some of that could be simplified if the C-level comparison routine didn't also have to handle >, >=, <, and <=.)
Objects of different types, except different numeric types, never compare equal.
And:
Python fully supports mixed arithmetic: when a binary arithmetic operator has operands of different numeric types, the operand with the “narrower” type is widened to that of the other, where integer is narrower than floating point, which is narrower than complex. Comparisons between numbers of mixed type use the same rule.
https://docs.python.org/3/library/stdtypes.html#numeric-types-int-float-complex
The comparison logic is implemented by each type's __eq__ method. And the standard numeric types are implemented in a way that they support comparisons (and arithmetic operations) among each other. Python as a language never does implicit type conversion (like Javascript's == operator would do implicit type juggling).
The simple answer is that the langue is designed this way. Here is an excerpt from the documentation supporting this:
6.10.1 Value Comparisons
Numbers of built-in numeric types (Numeric Types — int, float, complex) and of the standard library types fractions.Fraction and decimal.Decimal can be compared within and across their types, with the restriction that complex numbers do not support order comparison.
In other words, we want different numeric types with the same value to be equal.
PEP 20
Special cases aren't special enough to break the rules.
Although practicality beats purity.
What benefit is there to making numeric types not comparable, besides making life difficult in most common cases?
You can have a look at the source code for the CPython implementation.
The function is preceded by this comment explaining how the conversion is attempted:
/* Comparison is pretty much a nightmare. When comparing float to float,
* we do it as straightforwardly (and long-windedly) as conceivable, so
* that, e.g., Python x == y delivers the same result as the platform
* C x == y when x and/or y is a NaN.
* When mixing float with an integer type, there's no good *uniform* approach.
* Converting the double to an integer obviously doesn't work, since we
* may lose info from fractional bits. Converting the integer to a double
* also has two failure modes: (1) an int may trigger overflow (too
* large to fit in the dynamic range of a C double); (2) even a C long may have
* more bits than fit in a C double (e.g., on a 64-bit box long may have
* 63 bits of precision, but a C double probably has only 53), and then
* we can falsely claim equality when low-order integer bits are lost by
* coercion to double. So this part is painful too.
*/
Other implementations are not guaranteed to follow the same logic.
From the documentation:
Python fully supports mixed arithmetic: when a binary arithmetic
operator has operands of different numeric types, the operand with the
“narrower” type is widened to that of the other, where plain integer
is narrower than long integer is narrower than floating point is
narrower than complex. Comparisons between numbers of mixed type use
the same rule.
According to this 5*2 is widened to 10.0 and which is equal to 10.0
If you are comparing the mixed data types then the result will be considered on the basics of data type which is having long range, so in your case float range is more then int
float max number can be --> 1.7976931348623157e+308
int max number can be --> 9223372036854775807
Thanks
The == operator compares only the values but not the types. You can use the 'is' keyword to achieve the same effect as using === in other languages. For instance
5 is 5.0
returns
False
==
is a comparison operator
You are actually asking the interpreter if both sides of your expression are equal or not.
In other words you are asking for it to return a Boolean value, not to convert data types. If you want to convert the data types you will have to do so implicitly in your code.
While working on an issue, I stumbled at something I cannot really undestand on my own.
I have a variable:
a = pow(2, 1024)
Its type is long int. If I try casting it explicitly to float, like float(a), I receive OverflowError. The number is too big to fit in 64bit float, so it's understandable.
Then I try implicit cast, through mutliplying it by a float number:
b = a * 11.0
Once again, the OverflowError occurs, which is fine, because according to python docs, implicit conversion from long int to float happens. So the result is like before.
Finally, I try comparison:
a > 11.0
returns True. The OverflowError doesn't occur. And that confuses me a lot. How does the Python comparison mechanism work, if it doesn't require numerics to be in the same format? Accordind to this,
Python fully supports mixed arithmetic: when a binary arithmetic operator has operands of different numeric types, the operand with the “narrower” type is widened to that of the other, where plain integer is narrower than long integer is narrower than floating point is narrower than complex. Comparisons between numbers of mixed type use the same rule. The constructors int(), long(), float(), and complex() can be used to produce numbers of a specific type.
My question is, why a is not being cast to float in forementioned comparison?
The version of Python I'm using is 2.7.15. Thanks in an advance
From the source:
/* Comparison is pretty much a nightmare. When comparing float to float,
* we do it as straightforwardly (and long-windedly) as conceivable, so
* that, e.g., Python x == y delivers the same result as the platform
* C x == y when x and/or y is a NaN.
* When mixing float with an integer type, there's no good *uniform* approach.
* Converting the double to an integer obviously doesn't work, since we
* may lose info from fractional bits. Converting the integer to a double
* also has two failure modes: (1) a long int may trigger overflow (too
* large to fit in the dynamic range of a C double); (2) even a C long may have
* more bits than fit in a C double (e.g., on a 64-bit box long may have
* 63 bits of precision, but a C double probably has only 53), and then
* we can falsely claim equality when low-order integer bits are lost by
* coercion to double. So this part is painful too.
*/
As such, the potential pitfalls of conversion are taken into account.
The exact error is OverflowError: int too large to convert to float
Which also means that any int that generates that error is by definition bigger then any possible float. So just checking if it's bigger should return True.
I'm not entirely sure, but I wouldn't be surprised if the implementation is just catching this error in the background (when trying to cast to float) and returning True in that case.
That is always true with the exception of float('inf') which is a special case that should return False (and does)
I am working on some scripts that handle calculation with the need of maintaining high accuracy of the results so I started using decimal.Decimal instead of built-in float.
I know it doesn't work with float-type values and it returns TypeError: unsupported operand type(s) for +: 'decimal.Decimal' and 'float'
What I need to know exactly is why it doesn't support this type of operations with float.
Sample:
from decimal import Decimal
expr_= 1.2+Decimal('1')
As this seems logic for me when I try to add str to float to get this type of error but not while trying to calculate two numeric values.
While I can easily do the same thing using SymPy Float data-type without facing any issues. Ex:
from decimal import Decimal
from sympy import Float
expr_=Decimal('1.6')+Float(1.2)
PEP 327 -- Decimal Data Type explains:
Aahz is strongly opposed to interact with float, suggesting an explicit conversion:
The problem is that Decimal is capable of greater precision, accuracy, and range than float.
The example of the valid python expression, 35 + 1.1, seems to suggest that
Decimal(35) + 1.1 should also be valid. However, a closer look shows that it
only demonstrates the feasibility of integer to floating point
conversions. Hence, the correct analog for decimal floating point is 35 +
Decimal(1.1). Both coercions, int-to-float and int-to-Decimal, can be done
without incurring representation error.
The question of how to coerce between binary and decimal floating point is
more complex. I proposed allowing the interaction with float, making an exact
conversion and raising ValueError if exceeds the precision in the current
context (this is maybe too tricky, because for example with a precision of 9,
Decimal(35) + 1.2 is OK but Decimal(35) + 1.1 raises an error).
This resulted to be too tricky. So tricky, that c.l.p agreed to raise TypeError in this case: you could not mix Decimal and float.
This is the python developer's mailing list discussion on the subject. For the full thread, see the 2003-10 archive and search for "Decimal".
So in the end, the "Explicit is better than implicit" philosophy won out.
So I have a list of tuples of two floats each. Each tuple represents a range. I am going through another list of floats which represent values to be fit into the ranges. All of these floats are < 1 but positive, so precision matter. One of my tests to determine if a value fits into a range is failing when it should pass. If I print the value and the range that is causing problems I can tell this much:
curValue = 0.00145000000671
range = (0.0014500000067055225, 0.0020968749796738849)
The conditional that is failing is:
if curValue > range[0] and ... blah :
# do some stuff
From the values given by curValue and range, the test should clearly pass (don't worry about what is in the conditional). Now, if I print explicitly what the value of range[0] is I get:
range[0] = 0.00145000000671
Which would explain why the test is failing. So my question then, is why is the float changing when it is accessed. It has decimal values available up to a certain precision when part of a tuple, and a different precision when accessed. Why would this be? What can I do to ensure my data maintains a consistent amount of precision across my calculations?
The float doesn't change. The built-in numberic types are all immutable. The cause for what you're observing is that:
print range[0] uses str on the float, which (up until very recent versions of Python) printed less digits of a float.
Printing a tuple (be it with repr or str) uses repr on the individual items, which gives a much more accurate representation (again, this isn't true anymore in recent releases which use a better algorithm for both).
As for why the condition doesn't work out the way you expect, it's propably the usual culprit, the limited precision of floats. Try print repr(curVal), repr(range[0]) to see if what Python decided was the closest representation of your float literal possible.
In modern day PC's floats aren't that precise. So even if you enter pi as a constant to 100 decimals, it's only getting a few of them accurate. The same is happening to you. This is because in 32-bit floats you only get 24 bits of mantissa, which limits your precision (and in unexpected ways because it's in base2).
Please note, 0.00145000000671 isn't the exact value as stored by Python. Python only diplays a few decimals of the complete stored float if you use print. If you want to see exactly how python stores the float use repr.
If you want better precision use the decimal module.
It isn't changing per se. Python is doing its best to store the data as a float, but that number is too precise for float, so Python modifies it before it is even accessed (in the very process of storing it). Funny how something so small is such a big pain.
You need to use a arbitrary fixed point module like Simple Python Fixed Point or the decimal module.
Not sure it would work in this case, because I don't know if Python's limiting in the output or in the storage itself, but you could try doing:
if curValue - range[0] > 0 and...