How to take reciprocal of a float in python - python

I'm having some trouble in my pygame application that I'm making. There are buttons in the menu that change how fast my simulation runs (by changing speed in clock.tick(speed*10)). This, however, also slows down the rate that the menu buttons respond. If I ingame set speed anywhere lower than 0.5 the speed and play/pause buttons take up to five seconds to register a click. So I tried creating my own way to work around this:
speed = 1 # defined previously ingame
timeSlow = 0
timeSlowGoal = 0
while True: # game loop
if speed < 1:
timeSlowGoal = reciprocal(speed) # well here's my problem
else:
timeSlowGoal = -1
if timeSlowGoal != -1:
if timeSlow >= timeSlowGoal:
timeSlow = 0
# more code that actually does stuff
else:
timeSlow += 1
# doesn't match, try again
In python, there are tricks like int(),string(), and float() to change a variable. Of course, reciprocal() doesn't work. Is there some sort of function like these that gets the reciprocal of a number, (which in this case is always a decimal) or do I need to just do some fancy math to get it?
(of course if all of this is unnecessary and you have a better solution to my first problem let me know)
EDIT: Okay, there is a very simple solution to this that I overlooked. 1/n is always the reciprocal of n. There's no need for a reciprocal() function because it's so simple. That's what I get for forgetting elementary school math.

Assuming you are using Python 3, change
timeSlowGoal = reciprocal(speed)
to
timeSlowGoal = 1 / speed
Just make sure that you don't try to do that if speed is zero.

I do not know why you are having such a huge piece of code, because Reciprocal of a number can be simply mentioned as: 1/n
So, your reciprocal function can be simply written as:
def reciprocal(n):
return 1.0 / n
Here, I am using 1.0/n instead 1/n as in python for the resultant of division to be fraction, either numerator or denominator should have fraction value.
Sample run:
>>> reciprocal(3)
0.3333333333333333
>>> reciprocal(0.3333333)
3.00000030000003 # Not '3' because of the loss in the precision of value entered
>>> reciprocal(reciprocal(3))
3.0 # Doing reciprocal twice returns "3"

Related

Optimization of a simple Python script to calculate the first sophomore's dream number

I am currently working on a program to calculate 100,000 digits of the first sophomore's dream constant, I1. It's given by the sum below.
After about 10,000 terms in this series it gets quite slow. I opted to write the program so small because I wanted to see how small I could make it
from decimal import *
def sophodream(a):
s,i,t=0,1,int(a*1.5)
while i<t:
print(i)
n,d=Decimal(pow(-1,i+1)),Decimal(i**i)
f=n/d
s+=f
i+=1
return s
I would like to know if there are any ways to speed this up aside from multithreading/multiprocessing. I find that when I do series like these in threaded pieces the accuracy of them gets lower.
There are some minor changes / simplifications that can be made to your code but as has already been noted, you're working (at times) with some very big numbers.
from decimal import getcontext, Decimal
def sophodream(a):
s, p = 0, 1
getcontext().prec = a
for i in range(1, int(a * 1.5)):
s += p / Decimal(i**i)
p = -p
return s
print(sophodream(100))
Output:
0.7834305107121344070592643865269754694076819901469309582554178227016001845891404456248642049722689389
Obviously just a very short version to prove functionality

Been using rand.int for a while and seeing unexpected results

I've been running some code for an hour or so using a rand.int function, where the code models a dice's roll, where the dice has ten faces, and you have to roll it six times in a row, and each time it has to roll the same number, and it is tracking how many tries it takes for this to happen.
success = 0
times = 0
count = 0
total = 0
for h in range(0,100):
for i in range(0,10):
times = 0
while success == 0:
numbers = [0,0,0,0,0,0,0,0,0,0]
for j in range(0,6):
x = int(random.randint(0,9))
numbers[x] = 1
count = numbers.count(1)
if count == 1:
success = 1
else:
times += 1
print(i)
total += times
success = 0
randtst = open("RandomTesting.txt", "a" )
randtst.write(str(total / 10)+"\n")
randtst.close()
And running this code, this has been going into a file, the contents of which is below
https://pastebin.com/7kRK1Z5f
And taking the average of these numbers using
newtotal = 0
totalamounts = 0
with open ('RandomTesting.txt', 'rt') as rndtxt:
for myline in rndtxt: ,
newtotal += float(myline)
totalamounts += 1
print(newtotal / totalamounts)
Which returns 742073.7449342106. This number is incorrect, (I think) as this is not near to 10^6. I tried getting rid of the contents and doing it again, but to no avail, the number is nowhere near 10^6. Can anyone see a problem with this?
Note: I am not asking for fixes to the code or anything, I am asking whether something has gone wrong to get the above number rather that 100,000
There are several issues working against you here. Bottom line up front:
your code doesn't do what you described as your intent;
you currently have no yardstick for measuring whether your results agree with the theoretical answer; and
your expectations regarding the correct answer are incorrect.
I felt that your code was overly complex for the task you were describing, so I wrote my own version from scratch. I factored out the basic experiment of rolling six 10-sided dice and checking to see if the outcomes were all equal by creating a list of length 6 comprised of 10-sided die rolls. Borrowing shamelessly from BoarGules' comment, I threw the results into a set—which only stores unique elements—and counted the size of the set. The dice are all the same value if and only if the size of the set is 1. I kept repeating this while the number of distinct elements was greater than 1, maintaining a tally of how many trials that required, and returned the number of trials once identical die rolls were obtained.
That basic experiment is then run for any desired number of replications, with the results placed in a numpy array. The resulting data was processed by numpy and scipy to yield the average number of trials and a 95% confidence interval for the mean. The confidence interval uses the estimated variability of the results to construct a lower and an upper bound for the mean. The bounds produced this way should contain the true mean for 95% of estimates generated in this way if the underlying assumptions are met, and address the second point in my BLUF.
Here's the code:
import random
import scipy.stats as st
import numpy as np
NUM_DIGITS = 6
SAMPLE_SIZE = 1000
def expt():
num_trials = 1
while(len(set([random.randrange(10) for _ in range(NUM_DIGITS)])) > 1):
num_trials += 1
return num_trials
data = np.array([expt() for _ in range(SAMPLE_SIZE)])
mu_hat = np.mean(data)
ci = st.t.interval(alpha=0.95, df=SAMPLE_SIZE-1, loc=mu_hat, scale=st.sem(data))
print(mu_hat, ci)
The probability of producing 6 identical results of a particular value from a 10-sided die is 10-6, but there are 10 possible particular values so the overall probability of producing all duplicates is 10*10-6, or 10-5. Consequently, the expected number of trials until you obtain a set of duplicates is 105. The code above took a little over 5 minutes to run on my computer, and produced 102493.559 (96461.16185897154, 108525.95614102845) as the output. Rounding to integers, this means that the average number of trials was 102493 and we're 95% confident that the true mean lies somewhere between 96461 and 108526. This particular range contains 105, i.e., it is consistent with the expected value. Rerunning the program will yield different numbers, but 95% of such runs should also contain the expected value, and the handful that don't should still be close.
Might I suggest if you're working with whole integers that you should be receiving a whole number back instead of a floating point(if I'm understanding what you're trying to do.).
##randtst.write(str(total / 10)+"\n") Original
##randtst.write(str(total // 10)+"\n")
Using a floor division instead of a division sign will round down the number to a whole number which is more idea for what you're trying to do.
If you ARE using floating point numbers, perhaps using the % instead. This will not only divide your number, but also ONLY returns the remainder.
% is Modulo in python
// is floor division in python
Those signs will keep your numbers stable and easier to work if your total returns a floating point integer.
If this isn't the case, you will have to account for every number behind the decimal to the right of it.
And if this IS the case, your result will never reach 10x^6 because the line for totalling your value is stuck in a loop.
I hope this helps you in anyway and if not, please let me know as I'm also learning python.

Am I doing something wrong trying to #jit this Python function

I've got this Python function which I'm trying to #jit, but I can't really get around it (it's the first time I try jitting something, so I'm here to learn more than anything). I'll include the code (commented) and I'll explain what it does briefly:
def pwrchk(n, m):
no_prob = [] #The list that will contain the exponents
for i in range(2, m+1): #Start from 2 because 1 is useless
power = n**i
is_good = True #If this becomes false later, there's a zero.
for j in range(math.floor(math.log(power, 10)) + 1):
#The formula in the range is the number of digits of 'power'
digit = power % 10 #Returns the last digit so it can be checked
if digit in digits:
is_good = False #This is the check
power = 0
break
power = power // 10 #Gets rid of the digit just checked
if is_good:
no_prob.append(i) #Append to the list of "good" exponents
return no_prob
This function computes n^i , with 2 < i < m, and checks if n^i contains a zero in its digits, and then returns a list of which exponents are such that n^i contains no zeros. It works absolutely fine in normal Python compilation.
Since for big values of m the execution time gets really long (I've tried m = 10^6 and it goes to a crawl), I thought of putting it in Anaconda to #jit it. The problem is that when I use the #jit decorator it tells me that it keeps falling back to object mode, so I can't compile it in nopython mode.
I tried changing the lists to numpy arrays and populating them with the powers of n out of the for cycle, changing math.floor(math.log(power, 10)) using numpy to manage the arrays, nothing.
Am I doing something wrong? I'm sure there's a simple explanation to it that's just going over my head, but as said before I'm kinda new to Numba, so if I'm doing something really dumb please tell me, so I won't do it again in the future, and if I need to provide something else I'll update with anything needed.

Unexpected behavior with the IF function in Blender Game Engine

I am working on a project in BGE and I want to make an object slowly accelerate to its max speed when I press the button. When I press another button it should decelerate and then again slowly accelerate to the top speed in the other direction.
Here is the code:
import bge
cont = bge.logic.getCurrentController()
own = cont.owner
keyboard = bge.logic.keyboard
ACTIVE = bge.logic.KX_INPUT_ACTIVE
INACTIVE = bge.logic.KX_INPUT_NONE
accelerate = own['accelerateProp']
accelerateFactor = 0.005
own.applyMovement((0, accelerate, 0))
if(keyboard.events[bge.events.WKEY] == ACTIVE and accelerate > -0.05):
own['accelerateProp'] -= accelerateFactor
if(keyboard.events[bge.events.SKEY] == ACTIVE and accelerate < 0.05):
own['accelerateProp'] += accelerateFac
I have an object with the accelerateProp property which I'm using to controll the speed of the object.
When I hold W key it accelerates. But instead of stopping at -0.05, it runs one more time and it stops at -0.055. If I then hold S button, it deccelerates and then again accelerates and stops at 0.05.
The confusing thing is that if I hold S key first, it Will accelerate to 0.055, and it will work fine the other way around.
So actuali, the direction, which will reach the top speed firs will be broken and the other will be fine and it will stay that way, so one side will always have max speed 0.055 and the other 0.05.
I can't understand what's wrong. I suspect it has to do something wit game properties, but I realy don't Know. Also if there's another way of doing what I did, please let me know.
Thanks!
It's hard to be sure without more information, but I'm almost certain this is just a typical floating-point rounding error.
Consider this code (which is effectively doing the same thing as your code, but without all the user interaction stuff in the middle):
x = 0
while x < 0.05:
x += 0.005
print(x)
You'd think the result would be 0.05, right? But it's not. It's 0.05499999999999999. Why did it go one step too far?
If you print out all the values along the way, the reason is obvious:
0.005
0.01
0.015
0.02
0.025
0.030000000000000002
0.035
0.04
0.045
0.049999999999999996
0.05499999999999999
There is no floating-point double exactly equal to all of these numbers, so you accumulate rounding error. When you get to the 10th one, it's not 0.05, it's 0.049999999999999996, which is still less than 0.05, so it goes one more step.
There are two solutions to problems like this.
First, you can use Decimal instead of float. Of course Decimal is just as inexact and subject to rounding errors as float in general; the difference is that any number that has an exact decimal string representation (like 0.005 and all of your other values) also has an exact Decimal representation. So:
from decimal import Decimal
x = Decimal('0')
while x < Decimal('0.05'):
x += Decimal('0.005')
print(x)
And now you get 0.05 instead of 0.05499999999999999.
Alternatively, you can use absolute or relative epsilon comparisons. For example:
eps = 1e-5
while x + eps < 0.05:
x += 0.005
print(x)
Now you get 0.049999999999999996 instead of 0.05499999999999999 at the end.
The reason for the problems are rounding-errors with floating-points. Unfortunately, for floating-points addition and multiplication introduce small errors that can lead to problems with comparisons.
Instead, you should use "clamping", which means you prevent over/undershooting by comparing with a threshold, and then setting the value to the threshold itself:
acceleration = -0.05 if braking else 0.05
speed = max(0, min(max_speed, speed + acceleration))
Thus speed will never exceed the boundaries of [0..max_speed]
round off your property. prop = round(prop["value"], 2)
The 2 is the round point.

why is my if statement showing to be false? code not not quitting when a==0. the time is supposed to be in min/sec

i am having trouble figuring out why my timer is not reaching zero when i run it. I am trying to get the window to close when a=0 but a keeping decreasing to negative digits why please? This is my codes
def close_timer(self):
global a
a = float(a - 0.1)
self.labeltext.set(str(("%.1f" % (a))))
a = float(a)
print a
print (a == 0)
if a == 0:
self.canvas.after(100)
self.root.destroy()
self.root.after(100,self.close_timer)
Floating point number math is generally inaccurate - you can't represent a decimal 0.1 in binary floating points exactly, therefore you'll never reach 0:
>>> a = 1
>>> while a > 0:
... a = a - 0.1
... print(repr(a))
...
0.9
0.8
0.7000000000000001
0.6000000000000001
0.5000000000000001
0.40000000000000013
0.30000000000000016
0.20000000000000015
0.10000000000000014
1.3877787807814457e-16
-0.09999999999999987
Use if abs(a) < 0.000001: or something similar.
It's always dangerous to compare floats with fixed values unless you know and mitigate the consequences.
Most likely, your value is getting down to something like:
0.099999923354
as imprecision is gradually injected into your value every time you subtract 0.1 (which is not directly representable in IEEE754).
Then, when you subtract the final 0.1, you get something like:
-0.00000005345
which is not equal to zero.
Quickest fix is to probably change your zero check to be:
if a <= 0:
so that small errors are irrelevant, other than possibly taking an extra cycle (probably a tenth of a second) if it reaches 0.0000001 where it should be zero, for example.
If you want to ensure you don't take that extra cycle and you're confident that the gradually introduced error won't be too large, just change it to:
if a <= 0.0003:
or something similar.

Categories

Resources