Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does t /= d mean? Python and getting errors

// t: current time, b: begInnIng value, c: change In value, d: duration

def: 'easeOutQuad',
swing: function (x, t, b, c, d) {
    //alert(jQuery.easing.default);
    return jQuery.easing[jQuery.easing.def](x, t, b, c, d);
},
easeInQuad: function (x, t, b, c, d) {
    return c*(t/=d)*t + b;
},
easeOutQuad: function (x, t, b, c, d) {
    return -c *(t/=d)*(t-2) + b;
},

I am trying to convert Robert Penner's Easing Functions into python and getting stuck! Any help or any one else done this before?

https://github.com/danro/jquery-easing/blob/master/jquery.easing.js

like image 323
justachap Avatar asked Mar 20 '13 22:03

justachap


People also ask

What are the 3 types of errors in Python?

There are mainly three kinds of distinguishable errors in Python: syntax errors, exceptions and logical errors.

Why am I getting syntax errors in Python?

Syntax errors are produced by Python when it is translating the source code into byte code. They usually indicate that there is something wrong with the syntax of the program. Example: Omitting the colon at the end of a def statement yields the somewhat redundant message SyntaxError: invalid syntax.

What do Python errors mean?

Python - Error Types. The most common reason of an error in a Python program is when a certain statement is not in accordance with the prescribed usage. Such an error is called a syntax error. The Python interpreter immediately reports it, usually along with the reason.


1 Answers

In both JavaScript and Python, /= is an "augmented assignment" operator, with pretty much the same meaning.

In JS:

var i = 10;
i /= 2;

… is equivalent to:

var i = 10;
i = i / 2;

And, in Python:

i = 10
i /= 2

… is likewise equivalent (not quite exactly the same, but close enough for numbers) to:

i = 10
i = i / 2

However, there is one very big difference.

In JavaScript, assignment is an expression—it has a value, and that value is the value being assigned to the variable. So:

var i = 10;
var j = i /= 2;

… is roughly equivalent to:

var i = 10;
i /= 2;
var j = i;

In Python, assignment is a statement. It has no value, and cannot be used in an expression. So:

i = 10
j = i /= 2

… raises a SyntaxError.


Porting code that uses assignment (augmented or otherwise) in the middle of an expression generally requires breaking that expression up into multiple lines and/or finding a way to rewrite the expression to not require any assignments. (But often, that's not a bad thing, because the original expressions weren't very readable anyway…)

For example, assuming JS evaluates operands from left to right (which I'm not sure is guaranteed?):

def easeInQuad(x, t, b, c, d):
    t /= d
    return c*t*t+b

More generally, you do this:

old_t = t
t /= d

And then you replace any instances of t before that t/=d with old_t, and leave all instances from t/=d and later alone. Fortunately, in this case, there are no previous instances, so we don't need that old_t stuff.

And if you think about it, you can easily get the same effect without ever changing t, in one line, much more readably, in any of the following ways:

return c * (t/d) * (t/d) + b
return c * (t/d)**2 + b
return c * t*t / d*d + b

Someone who thinks in C will immediately complain that these are all "too slow". After all, the first does an extra division, the second does an exponentiation instead of a multiplication, and the third does two multiplications instead of one. Horrors!

Of course you can always use a temporary variable:

t_over_d = t/d
return c * t_over_d * t_over_d + b

… but again, to a C programmer, that implies that you're using up a valuable register. Sure, every compiler written after, say, 1985 will detect that t is dead as soon as t_over_d appears and reuse the same register, but why not force it to reuse the register if we can, especially if it saves a few keystrokes too?

In JS or Python, the cost of a multiplication is such a tiny fraction of the cost of calling a function, and interpreting the bytecode, and so on that you'd never even notice it. Meanwhile, the cost of rebinding a local variable (especially in a V8-style or PyPy-style JIT interpreter) might be much, much higher than the cost of passing around an unnamed temporary result.

So, this is a paradigm case of misguided "optimization" making code much harder to understand, while probably slowing it down instead of speeding it up, and in an area that cannot possibly be a bottleneck worth optimizing anyway.


Since gnibbler brought up the question of whether JavaScript actually does guarantee this evaluation order…

First, JavaScript is defined as, effectively, "what Firefox does" (and "what Spidermonkey does", but that ought to be the same thing—and, if it isn't, then JavaScript does 2 things, so that's twice as good, right?). But ECMAScript is defined by standards, and it's those standards that every JS implementation (despite the name) pays lip service to, and we can pretend that ECMAScript 5.1 is the standard that all implementations conform to (which is true so long as "all implementations" means "Opera"). You can find it here.

So, in ES 5.1: 11.5 Multiplicative Operators guarantees that the result of (t/=d) will be evaluated before t, and 11.13.2 Compound Assignment guarantees that evaluating t/=d will set the value of t before it finishes. (You have to read up on what "evaluate" means and what GetValue an SetValue mean, but I'm pretty sure this really is guaranteed.)

like image 120
abarnert Avatar answered Oct 02 '22 09:10

abarnert