I don’t.
Part of the trickiness with a pseudorandom (or, worse, actually random)
sequence is that without special arrangements you will be testing
different sequences on every run. This means that if you encountered a
problem such as division by zero and you change the code (your
try/except) and rerun and the problem doesn’t show up, it does not mean
that the problem is fixed. It may mean you just got a different sequence
which would not have shown the problem anyway.
Ideally you would test the same sequence you used before after your code
change. Let’s look at your function:
def number():
epoch = calendar.timegm(time.gmtime())
... compute a number from this starting point ...
For purposes of testing you might benefit by splitting this into 2
functions:
def number():
epoch = calendar.timegm(time.gmtime())
return _number(epoch)
def _number(epoch):
... compute a number from this starting point ...
With this structure you could test the _number()
function directly,
and feed it the same epoch
value which caused the problem you’re
trying to fix. Obviously, you’d need to know that number, by you can
just put a print(epoch)
call at the start of _number()
to see that.
Now your loop:
while True:
try:
z = (first*amount + second) % third
except ZeroDivisionError:
continue
else:
amount += z
if amount > 1000000:
break
return amount - 1000000
Can you see that if third
is zero the except ZeroDivisionError
branch will run and continue to the next loop iteration. But no values
have been changed, so the next iteration will also perform a division
by zero. This will repeat forever, essentially the same situation you
were in before.
You need to do something in the except
branch to change the situation,
maybe setting third=1
or something. Although 1
itself has problems
in than %1
always returns 0
, which means z
will be 0
, which
means amount
will not change. And your loop will again run forever
because amount
never reaches your cutoff point.
Ideally you should be certain that your loop will finish. One way to do
that is with a bound: exit the loop when some threshold is reached. You
have that: amount>1000000
. Normally that would be your while
condition as you originally had it:
while amount <= 1000000:
Instead of trying to be tricky with the condition, a different approach
is to ensure that every loop iteration advances closer to the bound.
That might mean that amount
must always increase. And that should mean
that z
is always >0
. Compute z
in a way so that that is always
true.
For example, knowing that %
in Python always returns a nonnegative
value, you might compute:
z = (first*amount + second) % third + 1
Your zero division clause might simply set z=1
instead of continuing.
In that way you always advance amount
and you will
eventually
reach the loop bound.
An approach like this means that you can prove to yourself that the loop
will always finish instead of trying things until you no longer
encounter problems. The latter approach just means you have not tried a
problematic starting point, not that you know that there are no
problematic starting points.
Testing can show the presence of bugs, but not their absence. - Dijkstra
Cheers,
Cameron Simpson cs@cskk.id.au