6
// 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

Matt K
  • 13,370
  • 2
  • 32
  • 51
justachap
  • 313
  • 1
  • 5
  • 12
  • 2
    `a /= b` is equal to `a = a / b;`. – Rob W Mar 20 '13 at 22:16
  • 1
    It's the shorthand [*divide-and-assign* operator](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Assignment_Operators) – Bergi Mar 20 '13 at 22:17
  • 1
    It's worth noting that, while Python also has a `/=` that does a divide-and-assign like JS's, assignment a _statement_ rather than an _expression_ in Python, so `-c * (t/=d)*(t-2) + b will be a `SyntaxError`. – abarnert Mar 20 '13 at 22:19
  • @VisioN: But you don't have to do it twice, since `t` *is* reused. "simple division" would require `c*t/d*t/d+b` – Bergi Mar 20 '13 at 22:21
  • @Bergi: we don't know if it's reused. It depends on whether `t/=d` or `t-2` is evaluated first. – André Caron Mar 20 '13 at 22:21
  • @AndréCaron Well, it should be evaluated first. I've skipped the second usage of `t`, my bad. – VisioN Mar 20 '13 at 22:22
  • @VisioN: What does "should" mean? Is that what the language spec says or are you assuming natural evaluation order is left to right? Most languages explicitly state that evaluation order is unspecified because it gives compilers/interpreters more flexibility for optimizations. – André Caron Mar 20 '13 at 22:28
  • @AndréCaron It means that in any case in `-c *(t/=d)*(t-2) + b` the part `(t/=d)` will be evaluated first according to natural evaluation order. The cases like that work in the same way for most languages. I doubt if optimization influences it anyhow. – VisioN Mar 20 '13 at 22:30
  • @AndréCaron: As it turns out, that _is_ what the language spec says, assuming you accept ECMAScript 5.1 as the language spec for JavaScript. See my answer for details. – abarnert Mar 20 '13 at 23:12
  • "Easing function specifies the speed of animation progresses to make it more realistic. " http://easings.net/ – Colonel Panic Mar 20 '13 at 23:22

5 Answers5

7

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.)

abarnert
  • 354,177
  • 51
  • 601
  • 671
  • Some people think that jamming it all in one line makes it magically run faster. – John La Rooy Mar 20 '13 at 22:29
  • Thanks @abarnert for the explanation. As a general question, I presume no one know of the python equivalent? I can't be the first person trying to use them in python surly... – justachap Mar 20 '13 at 22:34
  • @gnibbler: Actually, I think I know why someone thought it would be faster, not just the silly "fewer characters to interpret" fallacy, but the "JS is just like C on a PDP-11, right?" fallacy… – abarnert Mar 20 '13 at 22:34
  • @justachap: The Python equivalent is to move each `/=` onto its own line. And… well, it's complicated. Let me revise the answer. – abarnert Mar 20 '13 at 22:35
  • @justachap, the Python equivalent is in my answer – John La Rooy Mar 20 '13 at 22:36
  • 1
    @justachap: … or, better, the real Python equivalent is an expression that doesn't completely confuse you, and make me and gnibbler go running for references (that neither of us have found) about details of JS evaluation, and so on. Maybe `c * (t/d)**2 + b`, which any idiot (even me) can immediately figure out. – abarnert Mar 20 '13 at 22:50
1

/= is an augmented assignment operator. t /= d is the same as t = t / d. +=, -=, and *= also exist, among others...

MattDMo
  • 100,794
  • 21
  • 241
  • 231
1

Well its a short-hand operator just like the += but instead of adding it divides. Here is the long form

t = t / d
Hugo Dozois
  • 8,147
  • 12
  • 54
  • 58
1
c*(t/=d)*t + b;

Is equivalent to

t /= d            # or t = t / d
c * t * t + b

Because Python can't to assigment inside expressions

Remember that if t and d are both int/long, this will be a truncated division in Python2

Likewise easeOutQuad would be

def easeOutQuad (x, t, b, c, d):
    t /= d
    return -c * t * (t - 2) + b
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
  • 1
    Does JavaScript define when the assignment to t happens? That use of the `/=` operator makes me worry. – Matt K Mar 20 '13 at 22:19
  • 2
    No, it's not. `t = t/d` is evaluated before! – Bergi Mar 20 '13 at 22:19
  • @Bergi, ok, let me fix that – John La Rooy Mar 20 '13 at 22:22
  • @mkb, I agree. I had to try it out to check the order of the operations. I don't know if JS _defines_ this behaviour. Perhaps Bergi or someone can point us to a reference about it – John La Rooy Mar 20 '13 at 22:28
  • @gnibbler: Actually, JavaScript is specifically defined as what MDN says, or, if the latest Firefox contradicts it, what Firefox does… But _ECMAScript_ is standardized. – abarnert Mar 20 '13 at 22:54
0

Divide and assign.

>>> p = 6
>>> p /= 2
>>> p
3
dwerner
  • 6,462
  • 4
  • 30
  • 44