Why split this operation into two cause result changes?

Asked

Viewed 99 times

7

I made a simple algorithm that solved Fibonacci in 2 logical operations within the loop. I decided to look for a better way and found a version that makes in only 1 calculation inside the loop. It worked perfectly, but when I went to understand the logic appeared a problem.

The code that generates the correct sequence is as follows:

N = int(input())
x, b, a = 0, 1, 0

while x < N:
    print('{}'.format(a), end=' ')
    a, b = b, a + b
    x += 1

So I tried to break down logic a, b = b, a + b and the results started to give problems.

For example: Both

a = b
b = a + b

as

b = a + b
a = b

present as output a sequence totally outside the expected.

I ask: What is the mistake in changing the logic in these cases since I kept the same logical operations although in different lines? There is some difference in being on the same line or in separate lines?

2 answers

9


There is a difference. When on the same line, both values will be updated concurrently, while on different lines no. How a starts at zero and b in a, when you do a, b = b, a+b, a will receive the value of b, 1, and b will receive the value of a+b, 0+1=1. Note that the value of a is still 0 on this line as it will be 1 only after the entire line is executed. In separate lines, b would receive 1+1=2, breaking the sequence.

In the same vein:

a = 0
b = 1

print('Antes:')
print('a', a)  # a 0
print('b', b)  # b 1

a, b = b, a+b

print('Depois:')
print('a', a)  # a 1
print('b', b)  # b 1

See working on Repl.it | Ideone

In separate lines:

a = 0
b = 1

print('Antes:')
print('a', a)  # a 0
print('b', b)  # b 1

a = b 
b = a+b

print('Depois:')
print('a', a)  # a 1
print('b', b)  # b 2

See working on Repl.it | Ideone

What really happens is the construction and deconstruction of tuples. Analyzing only the line a, b = b, a + b, the interpreter will first build a tuple internally with the current values of b and a + b; would be the equivalent of doing temp = (b, a+b). Then he will deconstruct this tuple by assigning the values to (a, b); equivalent to (a, b) = temp. That is, first the tuple is built with the current values, then the assignment is made, so it works as expected.

Using the function dis.dis we can see what really happens in this instruction:

>>> print(dis.dis('a, b = b, a+b'))
  1           0 LOAD_NAME                0 (b)
              2 LOAD_NAME                1 (a)
              4 LOAD_NAME                0 (b)
              6 BINARY_ADD
              8 ROT_TWO
             10 STORE_NAME               1 (a)
             12 STORE_NAME               0 (b)
             14 LOAD_CONST               0 (None)
             16 RETURN_VALUE
None

Basically:

  1. LOAD_NAME: Press the value from the name in the stack b (Stack: b);
  2. LOAD_NAME: Press the value from the name in the stack a (Stack: b, a);
  3. LOAD_NAME: Press the value from the name in the stack b (Stack: b, a, b);
  4. BINARY_ADD: Runs the sum of the last two values on the stack and loads the result on the stack (Stack: b, a+b);
  5. ROT_TWO: Inverts the positions of the last two values in the stack (Stack: a+b, b);
  6. STORE_NAME: Removes a value (b) of the stack and stores in the name a (Stack: a+b);
  7. STORE_NAME: Removes a value (a+b) of the stack and stores in the name b (Stack: empty);

Which shows how it is stored before the values of b and a+b and only then is the assignment made.

2

What happens is that in the expression a, b = b, a + b, the value of a + b is calculated before the value of a be amended (to b).

Example:

a = 3
b = 5
a, b = b, a + b
a
=> 5
b
=> 8

When you do one at a time, the values that will be used in a + b change before the time.

Example:

a = 3
b = 5
a = b
a
=> 5
b = a + b
b
=> 10   

Browser other questions tagged

You are not signed in. Login or sign up in order to post.