Get logarithm without math log python - python

I need to generate the result of the log.
I know that:
Then I made my code:
def log(x, base):
log_b = 2
while x != int(round(base ** log_b)):
log_b += 0.01
print(log_b)
return int(round(log_b))
But it works very slowly. Can I use other method?

One other thing you might want to consider is using the Taylor series of the natural logarithm:
Once you've approximated the natural log using a number of terms from this series, it is easy to change base:
EDIT: Here's another useful identity:
Using this, we could write something along the lines of
def ln(x):
n = 1000.0
return n * ((x ** (1/n)) - 1)
Testing it out, we have:
print ln(math.e), math.log(math.e)
print ln(0.5), math.log(0.5)
print ln(100.0), math.log(100.0)
Output:
1.00050016671 1.0
-0.692907009547 -0.69314718056
4.6157902784 4.60517018599
This shows our value compared to the math.log value (separated by a space) and, as you can see, we're pretty accurate. You'll probably start to lose some accuracy as you get very large (e.g. ln(10000) will be about 0.4 greater than it should), but you can always increase n if you need to.

I used recursion:
def myLog(x, b):
if x < b:
return 0
return 1 + myLog(x/b, b)

You can use binary search for that.
You can get more information on binary search on Wikipedia:
Binary search;
Doubling search.
# search for log_base(x) in range [mn, mx] using binary search
def log_in_range(x, base, mn, mx):
if (mn <= mx):
med = (mn + mx) / 2.0
y = base ** med
if abs(y - x) < 0.00001: # or if math.isclose(x, y): https://docs.python.org/3/library/math.html#math.isclose
return med
elif x > y:
return log_in_range(x, base, med, mx)
elif x < y:
return log_in_range(x, base, mn, med)
return 0
# determine range using doubling search, then call log_in_range
def log(x, base):
if base <= 0 or base == 1 or x <= 0:
raise ValueError('math domain error')
elif 0 < base < 1:
return -log(x, 1/base)
elif 1 <= x and 1 < base:
mx = 1
y = base
while y < x:
y *= y
mx *= 2
return log_in_range(x, base, 0, mx)
elif 0 <= x < 1 and 1 < base:
mn = -1
y = 1/base
while y > x:
y = y ** 0.5
mn *= 2
return log_in_range(x, base, mn, 0)

import math
try :
number_and_base = input() ##input the values for number and base
##assigning those values for the variables
number = int(number_and_base.split()[0])
base = int(number_and_base.split()[1])
##exception handling
except ValueError :
print ("Invalid input...!")
##program
else:
n1 = 1 ##taking an initial value to iterate
while(number >= int(round(base**(n1),0))) : ##finding the most similer value to the number given, varying the vlaue of the power
n1 += 0.000001 ##increasing the initial value bit by bit
n2 = n1-0.0001
if abs(number-base**(n2)) < abs(base**(n1)-number) :
n = n2
else :
n = n1
print(math.floor(n)) ##output value

Comparison:-
This is how your log works:-
def your_log(x, base):
log_b = 2
while x != int(round(base ** log_b)):
log_b += 0.01
#print log_b
return int(round(log_b))
print your_log(16, 2)
# %timeit %run your_log.py
# 1000 loops, best of 3: 579 us per loop
This is my proposed improvement:-
def my_log(x, base):
count = -1
while x > 0:
x /= base
count += 1
if x == 0:
return count
print my_log(16, 2)
# %timeit %run my_log.py
# 1000 loops, best of 3: 321 us per loop
which is faster, using the %timeit magic function in iPython to time the execution for comparison.

It will be long process since it goes in a loop. Therefore,
def log(x,base):
result = ln(x)/ln(base)
return result
def ln(x):
val = x
return 99999999*(x**(1/99999999)-1)
log(8,3)
Values are nearly equal but not exact.

Related

A Normal Distribution Calculator

so im trying to make a program to solve various normal distribution questions with pure python (no modules other than math) to 4 decimal places only for A Levels, and there is this problem that occurs in the function get_z_less_than_a_equal(0.75):. Apparently, without the assert statement in the except clause, the variables all get messed up, and change. The error, i'm catching is the recursion error. Anyways, if there is an easier and more efficient way to do things, it'd be appreciated.
import math
mean = 0
standard_dev = 1
percentage_points = {0.5000: 0.0000, 0.4000: 0.2533, 0.3000: 0.5244, 0.2000: 0.8416, 0.1000: 1.2816, 0.0500: 1.6440, 0.0250: 1.9600, 0.0100: 2.3263, 0.0050: 2.5758, 0.0010: 3.0902, 0.0005: 3.2905}
def get_z_less_than(x):
"""
P(Z < x)
"""
return round(0.5 * (1 + math.erf((x - mean)/math.sqrt(2 * standard_dev**2))), 4)
def get_z_greater_than(x):
"""
P(Z > x)
"""
return round(1 - get_z_less_than(x), 4)
def get_z_in_range(lower_bound, upper_bound):
"""
P(lower_bound < Z < upper_bound)
"""
return round(get_z_less_than(upper_bound) - get_z_less_than(lower_bound), 4)
def get_z_less_than_a_equal(x):
"""
P(Z < a) = x
acquires a, given x
"""
# first trial: brute forcing
for i in range(401):
a = i/100
p = get_z_less_than(a)
if x == p:
return a
elif p > x:
break
# second trial: using symmetry
try:
res = -get_z_less_than_a_equal(1 - x)
except:
# third trial: using estimation
assert a, "error"
prev = get_z_less_than(a-0.01)
p = get_z_less_than(a)
if abs(x - prev) > abs(x - p):
res = a
else:
res = a - 0.01
return res
def get_z_greater_than_a_equal(x):
"""
P(Z > a) = x
"""
if x in percentage_points:
return percentage_points[x]
else:
return get_z_less_than_a_equal(1-x)
print(get_z_in_range(-1.20, 1.40))
print(get_z_less_than_a_equal(0.7517))
print(get_z_greater_than_a_equal(0.1000))
print(get_z_greater_than_a_equal(0.0322))
print(get_z_less_than_a_equal(0.1075))
print(get_z_less_than_a_equal(0.75))
Since python3.8, the statistics module in the standard library has a NormalDist class, so we could use that to implement our functions "with pure python" or at least for testing:
import math
from statistics import NormalDist
normal_dist = NormalDist(mu=0, sigma=1)
for i in range(-2000, 2000):
test_val = i / 1000
assert get_z_less_than(test_val) == round(normal_dist.cdf(test_val), 4)
Doesn't throw an error, so that part probably works fine
Your get_z_less_than_a_equal seems to be the equivalent of NormalDist.inv_cdf
There are very efficient ways to compute it accurately using the inverse of the error function (see Wikipedia and Python implementation), but we don't have that in the standard library
Since you only care about the first few digits and get_z_less_than is monotonic, we can use a simple bisection method to find our solution
Newton's method would be much faster, and not too hard to implement since we know that the derivative of the cdf is just the pdf, but still probably more complex than what we need
def get_z_less_than_a_equal(x):
"""
P(Z < a) = x
acquires a, given x
"""
if x <= 0.0 or x >= 1.0:
raise ValueError("x must be >0.0 and <1.0")
min_res, max_res = -10, 10
while max_res - min_res > 1e-7:
mid = (max_res + min_res) / 2
if get_z_less_than(mid) < x:
min_res = mid
else:
max_res = mid
return round((max_res + min_res) / 2, 4)
Let's test this:
for i in range(1, 2000):
test_val = i / 2000
left_val = get_z_less_than_a_equal(test_val)
right_val = round(normal_dist.inv_cdf(test_val), 4)
assert left_val == right_val, f"{left_val} != {right_val}"
# AssertionError: -3.3201 != -3.2905
We see that we are losing some precision, that's because the error introduced by get_z_less_than (which rounds to 4 digits) gets propagated and amplified when we use it to estimate its inverse (see Wikipedia - error propagation for details)
So let's add a "digits" parameter to get_z_less_than and change our functions slightly:
def get_z_less_than(x, digits=4):
"""
P(Z < x)
"""
res = 0.5 * (1 + math.erf((x - mean) / math.sqrt(2 * standard_dev ** 2)))
return round(res, digits)
def get_z_less_than_a_equal(x, digits=4):
"""
P(Z < a) = x
acquires a, given x
"""
if x <= 0.0 or x >= 1.0:
raise ValueError("x must be >0.0 and <1.0")
min_res, max_res = -10, 10
while max_res - min_res > 10 ** -(digits * 2):
mid = (max_res + min_res) / 2
if get_z_less_than(mid, digits * 2) < x:
min_res = mid
else:
max_res = mid
return round((max_res + min_res) / 2, digits)
And now we can try the same test again and see it passes

python, power function using one loop

I tried to solve a problem, writing a power by function that does the same job as the operator ** (by python for example)
after I solve it, I got another assignment:
I'm allowed to use only one loop and only one if\else.
I would love for some insight
I'm a beginer and have no clue how to go further.
my code was:
...
def power(x, y):
s = x
if y > 0:
for i in range (1, y):
s = s * x
elif (y < 0):
for i in range (y, -1):
s = s * x
s = 1 / s
else:
s = 1
return s
print(power(3, 5))
print(power(3, -5))
print(power(3, 0))
Are you allowed to use the abs function?
from typing import Union
def power(x: Union[float, int], y: int) -> Union[float, int]:
s: Union[float, int] = 1
for _ in range(abs(y)):
s *= x
if y < 0:
s = 1 / s
return s
assert power(3, 5) == 243
assert 0.0040 < power(3, -5) < 0.0042
assert power(3, 0) == 1
A way I would do it is creating a function that accepts a number and an exponent.
Then I would create a list with exp amount of that number. Multiply everything in the list together to get the result:
def power(num, exp):
prod = 1
powers = [num] * exp
for n in powers:
prod *= n
return prod

Python function returning first value twice

I've written this function to calculate sin(x) using Taylor series to any specified degree of accuracy, 'N terms', my problem is the results aren't being returned as expected and I can't figure out why, any help would be appreciated.
What is am expecting is:
1 6.28318530718
2 -35.0585169332
3 46.5467323429
4 -30.1591274102
5 11.8995665347
6 -3.19507604213
7 0.624876542716
8 -0.0932457590621
9 0.0109834031461
What I am getting is:
1 None
2 6.28318530718
3 -35.0585169332
4 46.5467323429
5 -30.1591274102
6 11.8995665347
7 -3.19507604213
8 0.624876542716
9 -0.0932457590621
Thanks in advance.
def factorial(x):
if x <= 1:
return 1
else:
return x * factorial(x-1)
def sinNterms(x, N):
x = float(x)
while N >1:
result = x
for i in range(2, N):
power = ((2 * i)-1)
sign = 1
if i % 2 == 0:
sign = -1
else:
sign = 1
result = result + (((x ** power)*sign) / factorial(power))
return result
pi = 3.141592653589793
for i in range(1,10):
print i, sinNterms(2*pi, i)
I see that you are putting the return under the for which will break it out of the while loop. You should explain if this is what you mean to do. However, given the for i in range(1,10): means that you will ignore the first entry and return None when the input argument i is 1. Is this really what you wanted? Also, since you always exit after the calculation, you should not do a while N > 1 but use if N > 1 to avoid infinite recursion.
The reason why your results are off is because you are using range incorrectly. range(2, N) gives you a list of numbers from 2 to N-1. Thus range(2, 2) gives you an empty list.
You should calculate the range(2, N+1)
def sinNterms(x, N):
x = float(x)
while N >1:
result = x
for i in range(2, N):
Your comment explains that you have the lines of code in the wrong order. You should have
def sinNterms(x, N):
x = float(x)
result = x
# replace the while with an if since you do not need a loop
# Otherwise you would get an infinite recursion
if N > 1:
for i in range(2, N+1):
power = ((2 * i)-1)
sign = 1
if i % 2 == 0:
sign = -1
# The else is not needed as this is the default
# else:
# sign = 1
# use += operator for the calculation
result += (((x ** power)*sign) / factorial(power))
# Now return the value with the indentation under the if N > 1
return result
Note that in order to handle things set factorial to return a float not an int.
An alternative method that saves some calculations is
def sinNterms(x, N):
x = float(x)
lim = 1e-12
result = 0
sign = 1
# This range gives the odd numbers, saves calculation.
for i in range(1, 2*(N+1), 2):
# use += operator for the calculation
temp = ((x ** i)*sign) / factorial(i)
if fabs(temp) < lim:
break
result += temp
sign *= -1
return result

python-How to reverse an negative integer or non-integer

I am learning python and I meet some troubles.
I want to write the script to reverse a negative integer " -1234 to 4321- " and non-integer " 1.234 to 432.1". please help me.
P.S. cannot use "str()" function
I just only can write the script to reverse positive integer 1234 to 4321
def reverse_int(n):
x = 0
while n > 0:
x *= 10
x += n % 10
n /= 10
return x
print reverse_int(1234)
def reve(x):
x=str(x)
if x[0]=='-':
a=x[::-1]
return f"{x[0]}{a[:-1]}"
else:
return x[::-1]
print(reve("abc"))
print(reve(123))
print(reve(-123))
#output
cba
321
-321
how about using your code, but just concatenate a - when n is negative?
rev_int.py:
def reverse_int(m):
x = 0
n = m
if m < 0 :
n *= -1
while n > 0 :
x *= 10
x += n % 10
n /= 10
if m < 0:
#concatenate a - sign at the end
return `x` + "-"
return x
print reverse_int(1234)
print reverse_int(-1234)
This produces:
$ python rev_int.py
4321
4321-
Using SLICING EASILY DONE IT
def uuu(num):
if num >= 0:
return int(str(num)[::-1])
else:
return int('-{val}'.format(val = str(num)[1:][::-1]))
Below code runs fine on Python-3 and handles positive and negative integer case. Below code takes STDIN and prints the output on STDOUT.
Note: below code handles only the integer case and doesn't handles the
non-integer case.
def reverseNumber(number):
x = 0
#Taking absolute of number for reversion logic
n = abs(number)
rev = 0
#Below logic is to reverse the integer
while(n > 0):
a = n % 10
rev = rev * 10 + a
n = n // 10
#Below case handles negative integer case
if(number < 0):
return (str(rev) + "-")
return (rev)
#Takes STDIN input from the user
number=int(input())
#Calls the reverseNumber function and prints the output to STDOUT
print(reverseNumber(number))
Using str convert method.
num = 123
print(str(num)[::-1])
Use this as a guide and make it work for floating point values as well:
import math
def reverse_int(n):
if abs(n) < 10:
v = chr(abs(n) + ord('0'))
if n < 0: v += '-'
return v
else:
x = abs(n) % 10
if n < 0: return chr(x + ord('0')) + reverse_int(math.ceil(n / 10))
else: return chr(x + ord('0')) + reverse_int(math.floor(n / 10))
print reverse_int(1234)
Why not just do the following?:
def reverse(num):
revNum = ''
for i in `num`:
revNum = i + revNum
return revNum
print reverse(1.12345)
print reverse(-12345)
These would print 54321.1 and 54321-.

How to return value for different layers of (x,y) levels

My problem is the following. I a functional requirement where the user can choose between 3 or 5 levels and a value will be returned according to which level (x,y) belong.
for example in 3 levels we have
def f(x,y):
if (0 <= x <= 0.3 and 0 <= y <= 1) or (0.3 <= x <= 1 and 0 <= y <= 0.3):
return 1
elif (0.3 < x <= 0.6 and 0.3 < y <= 1) or (0.6 <= x <= 1 and 0.3 < y <= 0.6):
return 2
else:
return 3
for 5 levels we would have 5 if branches and so on.
I was wondering which is the best way(or a good) to do that in Python with the DRY principle. My mind is short of short circuited right now.
So first, we can recognize that we can rewrite your program as:
def f(x, y):
if min(x, y) <= 0.3:
return 1
elif min(x, y) <= 0.6:
return 2
else:
return 3
We can then format this into a for loop fairly easily:
from __future__ import division
def f(x, y, n=3):
for i in range(1, n+1):
if min(x, y) <= i/n:
return i
else:
return n
We could also write a math equation for this and drop the for loop:
def f(x, y, n=3):
return int(min(x, y) * n) + 1
This last equation will fail when x == 1 or y == 1. You should probably just either make a special case for that, or also perform a max(result_so_far, n) as well.

Categories