tags:

views:

238

answers:

4

I have a particular application that needs to calculate something very specific, and while I excel at logic, math has always been my weak spot.

Given a number, say -20, it needs to apply a calculation of a 100 base (that is, the base is 100, not 0. not to be confused with base 100 which would be something else totally).

In other words, the math works like this ..., 105, 104, 103, 102, 101, 100, -101, -102, -103, -104, -105, ...

Then I need to do the math based on this 100 base figure.

So, for example:

-140 - 20 =  120
-120 - 20 =  100  
-115 - 20 = -105
-110 - 20 = -110
-105 - 20 = -115
 100 - 20 = -120  
 120 - 20 = -140

If it helps, the problem is related to sports odds. In theory, this refers to money (risk $1.40 to win $1.00 on one side, risk $1.00 to win $1.20 on the other, the .20 difference is what casinos call "the juice" or their cut of moving money back and forth.) However, the program is not dealing with real money, it's more of a simulator.

My current formula works like this:

decimal CalculateSides(decimal side, decimal vig)
{
    decimal newSide = side - vig;

    newSide = -(newSide < 0) ? newSide + 100 : newSide - 100;

    return (newSide < 0) ? newSide + 100 : newSide - 100;
}

While this formula works, I'm not very happy with the conditional +/-, but this is basically the only formula that works for me.

Can anyone suggest a way to improve this? Preferably without conditions of +/-?

EDIT:

When I asked the question, I knew one possible answer was "It's probably best the way you're doing it", and that seems to be the consensus.

+1  A: 

Optimization is generally done to make something run faster. Have you actually found that your code is not running fast enough? I suspect not.

If your code generates the right results and does it in such a way that it doesn't take a great deal of time, leave it alone, and concentrate on other code that's an actual rather than a perceived, problem.

If you're just worried about the way it looks, add some comments to explain how it works. You would most likely have to do that anyway with a one-formula solution so you may as well not waste your effort.

paxdiablo
Otimizing is not only to make something run faster. It's also to make the code more elegant or easy to read or to simplify the problem. In this case, it has nothing to do with performance.
Mystere Man
I should say, though, that this simulator could run billions of iterations, so performance could be an issue.. i just haven't reached the point of measuring that yet.
Mystere Man
Code is best made easy to read by adding a comment explaining it, and I can think of little more elegant than an if-statement with two one-statement choices. No doubt you could make it clever with a complicated y=fn(x) type statement, but that's likely to be less obvious (hence readable) than more.
paxdiablo
And the right time to optimize is when you have a problem, not before. Otherwise it's potentially wasted effort. "Measure, don't guess" is one of my all-time favorite sayings.
paxdiablo
Right. Have you run this code billions of times in a loop and shown that it is too slow?
Ed Swangren
As I said, I haven't reached the point of measuring that. My primary concern right now is not it's performance, just that performance is a secondary consideration, so I don't want to do anything that will obviously affect performance. My primary concern is making the code as simple as it can be, but no simpler (to paraphrase Einstein)
Mystere Man
While you can say you want to optimize the clarity/simplicity of a piece of code. Generally in a programming context "optimize" is taken to mean make it go faster. Clarity and simplicity are often sacrificed in the name of speed. So it's no surprise some people were confused by your request to optimize the simplicity.
ScottS
so maybe it's a bad title for the question - what he's asking is still valid
warren
I have to go with Mystere Man/warren. Comments are meta-data. Well-written code that is easy to read is best left without any redundancy. Cleaning up the code to a readable sate is a huge improvement over just throwing in a comment.
Jonas Byström
@Jonas, if you have code that's clearer than the one provided in the question, you should supply an answer. But so far, none of the code answers *have* been clearer (@starblue's suggestion is a nifty one, though). I still believe that the code provided can't be *made* much more readable and would benefit more from a comment if the questioner thinks it's unclear.
paxdiablo
+6  A: 

One sensible way to handle this would be to compute internally with ordinary numbers which go from positive to negative at zero, and only add/subtract 100 for presentation.

starblue
That's a thought that hadn't occurred to me. I'll mull that one over.
Mystere Man
what I would've suggested had I seen the question sooner :)
warren
+2  A: 

I strongly suspect that your sample function is broken. Is it a copy paste or did you retyped it ?

decimal CalculateSides(decimal side, decimal vig)
{
    decimal newSide = side - vig;
    newSide = -(newSide < 0) ? newSide + 100 : newSide - 100;
    return (newSide < 0) ? newSide + 100 : newSide - 100;
}

Just try with CalculatesSides(115, 20) you get -95, unlikely to be what you want. (I I understand well result should be -105).

However what you where trying to write seems clear enough. I believe it should be:

decimal CalculateSides(decimal side, decimal vig)
{
    decimal newSide;
    side = (side < 0) ? side + 100 : side - 100;
    newSide = side - vig;
    return (newSide < 0) ? newSide - 100 : newSide + 100;
}

This is quite straightforward and won't be easy to optimize

  1. change mode from 100base to 0base
  2. compute in zero base
  3. convert result base from 0base to 100base

You can do some tricks based on signs to avoid the tests as other suggested, but the result will be quite obfuscated and probably slower.

My advice would be to leave it that way.

kriss
vig will always be a negative number, if you use negative numbers the math works out correctly. CalculateSides(140,-20) = -160 which is correct. It's all +'s and -'s, so it really doesn't matter the order you do it in as long as you add the correct sign at the right time.
Mystere Man
I don't think so, or your function is way more broken that I thought ;-). But I indeed made a mistake. I quicly tried the algorithm in python languages overlooking the different semantic for -(newSide <0) (in python I must write 'not (newSide <0)). Hence CalculadeSides(140, -20) is 120 as expected.However, try with CalculateSides(115, -20) and your function give 95.If you want to change calling convention passing 20 instead of -20, no problem, it's your design. Just replace NewSide - vig with NewSide + vig.
kriss
What's going on with the sign is clear for me. At first reading I was sure the program was broken because you were not testing on the right variable (testing newSide instead of side), but with the c#/python confusion I pointed out the wrong error case, CalculatesSides(140, 20) indeed give 120 as expected.
kriss
A: 

The 'sign' solution could be more elegant:

decimal CalculateSides(decimal side, decimal vig)
{
    decimal res = side - vig  +  (100 * Math.Sign(side));
    return  res               +  (100 * Math.Sign(res));
}

please note that your algorithm doesn't apply to your given examples.

vaab