Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
math.log?
#1
Hi,
I'm trying to put all answers of equations that I calculated into a list, and I want to refer to this list multiple times because the same equations repeat over and over again, is the function math.log the thing I want to use to make the code short?
Reply
#2
Please show your code (or runnable snippet) so we can suggest how to shorten.
I'm guessing that you might be able to save in sqlite database (built into python, easy to use)
Reply
#3
It isn't clear to me what logarithms have to do with your problem. Please show code and explain.
Reply
#4
Nope.
Output:
>>> import math >>> help(math.log) Help on built-in function log in module math: log(...) log(x, [base=math.e]) Return the logarithm of x to the given base. If the base not specified, returns the natural logarithm (base e) of x.
I need more information about what you are trying to do to have a chance at answering your question. Could you provide some code and a description please?
Reply
#5
So for example i have an empty list (data), and I have a different list with some numbers(list_), I want to make math operations on them, there can be numbers that repeat in the list, so some operation have to be calculated multiple times, so instead of calculating multiple times, it can reach out to the list(data) that already has answers to operations calculated before.
For example:
data=[]
list_=[4,6,1,2,47,4,2,6,4]
for i in range(len(list_-1):
    data.append(list_[i]+list_[i+1]

As you can see, some operations repeat multiple times, such as the first one(4+6), and the last one,(6+4). So instead of counting i again, you can go to the data list and get the value from the list, to make the code faster. Does anyone have a hint on how to do that and, is the function math.log even necessary in this program?
Thanks
Reply
#6
I don't see how logs are relevant at all. Where did you get the idea that they were?

Can't you use a set, so you only keep the unique values?
Reply
#7
Doesn't seem worth it for an inexpensive call like integer addition. But if you have expensive operations you could cache them with functools.cache (or functools.lru_cache if you don't have 3.9...)

import functools

def expensive_function(n):
    print(f"  Debug.  Calling expensive_function with argument {n}")
    return n / 0.2385

@functools.lru_cache
def cached_function(n):
    return expensive_function(n)


# Call directly
for i in range(3):
    print(expensive_function(4))
print()


# Call through the cache
for i in range(3):
    print(cached_function(5))
Output:
Debug. Calling expensive_function with argument 4 16.771488469601678 Debug. Calling expensive_function with argument 4 16.771488469601678 Debug. Calling expensive_function with argument 4 16.771488469601678 Debug. Calling expensive_function with argument 5 20.964360587002098 20.964360587002098 20.964360587002098
After the function is called with a particular argument, this value is returned from the cache on future calls with the same arguments. Don't use this if the output can change when the arguments don't (like a function that depends on a random number, or one that looks up data from a database...)
Reply
#8
Here's an example of saving previous values for calculating prime numbers.
primes = [2, 3]

def prime(i):
    """Return i'th prime number"""
    def notPrime(value):
        """Return True if value is not prime"""
        sqrt = value**0.5
        for p in primes:
            if value % p == 0:
                return True
            if p > sqrt:
                return False

    # Calculate new prime numbers to fill primes to requested size"""
    count = 0
    while len(primes) <= i:
        value = primes[-1] + 2
        while notPrime(value):
            value += 2
        count += 1
        primes.append(value)
        
    if count > 0:
        print(f'Calculated {count} new primes')

    return primes[i]

print(prime(1))
print(prime(5))
print(prime(7))
print(prime(10))
print(prime(6))
print(primes)
Output:
3 Calculated 4 new primes 13 Calculated 2 new primes 19 Calculated 3 new primes 31 17 [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31]
For this example a list works because the index is adequate for looking up the previously calculated value. You could also use something like this to get numbers from the Fibonacci sequence.
fibonacci = [1, 1]

def fib(i):
    """Return i'th Fibonacci number"""
    count = 0
    while len(fibonacci) <= i:
        fibonacci.append(fibonacci[-1] + fibonacci[-2])
        count += 1
        
    if count > 0:
        print(f'Calculated {count} new values')

    return fibonacci[i]

print(fib(1))
print(fib(5))
print(fib(7))
print(fib(10))
print(fib(6))
print(fibonacci)
Output:
1 Calculated 4 new values 8 Calculated 2 new values 21 Calculated 3 new values 89 13 [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
Your problem is a bit trickier. An index will not work as a "key" to retrieve previously calculated values. You will probably use a dictionary. With a dictionary you'll need a key.
results = {}

def addum(x):
    key = str(set(x))
    result = results.get(key)
    if result:
        print(f'Reuse {x[0]}, {x[1]}')
    else:
        result = sum(x)
        results[key] = result
    return result
        
numbers = [4, 6, 1, 2, 7, 4, 2, 6, 4, 6, 2, 1]
print([addum(x) for x in zip(numbers[:-1], numbers[1:])])
Output:
Reuse 6, 4 Reuse 4, 6 Reuse 6, 2 Reuse 2, 1 [10, 7, 3, 9, 11, 6, 8, 10, 10, 8, 3]
Doing something like this you have to weigh the effort of calculating the value against the effort of generating keys and managing the dictionary.

This is a more substantial problem that reuses previous results many times.
import random

## Save partial solutions to speed things up.
solutions = {}

def sticks(bag, count):
    '''Split bag into count groups.  Find the grouping that results
    in the highest minimum group score.  Group score is the sum of
    numbers in the group.
    '''
    ## Reuse partial solution when possible
    if score := solutions.get((len(bag), count)):
        return score

    if count == 1:
        score = (sum(bag), [bag])
        solutions[(len(bag), count)] = score
        return score

    best_score = 0
    for i in range(1, len(bag)-count+1):
        if count > 1:
            score, groups = sticks(bag[i:], count-1)
            groups = [bag[:i]] + groups
            score = min(score, sum(bag[:i]))

        if score > best_score:
            best_score = score
            best = groups

    # Comment out following line to see how much time it saves
    solutions[(len(bag), count)] = (best_score, best)
    return (best_score, best)

bag = list(range(1, 51))
random.shuffle(bag)
print(sticks(bag, 7))
Reply
#9
functools.cache is not going to know that expensive_function(6, 4) is the same as expensive_function(4, 6). But if this is an expensive function the order of the arguments is probably important.

Care must be taken if your cached function returns a mutable result. Just last week somebody was using functools to speed up their code and it led to unexpected results because a cached list was returned instead of generating a new list each time.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  math.log versus math.log10 stevendaprano 10 2,301 May-23-2022, 08:59 PM
Last Post: jefsummers
  Why getting ValueError : Math domain error in trig. function, math.asin() ? jahuja73 3 3,703 Feb-24-2021, 05:09 PM
Last Post: bowlofred

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020