Jump to content

  • Log In with Google      Sign In   
  • Create Account

We're offering banner ads on our site from just $5!

1. Details HERE. 2. GDNet+ Subscriptions HERE. 3. Ad upload HERE.


Why is this code like this? (Order of function calls in an equation)


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
14 replies to this topic

#1 Servant of the Lord   Crossbones+   -  Reputation: 20974

Like
1Likes
Like

Posted 27 February 2013 - 01:34 PM

In one of the Robert Penner ease equations (bounceEase), one of the lines (in Javascript) are:

return (7.5625*(position-=(1.5/2.75))*position + .75);

 

However, when someone else was ported them to C++, the person porting did this:

float postFix = position-=(1.5f / 2.75f);
return (7.5625f * (postFix) * position + 0.75f);

Presumably because the order that "position -= n" is called is undefined behavior? It could be resolved before or after the second use of 'position' is resolved, right?

 

But the change seems rather silly to me, because isn't the altered code identical to:

 

position -= (1.5f / 2.75f);
return (7.5625f * position * position + 0.75f);

 

Why bother having a identical copy of 'position' be called 'postFix'. Wouldn't they hold the same value?


It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal

[Fly with me on Twitter] [Google+] [My broken website]

[Need web hosting? I personally like A Small Orange]


Sponsor:

#2 Nypyren   Crossbones+   -  Reputation: 4787

Like
3Likes
Like

Posted 27 February 2013 - 02:33 PM

Your confusion is the #1 reason why I would NEVER modify a variable in an expression that contains the same variable more than once. I would explicitly split the expression into multiple lines like the C++ version has.

I have no idea what Javascript's convention for expression evaluation order or sequence points is, but your second C++ code is the better interpretation of the function.

Edited by Nypyren, 27 February 2013 - 02:36 PM.


#3 Servant of the Lord   Crossbones+   -  Reputation: 20974

Like
0Likes
Like

Posted 27 February 2013 - 02:43 PM

You mean, this:

position -= (1.5f / 2.75f);
return (7.5625f * position * position + 0.75f);

 

Is in-fact a proper interpretation of the original Javascript version? Am I correct in thinking I can just cut out the whole 'postfix' variable?

 

I'm fully in agreement about not modifying a variable inside of expressions. smile.png

Aside from potential undesired behavior, it also makes the code look messier, IMO.


It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal

[Fly with me on Twitter] [Google+] [My broken website]

[Need web hosting? I personally like A Small Orange]


#4 King Mir   Members   -  Reputation: 2050

Like
1Likes
Like

Posted 27 February 2013 - 03:03 PM

It looks like the creation of the postFix variable was the minimal change to make the code valid c++ (because of undefined behavior, like you mentioned). It's the stock way of breaking up an expression by replacing a part of the expression with a intermediate variable. Your alternative code is much cleaner.

Edited by King Mir, 27 February 2013 - 03:07 PM.


#5 jwezorek   Crossbones+   -  Reputation: 1973

Like
2Likes
Like

Posted 27 February 2013 - 03:16 PM

It looks like the creation of the postFix variable was the minimal change to make the code valid c++ (because of undefined behavior, like you mentioned). It's the stock way of breaking up an expression by replacing a part of the expression with a intermediate variable. Your alternative code is much cleaner.

 
Yes, it looks to me like whoever wrote the original C++ port i.e. the one containing
float postFix = position-=(1.5f / 2.75f);
 
was just going really fast and porting without thinking too much about the source code. If you've ever ported from one language to another you've probably gotten into this mind set: let me just plow through this, get it working, and I can clean it up later. Of course, you never end up cleaning it up.
 
But yeah, your version 
position -= (1.5f / 2.75f);
return (7.5625f * position * position + 0.75f);
is equivalent (and clearer).  I think the original Javascript version was just being pointlessly clever, actually not even clever just kind of baroque.

Edited by jwezorek, 27 February 2013 - 03:19 PM.


#6 Servant of the Lord   Crossbones+   -  Reputation: 20974

Like
0Likes
Like

Posted 27 February 2013 - 03:27 PM

Thanks, that answered my question.
It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal

[Fly with me on Twitter] [Google+] [My broken website]

[Need web hosting? I personally like A Small Orange]


#7 Plethora   Members   -  Reputation: 679

Like
0Likes
Like

Posted 27 February 2013 - 08:50 PM

I think the original Javascript version was just being pointlessly clever, actually not even clever just kind of baroque.

 

May I piggyback on this thread (seeing as its been resolved) to ask a question that jumped to the fore of my mind when I read this?  :)

 

Many moons ago, I was just out of college and looking around to get a job in programming with my shiny new CS degree.  One place I applied gave me two interviews... Well long story short, they had their own proprietary language which they wrote their software with.  There was a test I had to take where it would give you some code snippet in c++ and then something equivilent in their language, then ask you to use those concepts to solve some common coding problems with their language.

 

The last task on the test was just to codeup a pretty simple sorting algorithm from scratch.  I was invited back for a second interview during which my test was reviewed.  The only issues the interviewer had were on this sorting algorithm, where the guy kept pointing out where I could have written it with fewer lines of code, as if fewer lines was the be all end all of coding.  This being an interview I mostly just nodded and kept my mouth shut even though I thought my version was just about identical to what he wanted with the exception of mine being significantly more readable and less confusing.

 

So this post reminded me very much of that experience.  Is there some historical basis for the belief that fewer lines of code are better if possible?  Is that sort of belief more common in certain areas of CS?  I remember being slightly confused but the emphasis being placed on the actual number of lines used. 


I'm working on a game!  It's called "Spellbook Tactics".  I'd love it if you checked it out, offered some feedback, etc.  I am very excited about my progress thus far and confident about future progress as well!

 

http://infinityelephant.wordpress.com


#8 Nypyren   Crossbones+   -  Reputation: 4787

Like
0Likes
Like

Posted 27 February 2013 - 09:05 PM

Lines of code doesn't matter as much as readability, but sometimes there are other ways to do things which are both shorter and more readable.
 
Here's an example.  In C#, you can open a file and read its contents:
 
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read))
{
  using (var sr = new StreamReader(fs))
  {
    return sr.ReadToEnd();
  }
}
Or, you can do it with one line of code:
return File.ReadAllText(path);

Edited by Nypyren, 27 February 2013 - 09:06 PM.


#9 Cornstalks   Crossbones+   -  Reputation: 6991

Like
0Likes
Like

Posted 27 February 2013 - 09:13 PM

So this post reminded me very much of that experience.  Is there some historical basis for the belief that fewer lines of code are better if possible?  Is that sort of belief more common in certain areas of CS?  I remember being slightly confused but the emphasis being placed on the actual number of lines used.

(100% speculation on my part):

I suspect this mentality has evolved from two sources.

The first (and probably biggest) is that back in the day, your screen was 80 characters wide and 24 lines tall. That's not a lot of room. These days we've got luxurious huge screens, multiple monitors, etc. Back then, the shorter and more concise your code was, the more you could fit on your screen and actually see your program's flow. These "old timers" who grew up with screens like this sometimes still have the habit of coding for 80x24 sized screens.

The second reason is that optimizers have gotten better, but back in the day, you pretty much had to optimize your own code. Shorter, sometimes cryptic code could mean using a few less cycles. These days, optimizers can kick the crap out of a lot of programmers and it's more worthwhile to focus on algorithmic optimizations than line-by-line optimizations. However, again, some people still have the mentality that their cryptic code is needed in order to squeeze out a few instructions, when that's not the common case today (if you're using a proper compiler).

These two things may have created habits in people that together can lead to some unnecessarily condensed and cryptic code.


[ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

#10 Servant of the Lord   Crossbones+   -  Reputation: 20974

Like
0Likes
Like

Posted 27 February 2013 - 09:26 PM

I personally like copious whitespace and good variable names.
 
Here's the code I got online: (Copied and pasted here, I didn't make it look worse)
float Bounce::easeOut(float t,float b , float c, float d) {
    if ((t/=d) < (1/2.75f)) {
        return c*(7.5625f*t*t) + b;
    } else if (t < (2/2.75f)) {
        float postFix = t-=(1.5f/2.75f);
        return c*(7.5625f*(postFix)*t + .75f) + b;
    } else if (t < (2.5/2.75)) {
        float postFix = t-=(2.25f/2.75f);
        return c*(7.5625f*(postFix)*t + .9375f) + b;
    } else {
        float postFix = t-=(2.625f/2.75f);
        return c*(7.5625f*(postFix)*t + .984375f) + b;
    }
}
(It's a static member function in an otherwise empty class. I don't know why they didn't just use a namespace)
 
Here's the same code, but after being added to my library:
float BounceEase(float position)
{
    //Optimization for end points, which are the most common spots.
    if(position == 0.0f || position == 1.0f)
    {
        return position;
    }
    
    if(position < (1.0f / 2.75f))
    {
        return (7.5625f * position * position);
    }
    else if(position < (2.0f / 2.75f))
    {
        position -= (1.5f / 2.75f);
        return (7.5625f * position * position + 0.75f);
    }
    else if(position < (2.5f / 2.75f))
    {
        position -= (2.25f / 2.75f);
        return (7.5625f * position * position + 0.9375f);
    }
    else
    {
        position -= (2.625f / 2.75f);
        return (7.5625f * position * position + 0.984375f);
    }
}
(There's minor differences because their version takes more parameters, but those parameters are constant in my code so I cut them out. The point is the whitespacing and the variable names)
 
@Nypyren: I like code like that. Sometimes few lines (hiding the rest of the lines in well-named functions) are a great benefit for legibility.
I have alot of C++ code that looks similar. LoadFileAsString(), LoadFileAsStringList(), LoadCSVFile(), LoadFileAsStringMap(), etc... 
 
This code:
StringList stringList = String::CommentedLinesRemoved(LoadFileAsStringList(filepath), '/');
if(stringList.empty())
    return false;

for(const auto &str : stringList)
{
    auto keyValue = StringToPair<std::string, std::string>(str, '=', ConvertFromString<std::string>, String::RemoveFlankingQuotes);
    this->SetVariable(keyValue.first, keyValue.second); //Add each key-value pair to the PathResolver's map.
}
 
Parses this file:
//--------------------------------------------------------------------------------
//Config file paths. These paths tell the game engine where to find the different types of config files.
//--------------------------------------------------------------------------------
 
%ENGINE-CONFIG%    = "%CONFIG%/Engine/"
%GAME-CONFIG%        = "%CONFIG%/Game/"
 
%USER-DEFAULTS%    = "%GAME-CONFIG%/User Defaults/"
%USER-SETTINGS%    = "%USER%/Settings/"
%DISPLAY-SETTINGS%      = "%USER-SETTINGS%/Display Settings/"
Helper functions for the win!

Edited by Servant of the Lord, 27 February 2013 - 09:27 PM.

It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal

[Fly with me on Twitter] [Google+] [My broken website]

[Need web hosting? I personally like A Small Orange]


#11 Trienco   Crossbones+   -  Reputation: 2224

Like
0Likes
Like

Posted 27 February 2013 - 11:23 PM

Maybe they are desperately trying to save money and use tools like Coverity. Where the absurd criteria for the price is "lines of code". But then, I pretty much doubt those tools would support their proprietary language.
 
In terms of code, whenever something looks very repetitive or has a pattern, I feel the strange urge to change the code (depending on how much performance might be an issue). Things like repeating magic numbers or formulas just irk me somehow.
 
float BounceEase(float position)
{
    //Optimization for end points, which are the most common spots.
    if(position == 0.0f || position == 1.0f)
    {
        return position;
    }
 
    const float bias[] = {.0f, 1.5f/2.75f, 2.25f/2.75f, 2.625f/2.75f};
    const float offset[] = {.0f, .75f, .9375.f, .984375f};
    unsigned range = 3;
    
    if (position < (1.0f / 2.75f))
        range = 0;
   
    else if (position < (2.0f / 2.75f))
        range = 1;
  
    else if (position < (2.5f / 2.75f))
        range = 2;
 
    position -= bias[range];
    return (7.5625f * position * position + offset[range]);
}

Edited by Trienco, 27 February 2013 - 11:32 PM.

f@dzhttp://festini.device-zero.de

#12 jwezorek   Crossbones+   -  Reputation: 1973

Like
0Likes
Like

Posted 28 February 2013 - 10:30 AM

Yeah, what's up with all those magic numbers? Shouldn't they be constants or parameters or something?



#13 Servant of the Lord   Crossbones+   -  Reputation: 20974

Like
0Likes
Like

Posted 28 February 2013 - 01:11 PM

I heavily use constants and variables in the code I write, but I'm still trying to understand the equation (which I didn't create) so I haven't messed with it too much. I think the '2.75f' and '7.5625f' are supposed to be variables passed in as parameters, and I think the rest are calculated based off of the '2.75f'. That's my goal for today - to figure out how it actually works, and to make it configurable through parameters like other peoples' implementations.


It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal

[Fly with me on Twitter] [Google+] [My broken website]

[Need web hosting? I personally like A Small Orange]


#14 jwezorek   Crossbones+   -  Reputation: 1973

Like
0Likes
Like

Posted 28 February 2013 - 01:27 PM

Servant, when you're done with this easing stuff you should write a journal about it and post the code. I think I could use easing functions for something I am working on. (I have a new version of my bezier curve paths code that supports bezier splines and re-parametrizing for arc length and could apply easing functions to the t-parameter for more natural looking behavior, I think)

#15 Servant of the Lord   Crossbones+   -  Reputation: 20974

Like
0Likes
Like

Posted 28 February 2013 - 01:40 PM

Sure - as mentioned, I'm just using Robert Penning's algorithms (what pretty much everyone uses), but doing a C++ port that fits better with my coding style and needs.

I'll post the code on my journal in a few days once I'm satisfied I got it all working.


It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal

[Fly with me on Twitter] [Google+] [My broken website]

[Need web hosting? I personally like A Small Orange]





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS