Python gmpy2 f_divmod function confusion - python

I'm pretty new to python and i just started playing with gmpy2, but i'm a little confused about one of the functions and gmpy's documentation isn't helpful in this regard:
I'd like to do division with a modulus (as well as a floor) so i found the f_divmod() function:
f_divmod(...) f_divmod(x, y) returns the quotient and remainder of x
divided by y. The quotient is rounded towards -Inf (floor rounding)
and the remainder will have the same sign as y. x and y must be
integers.
However if this does what i think it should do (and that is probably my mistake), it should do: x / y % m, and i see no way to provide an m. Is this the wrong function for that, or do i need to somehow define a modulus elsewhere?
I see my alternative being:
c = gmpy2.f_div(a, b) % m
Thanks in advance!

Note: I maintain gmpy2.
gmpy2.f_divmod() (along with gmpy2.c_divmod(), gmpy2.t_divmod(), and gmpy2.divmod()) are patterned after the builtin divmod(). All the functions return the quotient and remainder but each functions uses a slightly different rule to compute the quotient and remainder. The names are meant to imply that the functions return the tuple (a // b, a % b). They don't do division followed by mod.
If you want to calculate the quotient using floor division, and then reduce that result modulo another number, then your alternative is correct.
Slightly off-topic hint: You should get into the habit of using // for integer division. In Python 3, / becomes floating point division. // is integer division in both Python 2 and 3.

Related

Why Python builtin numeric type and decimal module differs on a same operation? [duplicate]

With simple ints:
>>> -45 % 360
315
Whereas, using a decimal.Decimal:
>>> from decimal import Decimal
>>> Decimal('-45') % 360
Decimal('-45')
I would expect to get Decimal('315').
Is there any reason for this? Is there a way to get a consistent behaviour (without patching decimal.Decimal)? (I did not change the context, and cannot find how it could be changed to solve this situation).
After a long search (because searching on "%", "mod", "modulo" etc. gives a thousand of results), I finally found that, surprisingly, this is intended:
There are some small differences between arithmetic on Decimal objects
and arithmetic on integers and floats. When the remainder operator %
is applied to Decimal objects, the sign of the result is the sign of
the dividend rather than the sign of the divisor:
>>> (-7) % 4
1
>>> Decimal(-7) % Decimal(4)
Decimal('-3')
I don't know the reason for this, but it looks like it's not possible to change this behaviour (without patching).
Python behaves according to IBM's General Decimal Arithmetic Specification.
The remainder is defined as:
remainder takes two operands; it returns the remainder from integer division. […]
the result is the residue of the dividend after the operation of calculating integer division as described for divide-integer, rounded to precision digits if necessary. The sign of the result, if non-zero, is the same as that of the original dividend.
So because Decimal('-45') // D('360') is Decimal('-0'), the remainder can only be Decimal('-45').
Though why is the quotient 0 and not -1? The specification says:
divide-integer takes two operands; it divides two numbers and returns the integer part of the result. […]
the result returned is defined to be that which would result from repeatedly subtracting the divisor from the dividend while the dividend is larger than or equal to the divisor. During this subtraction, the absolute values of both the dividend and the divisor are used: the sign of the final result is the same as that which would result if normal division were used. […]
Notes: […]
The divide-integer and remainder operations are defined so that they may be calculated as a by-product of the standard division operation (described above). The division process is ended as soon as the integer result is available; the residue of the dividend is the remainder.
How many times can you subtract 360 from 45? 0 times. Is an integer result available? It is. Then the quotient is 0 with a minus sign because the divide operation says that
The sign of the result is the exclusive or of the signs of the operands.
As for why the Decimal Specification goes on this route, instead of doing it like in math where the remainder is always positive, I'm speculating that it could be for the simplicity of the subtraction algorithm. No need to check the sign of the operands in order to compute the absolute value of the quotient. Modern implementations probably use more complicated algorithms anyway, but simplicity could be have an important factor back in the days when the standard was taking form and hardware was simpler (way fewer transistors). Fun fact: Intel switched from radix-2 integer division to radix-16 only in 2007 with the release of Penryn.

Python equal operator for finite precision [duplicate]

I have been asked to test a library provided by a 3rd party. The library is known to be accurate to n significant figures. Any less-significant errors can safely be ignored. I want to write a function to help me compare the results:
def nearlyequal( a, b, sigfig=5 ):
The purpose of this function is to determine if two floating-point numbers (a and b) are approximately equal. The function will return True if a==b (exact match) or if a and b have the same value when rounded to sigfig significant-figures when written in decimal.
Can anybody suggest a good implementation? I've written a mini unit-test. Unless you can see a bug in my tests then a good implementation should pass the following:
assert nearlyequal(1, 1, 5)
assert nearlyequal(1.0, 1.0, 5)
assert nearlyequal(1.0, 1.0, 5)
assert nearlyequal(-1e-9, 1e-9, 5)
assert nearlyequal(1e9, 1e9 + 1 , 5)
assert not nearlyequal( 1e4, 1e4 + 1, 5)
assert nearlyequal( 0.0, 1e-15, 5 )
assert not nearlyequal( 0.0, 1e-4, 6 )
Additional notes:
Values a and b might be of type int, float or numpy.float64. Values a and b will always be of the same type. It's vital that conversion does not introduce additional error into the function.
Lets keep this numerical, so functions that convert to strings or use non-mathematical tricks are not ideal. This program will be audited by somebody who is a mathematician who will want to be able to prove that the function does what it is supposed to do.
Speed... I've got to compare a lot of numbers so the faster the better.
I've got numpy, scipy and the standard-library. Anything else will be hard for me to get, especially for such a small part of the project.
As of Python 3.5, the standard way to do this (using the standard library) is with the math.isclose function.
It has the following signature:
isclose(a, b, rel_tol=1e-9, abs_tol=0.0)
An example of usage with absolute error tolerance:
from math import isclose
a = 1.0
b = 1.00000001
assert isclose(a, b, abs_tol=1e-8)
If you want it with precision of n significant digits, simply replace the last line with:
assert isclose(a, b, abs_tol=10**-n)
There is a function assert_approx_equal in numpy.testing (source here) which may be a good starting point.
def assert_approx_equal(actual,desired,significant=7,err_msg='',verbose=True):
"""
Raise an assertion if two items are not equal up to significant digits.
.. note:: It is recommended to use one of `assert_allclose`,
`assert_array_almost_equal_nulp` or `assert_array_max_ulp`
instead of this function for more consistent floating point
comparisons.
Given two numbers, check that they are approximately equal.
Approximately equal is defined as the number of significant digits
that agree.
Here's a take.
def nearly_equal(a,b,sig_fig=5):
return ( a==b or
int(a*10**sig_fig) == int(b*10**sig_fig)
)
I believe your question is not defined well enough, and the unit-tests you present prove it:
If by 'round to N sig-fig decimal places' you mean 'N decimal places to the right of the decimal point', then the test assert nearlyequal(1e9, 1e9 + 1 , 5) should fail, because even when you round 1000000000 and 1000000001 to 0.00001 accuracy, they are still different.
And if by 'round to N sig-fig decimal places' you mean 'The N most significant digits, regardless of the decimal point', then the test assert nearlyequal(-1e-9, 1e-9, 5) should fail, because 0.000000001 and -0.000000001 are totally different when viewed this way.
If you meant the first definition, then the first answer on this page (by Triptych) is good.
If you meant the second definition, please say it, I promise to think about it :-)
There are already plenty of great answers, but here's a think:
def closeness(a, b):
"""Returns measure of equality (for two floats), in unit
of decimal significant figures."""
if a == b:
return float("infinity")
difference = abs(a - b)
avg = (a + b)/2
return math.log10( avg / difference )
if closeness(1000, 1000.1) > 3:
print "Joy!"
This is a fairly common issue with floating point numbers. I solve it based on the discussion in Section 1.5 of Demmel[1]. (1) Calculate the roundoff error. (2) Check that the roundoff error is less than some epsilon. I haven't used python in some time and only have version 2.4.3, but I'll try to get this correct.
Step 1. Roundoff error
def roundoff_error(exact, approximate):
return abs(approximate/exact - 1.0)
Step 2. Floating point equality
def float_equal(float1, float2, epsilon=2.0e-9):
return (roundoff_error(float1, float2) < epsilon)
There are a couple obvious deficiencies with this code.
Division by zero error if the exact value is Zero.
Does not verify that the arguments are floating point values.
Revision 1.
def roundoff_error(exact, approximate):
if (exact == 0.0 or approximate == 0.0):
return abs(exact + approximate)
else:
return abs(approximate/exact - 1.0)
def float_equal(float1, float2, epsilon=2.0e-9):
if not isinstance(float1,float):
raise TypeError,"First argument is not a float."
elif not isinstance(float2,float):
raise TypeError,"Second argument is not a float."
else:
return (roundoff_error(float1, float2) < epsilon)
That's a little better. If either the exact or the approximate value is zero, than the error is equal to the value of the other. If something besides a floating point value is provided, a TypeError is raised.
At this point, the only difficult thing is setting the correct value for epsilon. I noticed in the documentation for version 2.6.1 that there is an epsilon attribute in sys.float_info, so I would use twice that value as the default epsilon. But the correct value depends on both your application and your algorithm.
[1] James W. Demmel, Applied Numerical Linear Algebra, SIAM, 1997.
"Significant figures" in decimal is a matter of adjusting the decimal point and truncating to an integer.
>>> int(3.1415926 * 10**3)
3141
>>> int(1234567 * 10**-3)
1234
>>>
Oren Shemesh got part of the problem with the problem as stated but there's more:
assert nearlyequal( 0.0, 1e-15, 5 )
also fails the second definition (and that's the definition I learned in school.)
No matter how many digits you are looking at, 0 will not equal a not-zero. This could prove to be a headache for such tests if you have a case whose correct answer is zero.
There is a interesting solution to this by B. Dawson (with C++ code)
at "Comparing Floating Point Numbers". His approach relies on strict IEEE representation of two numbers and the enforced lexicographical ordering when said numbers are represented as unsigned integers.
I have been asked to test a library provided by a 3rd party
If you are using the default Python unittest framework, you can use assertAlmostEqual
self.assertAlmostEqual(a, b, places=5)
There are lots of ways of comparing two numbers to see if they agree to N significant digits. Roughly speaking you just want to make sure that their difference is less than 10^-N times the largest of the two numbers being compared. That's easy enough.
But, what if one of the numbers is zero? The whole concept of relative-differences or significant-digits falls down when comparing against zero. To handle that case you need to have an absolute-difference as well, which should be specified differently from the relative-difference.
I discuss the problems of comparing floating-point numbers -- including a specific case of handling zero -- in this blog post:
http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/

Why is -1/2 evaluated to 0 in C++, but -1 in Python?

C++: cout << -1/2 evaluates to 0
Python: -1/2 evaluates to -1.
Why is this the case?
Integer division in C++ rounds toward 0, and in Python, it rounds toward -infinity.
People dealing with these things in the abstract tend to feel that rounding toward negative infinity makes more sense (that means it's compatible with the modulo function as defined in mathematics, rather than % having a somewhat funny meaning). The tradition in programming languages is to round toward 0--this wasn't originally defined in C++ (following C's example at the time), but eventually C++ (and C) defined it this way, copying Fortran.
From the Python docs (emphasis mine):
The / (division) and // (floor division) operators yield the quotient of their arguments. The numeric arguments are first converted to a common type. Plain or long integer division yields an integer of the same type; the result is that of mathematical division with the ‘floor’ function applied to the result.
The floor function rounds to the number closest to negative infinity, hence -1.
For C++, from this reference: 5.2 — Arithmetic operators
It is easiest to think of the division operator as having two
different “modes”. If both of the operands are integers, the division
operator performs integer division. Integer division drops any
fractions and returns an integer value.
Thus, -1/2 would yield -0.5 with the fraction dropped, yielding 0.
As SethMMorton indicated, Python's rule is floor, which yields -1. It's described in 5. Expressions.
Put in the terms that Mike Graham mentioned, floor is a round toward minus infinity. Dropping the fraction is a round toward zero.
I am not sure about Python, but in C++ integer/integer = integer, and therefore in case of -1/2 is -0.5 which is rounded automatically to integer and therefore you get the 0 answer.
In case of Python, maybe the system used the floor function to convert the result into an integer.

calculating n-th roots using Python 3's decimal module

Is there a built-in way to calculate the correctly rounded n-th root of a Python 3 decimal object?
According to the documentation, there is a function power(x,y) :
With two arguments, compute x**y. If x is negative then y must be
integral. The result will be inexact unless y is integral and the
result is finite and can be expressed exactly in ‘precision’ digits.
The result should always be correctly rounded, using the rounding mode
of the current thread’s context
This implies that power(x, 1.0/n) should give you what you want.
You can also take the nth root with
nthRoot = Decimal(x) ** (Decimal(1.0) / Decimal(n) )
Not sure if you consider either of these "built in" as you have to compute the reciprocal of n explicitly to get the nth root.

How to implement division with round-towards-infinity in Python

I want 3/2 to equal 2 not 1.5
I know there's a mathematical term for that operation(not called rounding up), but I can't recall it right now.
Anyway, how do i do that without having to do two functions?
ex of what I do NOT want:
answer = 3/2 then math.ceil(answer)=2 (why does math.ceil(3/2)=1?)
ex of what I DO want:
"function"(3/2) = 2
To give a short answer...
Python only offers native operators for two types of division: "true" division, and "round down" division. So what you want isn't available as a single function. However, it is possible to easily implement a number of different types of division-with-rounding using some short expressions.
Per the title's request: given strictly integer inputs, "round up" division can be implemented using (a+(-a%b))//b, and "round away from zero" division can be implemented using the more complex a//b if a*b<0 else (a+(-a%b))//b. One of those is probably what you want. As to why...
To give a longer answer...
First, let me answer the subquestion about why 3/2==1 and math.ceil(3/2)==1.0, by way of explaining how the Python division operator works. There are two main issues at play...
float vs int division: Under Python 2, division behaves differently depending on the type of the inputs. If both a and b are integers, a/b performs "round down" or "floor integer" division (eg 3/2==1, but -3/2==-2). This is equivalent to int(math.floor(float(a)/b)) .
But if at least one of a and b are floats, Python performs "true" division, and gives you a float result (eg 3.0/2==1.5, and -3.0/2==-1.5). This is why you'll sometimes see the construction float(a)/b: it's being used to force true division even both inputs are integers (eg float(3)/2==1.5). This is why your example math.ceil(3/2) returns 1.0, whereas math.ceil(float(3)/2) returns 2.0. The result has already been rounded down before it even reaches math.ceil().
"true division" by default: In 2001, it was decided (PEP 238) that Python's division operator should be changed so that it always performs "true" division, regardless of whether the inputs are floats or integers (eg, this would make 3/2==1.5). In order to not break existing scripts, the change in default behavior was deferred until Python 3.0; in order to get this behavior under Python 2.x, you have to enable it per-file by adding from __future__ import division to the top of the file. Otherwise the old type-dependant behavior is used.
But "round down" division is still frequently needed, so the PEP didn't do way with it entirely. Instead, it introduced a new division operator: a//b, which always performs round down division, even if the inputs include floats. This can be used without doing anything special under both Python 2.2+ and 3.x.
That out of that way, division-with-rounding:
In order to simplify things, the following expressions all use the a//b operator when working on integers, since it will behave the same under all python versions. As well, I'm making an assumption that 0<=a%b<b if b is positive, and b<=a%b<=0 if b is negative. This is how Python behaves, but other languages may have slightly different modulus operators.
The four basic types of integer division with rounding:
"round down" aka "floor integer" aka "round to minus infinity" divsion: python offers this natively via a//b.
"round up" aka "ceiling integer" aka "round to positive infinity" division: this can be achieved via int(math.ceil(float(a)/b)) or (a+(-a%b))//b. The latter equation works because -a%b is 0 if a is a multiple of b, and is otherwise the amount we need to add to a to get to the next highest multiple.
"round towards zero" aka "truncated" division - this can be achieved via int(float(a)/b). Doing this without using floating point is trickier... since Python only offers round-down integer division, and the % operator has a similar round-down bias, we don't have any non-floating-point operators which round symmetrically about 0. So the only way I can think of is to construct a piecewise expression out of round-down and round-up: a//b if a*b>0 else (a+(-a%b))//b.
"round away from zero" aka "round to (either) infinity" division - unfortunately, this is even trickier than round-towards-zero. We can't leverage the truncating behavior of the int operator anymore, so I can't think of a simple expression even when including floating-point ops. So I have to go with the inverse of the round-to-zero expression, and use a//b if a*b<0 else (a+(-a%b))//b.
Note that if you're only using positive integers, (a+b-1)//b provides round up / away from zero even more efficiently than any of the above solutions, but falls apart for negatives.
Hope that helps... and happy to make edits if anyone can suggest better equations for round to/away from zero. I find the ones I have particularly unsatisfactory.
Integral division in Python 3:
3 // 2 == 1
Non-integral division in Python 3:
3 / 2 == 1.5
What you're talking about is not a division by all means.
The intent of the OP's question is "How to implement division with round-towards-infinity in Python" (suggest you change the title).
This is a perfectly legitimate rounding mode as per the IEEE-754 standard (read this overview), and the term for it is "round towards infinity" (or "round away from zero"). Most of the 9 downvotes were beating up on the OP unfairly. Yes, there is no single-function way to do this in native Python, but we can use round(float(a)/b) or else subclass numbers.Number and override __div__().
The OP would need to clarify whether they want -3/2 to round to -2 or -1 (or don't-care for negative operands). Since they already said they don't want round-upwards, we can infer -3/2 should round to -2.
Enough theory. For implementations:
If you just want the fast-and-dirty one-line solution for round-towards-infinity , use round(float(a)/b)
math.ceil(float(a)/b) gives you round-upwards, which you said you don't want
But if this is your default division operation, or you are doing a lot of this, then do like the pseudocode below: inherit from one of the subclasses of numbers.Number Real, Rational or Integral (new in 2.6), redefine __div__() or else define a non-default alternative __divra__() operation. You could define a class member or classmethod rounding_mode and look it up during divisions. Be careful of __rdiv__() and mixing with ordinary floats though.
.
import numbers
class NumberWithRounding(numbers.Integral):
# Here you could implement a classmethod setRoundingMode() or member rounding_mode
def __div__(self,other):
# here you could consider value of rounding_mode, or else hardwire it like:
return round(float(self)/other)
# You also have to raise ImplementationError/ pass/ or implement the other 31
# methods for Float: __abs__(),...,__xor__() Just shortcut that for now...
When you divide two integers, the result is an integer.
3 / 2 equals 1, not 1.5.
See the documentation, note 1:
For (plain or long) integer division, the result is an integer. The result is always rounded towards minus infinity: 1/2 is 0, (-1)/2 is -1, 1/(-2) is -1, and (-1)/(-2) is 0. Note that the result is a long integer if either operand is a long integer, regardless of the numeric value.
Once you get 1 from the division, there is no way to turn that into 2.
To get 1.5, you need floating-point division: 3.0 / 2.
You can then call math.ceil to get 2.
You are mistaken; there is no mathematical function that divides, then rounds up.
The best you can do is write your own function that takes two floats and calls math.ceil.
What you probably want is something like:
math.ceil(3.0/2.0)
# or
math.ceil(float(3)/float(2))
You could also do an import from future:
from __future__ import division
math.ceil(3/2) # == 2
But, if you do this, to get the current behavior of integer division you need to use the double slash:
3 // 2 == 1 # True
Integer division with ceiling rounding (to +Inf), floor rounding (to -Inf), and truncation (to 0) is available in gmpy2.
>>> gmpy2.c_div(3,2)
mpz(2)
>>> help(gmpy2.c_div)
Help on built-in function c_div in module gmpy2:
c_div(...)
c_div(x,y): returns the quotient of x divided by y. The quotient
is rounded towards +Inf (ceiling rounding). x and y must be integers.
>>> help(gmpy2.f_div)
Help on built-in function f_div in module gmpy2:
f_div(...)
f_div(x,y): returns the quotient of x divided by y. The quotient
is rounded towards -Inf (floor rounding). x and y must be integers.
>>> help(gmpy2.t_div)
Help on built-in function t_div in module gmpy2:
t_div(...)
t_div(x,y): returns the quotient of x divided by y. The quotient
is rounded towards 0. x and y must be integers.
>>>
gmpy2 is available at http://code.google.com/p/gmpy/
(Disclaimer: I'm the current maintainer of gmpy and gmpy2.)
I think that what you're looking for is this:
assuming you have x (3) and y (2),
result = (x + y - 1) // y;
this is the equivalent of a ceiling without the use of floating points.
Of course, y cannot be 0.
Firstly, you want to be using floating-point division in the arguments. Use:
from __future__ import division
If you always want to round up, so f(3/2)==2 and f(1.4)==2, then you want f to be math.trunc(math.ceil(x)).
If you want to get the closest integer, but have ties round up, then you want math.trunc(x + 0.5). That way f(3/2)==2 and f(1.4)==1.

Categories