In excel, there is this formula:
=ROUNDDOWN(D28-D33-D34, -2) and I got the results ==> 166400. But the result without the Rounddown formulas is ==> 166468.50.
My question is how to get the same in python. When I do round (n, -2) I get ==> 166500.
Any help would be much appreciated! Thank you.
This is an implementation of the ROUNDDOWN(x,n) function in Python
def rounddown(x,n):
return int(x// 10**n * 10**n)
print(rounddown(166468.50,1)) #166460
print(rounddown(166468.50,2)) #166400
print(rounddown(166468.50,3)) #166000
[Update]
A new version of the function rounddown, that can handle both positive and negative values of n. (simulate the ROUNDDOWN(x,n) found in Excel)
def rounddown(x,n):
sign=1 if n>0 else 0 # getting the sign of n.
n=abs(n) # getting the absolute value of n.
p= 10**n # calculating p the nth power of 10.
result= (x // p) * p + sign * p # calculating result.
return int( result )
# sample result
print(rounddown(166468.50,1)) #166470
print(rounddown(166468.50,2)) #166500
print(rounddown(166468.50,3)) #167000
print(rounddown(166468.50,0)) #166468
print(rounddown(166468.50,-1)) #166460
print(rounddown(166468.50,-2)) #166400
print(rounddown(166468.50,-3)) #166000
Related
I know my algebra is rusty, but isn't the following an identity operation: multiplying an element of a GF by the cardinal of the field (the modulus)? I wrote a program to verify it but couldn't:
from ecpy.curves import Curve, Point # I use Python 2.7
def bin256(num):
"""binary conversion, returns a binary string, MSB first and LSB last"""
return '{:0256b}'.format(num)
def ec_multiply(P, d):
"""double-and-add algo. Index decreasing, same naming as Wikipedia:
P is a point on the curve
d is a long
returns P*d"""
Q = None
for bit in map(int, bin256(d)):
if Q is not None:
Q = Q + Q
if bit:
if Q is None:
Q = P
else:
Q = Q + P
return Q
def main():
"""Picks a random point on secp256k1 and multiply it by the modulus
of secp256k1 and print the result."""
cv = Curve.get_curve('secp256k1')
N = Point(0x65d5b8bf9ab1801c9f168d4815994ad35f1dcb6ae6c7a1a303966b677b813b00,
0xe6b865e529b8ecbf71cf966e900477d49ced5846d7662dd2dd11ccd55c0aff7f, cv)
MODULUS = 2**256 - 2**32 - 2**9 - 2**8 - 2**7 - 2**6 - 2**4 - 1
Q = ec_multiply(N, MODULUS)
print 'Q: %064x %064x' % (Q.x, Q.y)
if __name__ == '__main__':
main()
But I get a different point:
Q: d113d66bf911fbf026b2a3e24c96bba45ca2d2b130cbf312a36e584249153090 56cabae3704f1c5a7957cbb1d9e2f6198337c59c02b2974d32fb7501b7e287d2
I expected Q: 65d5b8bf..., e6b865e5... instead.
Any idea why multiplying by the modulus is not working in secp256k1? Thanks in advance.
Notes:
I am using the python elliptic curve library ecpy which just works, I've tested against another library (py_ecc, pure python) and I get consistent results.
The multiplication over secp256k1 uses the double-and-add algo from Wikipedia where the index is decreasing because I start from the MSB.
I use this excellent paper that explains everything about EC and how to implement them.
So, I'm trying to find the value of cos(x), where x=1.2. I feel the script I have written should be fine, however, the value I get out isn't correct. That is; cos(1.2)=0.6988057880877979, for 25 terms, when I should get out: cos(1.2)=0.36235775.
I have created a similar program for calculating sin(1.2) which works fine.
Calculating sin(1.2):
import math as m
x=1.2
k=1
N=25
s=x
sign=1.0
while k<N:
sign=-sign
k=k+2
term=sign*x**k/m.factorial(k)
s=s+term
print('sin(%g) = %g (approximation with %d terms)' % (x,s,N))
Now trying to calculate cos(1.2):
import math as m
x=1.2
k=1
N=25
s=x
sign=1.0
while k<N:
sign=-sign
k=k+1
term=sign*x**k/m.factorial(k)
s=s+term
print(s)
You shouldn't be setting your initial sum to 1.2, and your representation of the expansion
is a bit off - we need to account for the even-ness of the function, so increment k by 2. Also, without modifying your program structure, you'd have to set the initial variables so they are correctly put to their starting values at the beginning of the first loop. Re-ordering your loop control flow a bit, we have
import math as m
x=1.2
k=0
N=25
s=0
sign=1.0
while k<N:
term=sign*x**(k)/m.factorial(k)
s=s+term
k += 2
sign = -sign
print(s)
Gives
0.3623577544766735
I think you're using the wrong series for the cosine, the correct formula would be (I highlighted the important differences with ^):
sum_over_n [(-1)**n * x ** (2 * n) / (math.factorial(2 * n))]
# ^^^^ ^^^^
that means to add n-terms you have something like:
def cosine_by_series(x, terms):
cos = 0
for n in range(terms):
cos += ((-1)**n) * (x ** (2*n)) / (math.factorial(2 * n))
return cos
# or simply:
# return sum(((-1)**n) * (x ** (2*n)) / (math.factorial(2 * n)) for n in range(terms)
which gives:
>>> cosine_by_series(1.2, 30)
0.3623577544766735
I am trying to complete the following exercise:
https://www.codewars.com/kata/whats-a-perfect-power-anyway/train/python
I tried multiple variations, but my code breaks down when big numbers are involved (I tried multiple variations with solutions involving log and power functions):
Exercise:
Your task is to check wheter a given integer is a perfect power. If it is a perfect power, return a pair m and k with m^k = n as a proof. Otherwise return Nothing, Nil, null, None or your language's equivalent.
Note: For a perfect power, there might be several pairs. For example 81 = 3^4 = 9^2, so (3,4) and (9,2) are valid solutions. However, the tests take care of this, so if a number is a perfect power, return any pair that proves it.
The exercise uses Python 3.4.3
My code:
import math
def isPP(n):
for i in range(2 +n%2,n,2):
a = math.log(n,i)
if int(a) == round(a, 1):
if pow(i, int(a)) == n:
return [i, int(a)]
return None
Question:
How is it possible that I keep getting incorrect answers for bigger numbers? I read that in Python 3, all ints are treated as "long" from Python 2, i.e. they can be very large and still represented accurately. Thus, since i and int(a) are both ints, shouldn't the pow(i, int(a)) == n be assessed correctly? I'm actually baffled.
(edit note: also added integer nth root bellow)
you are in the right track with logarithm but you are doing the math wrong, also you are skipping number you should not and only testing all the even number or all the odd number without considering that a number can be even with a odd power or vice-versa
check this
>>> math.log(170**3,3)
14.02441559235585
>>>
not even close, the correct method is described here Nth root
which is:
let x be the number to calculate the Nth root, n said root and r the result, then we get
rn = x
take the log in any base from both sides, and solve for r
logb( rn ) = logb( x )
n * logb( r ) = logb( x )
logb( r ) = logb( x ) / n
blogb( r ) = blogb( x ) / n
r = blogb( x ) / n
so for instance with log in base 10 we get
>>> pow(10, math.log10(170**3)/3 )
169.9999999999999
>>>
that is much more closer, and with just rounding it we get the answer
>>> round(169.9999999999999)
170
>>>
therefore the function should be something like this
import math
def isPP(x):
for n in range(2, 1+round(math.log2(x)) ):
root = pow( 10, math.log10(x)/n )
result = round(root)
if result**n == x:
return result,n
the upper limit in range is to avoid testing numbers that will certainly fail
test
>>> isPP(170**3)
(170, 3)
>>> isPP(6434856)
(186, 3)
>>> isPP(9**2)
(9, 2)
>>> isPP(23**8)
(279841, 2)
>>> isPP(279841)
(529, 2)
>>> isPP(529)
(23, 2)
>>>
EDIT
or as Tin Peters point out you can use pow(x,1./n) as the nth root of a number is also expressed as x1/n
for example
>>> pow(170**3, 1./3)
169.99999999999994
>>> round(_)
170
>>>
but keep in mind that that will fail for extremely large numbers like for example
>>> pow(8191**107,1./107)
Traceback (most recent call last):
File "<pyshell#90>", line 1, in <module>
pow(8191**107,1./107)
OverflowError: int too large to convert to float
>>>
while the logarithmic approach will success
>>> pow(10, math.log10(8191**107)/107)
8190.999999999999
>>>
the reason is that 8191107 is simple too big, it have 419 digits which is greater that the maximum float representable, but reducing it with a log produce a more reasonable number
EDIT 2
now if you want to work with numbers ridiculously big, or just plain don't want to use floating point arithmetic altogether and use only integer arithmetic, then the best course of action is to use the method of Newton, that the helpful link provided by Tin Peters for the particular case for cube root, show us the way to do it in general alongside the wikipedia article
def inthroot(A,n):
if A<0:
if n%2 == 0:
raise ValueError
return - inthroot(-A,n)
if A==0:
return 0
n1 = n-1
if A.bit_length() < 1024: # float(n) safe from overflow
xk = int( round( pow(A,1/n) ) )
xk = ( n1*xk + A//pow(xk,n1) )//n # Ensure xk >= floor(nthroot(A)).
else:
xk = 1 << -(-A.bit_length()//n) # power of 2 closer but greater than the nth root of A
while True:
sig = A // pow(xk,n1)
if xk <= sig:
return xk
xk = ( n1*xk + sig )//n
check the explanation by Mark Dickinson to understand the working of the algorithm for the case of cube root, which is basically the same for this
now lets compare this with the other one
>>> def nthroot(x,n):
return pow(10, math.log10(x)/n )
>>> n = 2**(2**12) + 1 # a ridiculously big number
>>> r = nthroot(n**2,2)
Traceback (most recent call last):
File "<pyshell#48>", line 1, in <module>
nthroot(n**2,2)
File "<pyshell#47>", line 2, in nthroot
return pow(10, math.log10(x)/n )
OverflowError: (34, 'Result too large')
>>> r = inthroot(n**2,2)
>>> r == n
True
>>>
then the function is now
import math
def isPPv2(x):
for n in range(2,1+round(math.log2(x))):
root = inthroot(x,n)
if root**n == x:
return root,n
test
>>> n = 2**(2**12) + 1 # a ridiculously big number
>>> r,p = isPPv2(n**23)
>>> p
23
>>> r == n
True
>>> isPPv2(170**3)
(170, 3)
>>> isPPv2(8191**107)
(8191, 107)
>>> isPPv2(6434856)
(186, 3)
>>>
now lets check isPP vs isPPv2
>>> x = (1 << 53) + 1
>>> x
9007199254740993
>>> isPP(x**2)
>>> isPPv2(x**2)
(9007199254740993, 2)
>>>
clearly, avoiding floating point is the best choice
I've been having trouble trying to round my answer for a problem where I find the area of a regular polygon and then square the perimeter. My final answer should be the area plus the perimeter(squared), rounded to 4 decimal places. My math seems to be correct, however, no matter what numbers I use for inputs, there are only zeros after the decimal. I have included a screen shot of my code and incorrect message from the checker that I use.
import math
def polysum(n, s):
a = ((0.25 * n * s ** 2) / (math.tan(math.pi / 2)))
p = ((n * s) ** 2)
total = a + p
return '%.4f' % round(total)
print polysum(8, 8)
Of course you're only getting zeroes after the decimal point, because you are using the round() function to chop off all digits after the decimal point. If that's not what you want, don't do it. Just do:
return "%.4f" % total
Or possibly:
return round(total, 4)
There are two issues:
Change return '%.4f' % round(total) to return round(total,4) or else you are returning a str round to the nearest integer. It looks like the expected output is a float.
The factor of math.tan(math.pi / 2) is incorrect. This should evaluate to infinity (if not for floating point approximations) and is clearly not what you want. It should be math.tan(math.pi / 2 / n).
import math
def polysum(n, s):
a = (0.25 * n * s ** 2) / (math.tan(math.pi / n))
p = ((n * s) ** 2)
total = a + p
ans = round(total, 4)
return ans
print polysum(8,8)
print polysum(4, 89)
from math import *
def polysum(n, s):
lst = [(0.25 * n * s **2) / tan(pi / n), ((n * s) ** 2)]
return round(sum(lst), 4)
I have tried both the test cases. The output is matching.
The R ppoints function is described as:
Ordinates for Probability Plotting
Description:
Generates the sequence of probability points ‘(1:m - a)/(m +
(1-a)-a)’ where ‘m’ is either ‘n’, if ‘length(n)==1’, or
‘length(n)’.
Usage:
ppoints(n, a = ifelse(n <= 10, 3/8, 1/2))
...
I've been trying to replicate this function in python and I have a couple of doubts.
1- The first m in (1:m - a)/(m + (1-a)-a) is always an integer: int(n) (ie: the integer of n) if length(n)==1 and length(n) otherwise.
2- The second m in the same equation is NOT an integer if length(n)==1 (it assumes the real value of n) and it IS an integer (length(n)) otherwise.
3- The n in a = ifelse(n <= 10, 3/8, 1/2) is the real number n if length(n)==1 and the integer length(n) otherwise.
This points are not made clear at all in the description and I'd very much appreciate if someone could confirm that this is the case.
Add
Well this was initially posted at https://stats.stackexchange.com/ because I was hoping to get the input of staticians who work with the ppoints function. Since it has been migrated here, I'll paste below the function I wrote to replicate ppoints in python. I've tested it and both seem to give back the same results, but I'd be great if someone could clarify the points made above because they are not made at all clear by the function's description.
def ppoints(vector):
'''
Mimics R's function 'ppoints'.
'''
m_range = int(vector[0]) if len(vector)==1 else len(vector)
n = vector[0] if len(vector)==1 else len(vector)
a = 3./8. if n <= 10 else 1./2
m_value = n if len(vector)==1 else m_range
pp_list = [((m+1)-a)/(m_value+(1-a)-a) for m in range(m_range)]
return pp_list
I would implement this with numpy:
import numpy as np
def ppoints(n, a):
""" numpy analogue or `R`'s `ppoints` function
see details at http://stat.ethz.ch/R-manual/R-patched/library/stats/html/ppoints.html
:param n: array type or number"""
try:
n = np.float(len(n))
except TypeError:
n = np.float(n)
return (np.arange(n) + 1 - a)/(n + 1 - 2*a)
Sample output:
>>> ppoints(5, 1./2)
array([ 0.1, 0.3, 0.5, 0.7, 0.9])
>>> ppoints(5, 1./4)
array([ 0.13636364, 0.31818182, 0.5 , 0.68181818, 0.86363636])
>>> n = 10
>>> a = 3./8. if n <= 10 else 1./2
>>> ppoints(n, a)
array([ 0.06097561, 0.15853659, 0.25609756, 0.35365854, 0.45121951,
0.54878049, 0.64634146, 0.74390244, 0.84146341, 0.93902439])
One can use R fiddle to test implementation.