Do an action when a time counter gets a new integer - python

I'm trying to store some values in a while with a variable counter t in a certain way that for example, t reaches 2, certain value gets stored, t reaches 3, value gets stored and so on until 20:
In this example t starts at 1, and dt=0.1. I want that when we reach t=2 do the action:
while t<t_final:
t += dt
tint = int(t)
for i in range(20):
if tint == int(i):
action
break
But I'm not sure if the break does what I want. Which is the best approach?

If i undesrstand correctly dt is a float (0.1 for example). If you want to add 0.1 every time but you want the action happen only when the number is a integer(AKA has no decimals) you will have a floating point problem. for example 0+0.1+0.1+0.1... will never give you 15, it will give you, 14.999999999999963.
You could say if the numbers after the decimal point have a value less than (and some confindence interval) assume is integer:
t= 0
t_final = 20
dt = 0.1
while t<t_final:
t += dt
tDecimals = t%1
if tDecimals < dt: # less than dt or less than 0.1
print(int(t))
#action
Or, i think this is a better option, use a flag and: if the value of t are greater than the value of last t by at least 1 do the action
t= 0
lastInteger = t-1
t_final = 20
dt = 0.1
while t<t_final:
t += dt
if lastInteger + 1 < t:
lastInteger = int(t)
print(int(t))
#action
And another option is use Decimals (are better than floats for a lot of operations)
import decimal
decimal.getcontext().prec = 9 # number of 0 after decimal points
# that decimal will use and save
t= decimal.Decimal('0')
t_final = 20
dt = decimal.Decimal('0.1')
while t<t_final:
t += dt
for i in range(20):
if t == i:
Action
break

Related

Convert float number into binary

import struct
def print_binary(number_string):
bin = ""
if "." in number_string:
number_string = float(number_string)
bin += bin(struct.unpack('!i',struct.pack('!f', number_string)))
else:
num = int(number_string)
bin += "{0:b}".format(num)
print(bin)
I'm having trouble with converting a number with a decimal in it to binary (my if statement)
test_values = "0 1234 -1234 12.4 0.6 -12.4 -0.6 -1234567890.123456789".split()
I get an error when it gets up to 12.4
I used recursion. But there can be a recursion limit on some value here.
Here is the method I used by hand.
Fractional Part = .6875 in base 10
.6875*2 equals 1.375 whole number is 1
.375*2 equals 0.75 whole number is 0
.75*2 equals 1.5 whole number is 1
.5*2 equals 1.0 whole number is 1
Hence .6875D = .1011 in base 2
However, think about the value 12.4. It will go forever!
.4*2 = .8
.8*2 = 1.6
.6*2 = .2
.2*2 = .4
... and so on
So we have to set a limit in our recursion calculation. I made it 10. Although this does not sound like a lot, see how accurate it is.
My input of 12.4 returns 1100.0110011001 which is equal to 12.3994140625
Pretty close, feel free to play with that number, take the ceiling of it, etc.
Here is the code:
def get_integer_part(pre_decimal_string):
# special case of negative 0 being a prefix "-0.6"
if pre_decimal_string == "-0":
return "-0"
else:
num = int(pre_decimal_string)
return "{0:b}".format(num)
def get_decimal_part(post_decimal_string, string_builder, recurse):
recurse += 1
post_decimal_value = float("." + post_decimal_string)
if post_decimal_value == 0 or recurse > 10:
return string_builder
else:
temp_mult_str = str(post_decimal_value * 2)
temp_mult_split = temp_mult_str.split(".")
string_builder += temp_mult_split[0]
return get_decimal_part(temp_mult_split[1], string_builder, recurse)
def print_binary(number_string):
# handle case of no preceding 0 ".3" or
if number_string[0] == ".":
number_string = "0" + number_string
# handle case of no preceding 0 and is negative
if number_string[0:2] == "-.":
number_string = "-0" + number_string[1:]
if "." in number_string:
str_split = number_string.split(".")
print(get_integer_part(str_split[0]) + "." + str(get_decimal_part(str_split[1], "", 0)))
else:
print(get_integer_part(number_string))
test_values = "0 1234 -1234 12.4 0.6 -12.4 -0.6 -1234567890.123456789".split()
print(test_values)
for each in test_values:
print_binary(each)
# special cases
print_binary("-.7")
print_binary(".67")
Here is the final output:
0
10011010010
-10011010010
1100.0110011001
0.1001100110
-1100.0110011001
-0.1001100110
-1001001100101100000001011010010.0001111110
-0.1011001100
0.1010101110
Although I would have done this differently, I kept your code and format as much as possible to make it easiest for you to learn.

Extract the n-th digit of a number in Sagemath

How is it possible to extract the n-th digit of a number in Sagemath? We have to compute the 13787th digit from pi + e in Sagemath. My approach was the following:
sage: xi = e + pi
....: var1 = xi.n(digits=13786+1)
....: var2 = xi.n(digits=13787+1)
....: var3 = ((var2-var1) * 10^13787).trunc()
....: var3
0
Which gave me 0 back, however it should be 9.
The digit is indeed 9. But the subsequent digits are also 9: this part of decimal expansion goes ...9999237... Rounding rolls these 9s to 0s, carrying 1 to a higher digit.
So you need some extra digits in order to avoid the digit you are interested in from being affected by rounding. How many depends on the number; we don't know in advance if there isn't a sequence of one billion of 9s starting from that position. Here I use 10 extra digits
xi = e + pi
n = 13787
offset = 1 + floor(log(xi, 10)) # the first significant figure is not always the first digit after decimal dot, so we account for that
extra = 10
digit = int(str(xi.n(digits = n + offset + extra))[-1 - extra])
This returns 9. I think extracting with str is more reliable than subtracting two nearly-equal numbers and hoping there won't be additional loss of precition there.
Of course, including a magic number like 10 isn't reliable. Here is a better version, which starts with 10 extra digits but then increases the number until we no longer have 00000000... as a result.
xi = e + pi
n = 13787
offset = 1 + floor(log(xi, 10))
extra = 10
while True:
digits = str(xi.n(digits = n + offset + extra))[-1 - extra:]
if digits == "0" * len(digits):
extra *= 2
else:
digit = int(digits[0])
break
print(digit)
This will loop forever if the digits keep coming as 0, and rightly so: without actually knowing what the number is we can never be sure if the ...0000000... we get is not really ...999999999942... rounded up.

Issue with converting seconds to hh:mm:ss with large numbers in Python

The input I get the user to enter is seconds. Most of the time I am able to convert my input to the hh:mm:ss format but when the numbers get a bit larger I seem to run into some issues. For example when I input 900, I get a result of 01:15:-100. I especially don't want negatives and only want two digests (no decimals either) per each number. Not sure if I have gone wrong on my math.
if sys.argv[1] == "raceTime":
n = int(sys.argv[2])
if n < 60:
s = format(number, '0>2.0f')
print("{}:{}:{}".format(00, 00, s))
else:
n = int (sys.argv[2])/60
m =n//1
h = min//10
s = (n - h - m)*100
second = format(s,'0>2.0f')
minute = format(m, '0>2.0f')
hour = format(h, '0>2.0f')
print("{}:{}:{}".format(hour, minute, second))
Use proper string formatting:
second = format(sec, '02.0f') # etc.
or just
print("{:02.0f}:{:02.0f}:{:02.0f}".format(hour, min, sec))
# f -> float, 02 -> 2 places before (0-padded), .0 -> 0 places after point

Convert fraction to string with repeating decimal places in brackets

I want to write a function in Python 3 that converts fractions given as numerator and denominator into their string representation as decimal number, but with repeating decimal places in brackets.
An example:
convert(1, 4) should output "0.25"
convert(1, 3) should output "0.(3)" instead of "0.3333333333"
convert(7, 11) should output "0.(63)" instead of "0.6363636364"
convert(29. 12) should output "2.41(6)" instead of "2.4166666667"
My current code is at the end of the question, but it fails if there are non-repeating and repeating decimal places. Here's an example run including the debug output (commented print calls):
----> 29 / 12
5
appended 4
2
appended 1
8
index 2 ['29', 2, 8] result ['2.', '4', '(', '1']
repeating 8
['2.', '4', '(', '1', ')']
What am I doing wrong here?
My code:
def convert(numerator, denominator):
#print("---->", numerator, "/", denominator)
result = [str(numerator//denominator) + "."]
subresults = [str(numerator)]
numerator %= denominator
while numerator != 0:
#print(numerator)
numerator *= 10
result_digit, numerator = divmod(numerator, denominator)
if numerator not in subresults:
subresults.append(numerator)
result.append(str(result_digit))
#print("appended", result_digit)
else:
result.insert(subresults.index(numerator), "(")
#print("index", subresults.index(numerator), subresults, "result", result)
result.append(")")
#print("repeating", numerator)
break
#print(result)
return "".join(result)
Your code just needed some minor changes (see the comments below):
def convert(numerator, denominator):
#print("---->", numerator, "/", denominator)
result = [str(numerator//denominator) + "."]
subresults = [numerator % denominator] ### changed ###
numerator %= denominator
while numerator != 0:
#print(numerator)
numerator *= 10
result_digit, numerator = divmod(numerator, denominator)
result.append(str(result_digit)) ### moved before if-statement
if numerator not in subresults:
subresults.append(numerator)
#print("appended", result_digit)
else:
result.insert(subresults.index(numerator) + 1, "(") ### added '+ 1'
#print("index", subresults.index(numerator), subresults, "result", result)
result.append(")")
#print("repeating", numerator)
break
#print(result)
return "".join(result)
I believe what is wrong is that you should only be checking if the number of decimal places previously seen is the number of the length of the cycle and it was seen just previous to this length.
I think the best way to do this would be to use some good ol' math.
Lets try and devise a way to find the decimal representation of fractions and how to know when there will be repeating decimals.
The best way to know if a fraction will terminate (or repeat) is to look at the factorization (hard problem) of the denominator.
There are many ways to find the factorization, but what we really want to know is, does this number have a prime factor other than 2 or 5. Why? Well a decimal expansion is just some number a / 10 * b. maybe 1/2 = .5 = 5/10. 1/20 = .05 = 5/100. etc.
So the factors of 10 are 2 and 5, so we want to find out if it has any other factors other than 2 and 5. Perfect, thats easy, just keep dividing by 2 until it is not divisible by 2 anymore, than do the same with 5. Or the other way around.
First we may want to find out if it is divisible by 2 or 5 before we start doing some serious work.
def div_by_a_or_b( a, b, number):
return not ( number % a ) or not ( number % b )
Then we divide out all the fives then all the twos and check if the number is 1
def powers_of_only_2_or_5(number):
numbers_to_check = [ 2, 5 ]
for n in numbers_to_check:
while not number % n: # while it is still divisible by n
number = number // n # divide it by n
return number == 1 # if it is 1 then it was only divisble by the numbers in numbers_to_check
I made this a bit more polymorphic so you can change this around if you want to change the base. (all you need is the factors of that base, for instance in base 14 you check 2 and 7 instead of 2 and 5)
Now all thats left to do is find out what we do in the case of non-terminating/repeating fractions.
Now this is super number theory filled, so i'll leave you with the algorithm and let you decide if you want to find out more on mathforum.org or wolfram alpha
Now that we can easily tell if a fraction will terminate and if not, what will be the length of its cycle of repeating digits. Now all thats left to do is find the cycle or how many digits it will start in.
In my search for an efficient algorithm, I found this post on https://softwareengineering.stackexchange.com/ which should be helpful.
some great insight - "When a rational number m/n with (m,n)=1 is expanded, the period begins after s terms and has length t, where s and t are the smallest numbers satisfying
10^s=10^(s+t) (mod n). "
So all we need to do is find s and t:
def length_of_cycle(denominator):
mods = {}
for i in range(denominator):
key = 10**i % denominator
if key in mods:
return [ mods[key], i ]
else:
mods[ key ] = i
Let's generate the numbers of the expansion
def expasionGenerator( numerator, denominator ):
while numerator:
yield numerator // denominator
numerator = ( numerator % denominator ) * 10
Now be careful about using this as it will create an infinite loop in a repeating expansion (as it should ).
Now I think we have all the tools in place to write our function:
def the_expansion( numerator, denominator ):
# will return a list of two elements, the first is the expansion
# the second is the repeating digits afterwards
# the first element's first
integer_part = [ numerator // denominator ]
numerator %= denominator
if div_by_a_or_b( 2, 5, denominator ) and powers_of_only_2_or_5( denominator ):
return [ integer_part, [ n for n in expasionGenerator( numerator, denominator ) ][1:], [0] ]
# if it is not, then it is repeating
from itertools import islice
length_of_cycle = cycleLength( denominator )
generator = expasionGenerator( numerator*10, denominator )
# multiply by 10 since we want to skip the parts before the decimal place
list_of_expansion = [ n for n in islice(generator, length_of_cycle[0]) ]
list_of_repeating = [ n for n in islice(generator, length_of_cycle[1]) ]
return [ integer_part, list_of_expansion, list_of_repeating ]
Now all thats left is to print it, that shouldn't be too bad. I am just going to build a function first that takes a list of numbers to a string:
def listOfNumbersToString(the_list):
string = ""
for n in the_list:
string += str(n)
return string
Then create the convert function:
def convert(numerator, denominator):
expansion = the_expansion(numerator,denominator)
expansion = [ listOfNumbersToString(ex) for ex in expansion ]
return expansion[0] + "." + expansion[1] + "(" + expansion[2] + ")"
interesting read on the topic at http://thestarman.pcministry.com/ and a similar-ish question on stackoverflow
This doesn't answer your actual question ("why isn't my code working?") but maybe it will be useful to you anyway. A few months ago I wrote some code to do the same thing you're trying to do now. Here it is.
import itertools
#finds the first number in the sequence (9, 99, 999, 9999, ...) that is divisible by x.
def first_divisible_repunit(x):
assert x%2 != 0 and x%5 != 0
for i in itertools.count(1):
repunit = int("9"*i)
if repunit % x == 0:
return repunit
#return information about the decimal representation of a rational number.
def form(numerator, denominator):
shift = 0
for x in (10,2,5):
while denominator % x == 0:
denominator //= x
numerator *= (10//x)
shift += 1
base = numerator // denominator
numerator = numerator % denominator
repunit = first_divisible_repunit(denominator)
repeat_part = numerator * (repunit // denominator)
repeat_size = len(str(repunit))
decimal_part = base % (10**shift)
integer_part = base // (10**shift)
return integer_part, decimal_part, shift, repeat_part, repeat_size
def printable_form(n,d):
integer_part, decimal_part, shift, repeat_part, repeat_size = form(n,d)
s = str(integer_part)
if not (decimal_part or repeat_part):
return s
s = s + "."
if decimal_part or shift:
s = s + "{:0{}}".format(decimal_part, shift)
if repeat_part:
s = s + "({:0{}})".format(repeat_part, repeat_size)
return s
test_cases = [
(1,4),
(1,3),
(7,11),
(29, 12),
(1, 9),
(2, 3),
(9, 11),
(7, 12),
(1, 81),
(22, 7),
(11, 23),
(1,97),
(5,6),
]
for n,d in test_cases:
print("{} / {} == {}".format(n, d, printable_form(n,d)))
Result:
1 / 4 == 0.25
1 / 3 == 0.(3)
7 / 11 == 0.(63)
29 / 12 == 2.41(6)
1 / 9 == 0.(1)
2 / 3 == 0.(6)
9 / 11 == 0.(81)
7 / 12 == 0.58(3)
1 / 81 == 0.(012345679)
22 / 7 == 3.(142857)
11 / 23 == 0.(4782608695652173913043)
1 / 97 == 0.(0103092783505154639175257
73195876288659793814432989690721649484
536082474226804123711340206185567)
5 / 6 == 0.8(3)
I forget exactly how it works... I think I was trying to reverse-engineer the process for finding the fraction form of a number, given its repeating decimal, which is much easier than the other way around. For example:
x = 3.(142857)
1000000*x = 3142857.(142857)
999999*x = 1000000*x - x
999999*x = 3142857.(142857) - 3.(142857)
999999*x = 3142854
x = 3142854 / 999999
x = 22 / 7
In theory, you can use the same approach going from fraction to decimal. The primary obstacle is that it's not completely trivial to turn an arbitrary fraction into something of the form "(some number) / (some amount of nines)". If your original denominator is divisible by 2 or 5, it can't evenly divide any 9-repunit. So a lot of form's work is about removing factors that would otherwise make it impossible to divide by 999...9.
The main idea is to find out the decimal place. In order word, where to put a decimal '.'
When a number is divided by 2 or 5, there is no recurring decimal. 1/2 = 0.5, 1/5 = 0.2. Only those are not 2 or not 5. eg. 3, 7, 11. How about 6? In fact, 6 is 2x3 where recurring decimal occurs due to the factor of 3. 1/6 = 1/2 - 1/3 = non recurring part + recurring part.
Take an other example 1/56. 56=8x7=2^3x7. Note that 1/56 = 1/7 - 1/8 = 1/7 - 1/2^3. There are 2 parts. The front part is 1/7 which is recurring 0.(142857), while the latter part 1/2^3 = 0.125 not recurring. However, 1/56 = 0.017(857142). 1/7 has recurring just after the '.' The recurring part for 1/56 is 3 decimal place later. This is because 0.125 has 3 decimal place and make it not recurring until 3 decimal place later. When we know where the recurring part starts, it is not hard to use long division to find out where the recurring's last digit.
Similar case for 5. Any fraction can have form like = a/2^m + b/5^n + recurring part. The recurring part is pushed rightward either by a/2^m or b/5^n. This is not hard to find out which ones push harder. Then we know where the recurring part starts.
For finding recurring decimal, we use long division. Since long divison will get the remainder, multiply the remainder by 10 and then use as a new nomerator and divide again. This process goes on and on. If the digit appear again. This is the end of the recurring.

Rounding of a Value in Python

Can Python disable or not used the rounding off a float?
This is my sample
value = 6.30 * 75.73
value:
477.099
I want only to get the value 477.09 without rounding it off.
You can convert to a string and using string split, append just the last 2 digits of the number
num = 477.097
strnum = str(int(num)) + str(num).split(".")[1][:2]
What you want is called truncating, which is notoriously difficult with float values because of the way they are stored.
If you are doing this for the value itself, you can do this;
value = 6.30 * 75.73
value = (( value * 100 ) // 1) * .01
print(value)
This will print
477.09000000000003
which is equivalent to 477.09 for math calculations.
If you are doing this to display the value, then you can convert to a string and just cut off the last digit that you have. Or, if you don't know how many digits there are after the decimal point, you can get the index of the ".", and cut everything that is 2 after that point, as so:
value = 6.30 * 75.73
val_str = str(value)
rounded_str = val_str[:val_str.index('.') + 3]
This will print
477.09
convert value to string(if value an integer then the code will still work, because before the conversion to a string we convert to a float):
value = = 6.30 * 75.73
value_str = str(float(value))
'{:.2f}'.format(float(value_str[:value_str.index('.') + 3]))
Possibly this? (takes about 100 nanoseconds independent of number of digits)
** note, this does not work for negative numbers as written, so it's of limited use.
value = 6.30 * 75.73
print value
print value - value % 0.01
477.097
477.09
does it really truncate?
value = 1./3.
print value - 0.33333333 # see the leftovers
3.333333331578814e-09
print value - value % 0.01
0.33
print (value - value % 0.01) - 0.33 # no leftovers
0.0
(value - value % 0.01) == 0.33
True
You can try this hack with round:
>>> 6.30 * 75.73
>>> 477.099
>>> DIGITS = 2
>>> round(6.30 * 75.73 - 5.0 * 10**(-DIGITS-1), DIGITS)
>>> 477.09

Categories

Resources