Help optimizing algorithm - c#

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.

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.

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
change mode from 100base to 0base
compute in zero base
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.

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.

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.

Related

Dividing prices by 3

For accounting program I need to divide a price by 3 so it can be shared over 3 months
For example 9€
3€ first month
3€ second month
3€ third month
Now this would be price/3
But what if the number is 10?
3,33€ first month
3,33€ second month
3,33€ last month
3,33€*3 =€9.99
One cent has gone missing.
How can I make it so the ouput would become 3,33€ , 3,33€ , 3,34€?
You need to ask the accountant what they would want here. That's an important thing to do in software development: ask the users.
Normally, for stability, you would subtract the amounts paid from a balance account, and put checks in to ensure that the balance falls to zero.
And don't ever use a floating point data type when building accounting software. Floating point precision will bite you. Use a currency type instead.
You could set the last by making up the difference, instead of via the same calculation as the rest. In pseudocode:
normalMonthPrice = RoundToTwoPlaces(totalPrice / months);
lastMonthPrice = totalPrice - (normalMonthPrice * (months - 1));
As Bathsheba said, ask your users first.
Here's a technique that I've used often in such scenarios. This method will ensure the most even distribution, with the upward bias toward the end. For example, if you call DivvyUp(101, 3), you'll get 33.66, 33.67, 33.67. Notice that the difference isn't just made up for at the end. Instead, each value is computed according to what's left, not what was started with.
public static double[] DivvyUp(double total, uint count)
{
var parts = new double[count];
for (var i = 0; i < count; ++i)
{
var part = Math.Truncate((100d * total) / (count - i)) / 100d;
parts[i] = part;
total -= part;
}
return parts;
}
Congratulations, you've found out why the computing world isn't as simple as "put math on it"-
The easiest solution would be to divide by 3, round to two decimal places, and use that value for the first two months, and original - 2 * perMonth for the rest.

Using the mod operator to decrease value in a textbox

Okay so I have created this vending machine application form and I am having problems getting rid of the change. The machine has 50 10p's in at the start of the day. A fizzy drink costs 40p, so, if the user puts in 50p, he will get change back of 10p. I have a textbox showing the amount of 10p's in the machine, so at the start, 50, after he puts in 50p it will be 55. However, now that he has to get 10p change (I have a release change button), I want the amount of 10p's in the textbox to go to 54...any ideas? I tried using the mod operator but wasn't sure how to use it:
decimal change = decimal.Parse(txtChange.Text)
if (change % 10 > 1)
{
int tenPenny = int.Parse(txt_BoxTenPenny.Text);
int totalTenPen = tenPenny - 1;
txt_BoxTenPenny.Text = totalTenPen.ToString();
}
I know this isn't right, when I was doing research, they were using the % operator and using the number 10 as the numerator..so..I got a bit lost. Any suggestions would be great!
If you're trying to determine how many 10 pennies the user is owed, this is calculated using:
int tenPennies = change / 10
As opposed to the modulus (%) operator, so:
decimal change = decimal.Parse(txtChange.Text)
int tenPenny = int.Parse(txt_BoxTenPenny.Text);
int totalTenPen = tenPenny - change / 10 ;
txt_BoxTenPenny.Text = totalTenPen.ToString();
Hope that helps!
Something like that:
decimal change = decimal.Parse(txtChange.Text)
if (change % 10 > 0)
{
int tenPenny = int.Parse(txt_BoxTenPenny.Text);
int totalTenPen = tenPenny - (change % 10);
txt_BoxTenPenny.Text = totalTenPen.ToString();
}
But is supposed that before that, you have added the 50p the users puts into machine in the txt_BoxTenPenny.
The modulo operator (%) returns the remainder of a division operation. For example, 23 MOD 10 = 3.
In this case I believe you want integer division, or the Floor. That is, you want to divide and throw away the remainder.
Since you are using decimal, I presume change will contain 0.10 for 10p. In that case, try the following:
//calculate the number of 10p coins you will get for change
var tenPenniesChange = (int)Math.Floor(change / 0.10m);
if(tenPenniesChange > 0)
txt_BoxTenPenny.Text = (int.Parse(txt_BoxTenPenny.Text) - tenPenniesChange).ToString();
change -= tenPenniesChange * 0.10;
Note the use of the Math.Floor function. If you had change = 0.13 you will get tenPenniesChange = 1. After the subtraction, you will then get change = 0.03.
This may be of some use:
Issuing vending machine change: Using C# to recursively build and search a tree

MMMMMMSS what kind of a time duration format is this?

i have a file which states duration for a particular event in format MMMMMMSS.Does any one know what kind of format is this for time duration and how to convert it into seconds.I'm using C# language
If the format is really M...MSS (supplied as an integer value), converting it to seconds is quite easy:
var seconds = (value / 100) * 60 + (value % 100);
Why does it work?
value / 100 removes the last two digits (integer division), thus returning MMMMMM, and
value % 100 returns the last two digits (modulo), i.e., SS.
The remainder of the formula is MMMMMM * 60 + SS, which should be pretty self-explanatory.
My guess based on the format is that it could hold a maximum value of 99999959, which would mean 999999 minutes and 59 seconds. But that is pure conjecture, and some sample data would help to bolster this idea. You may never know for certain though.
You should at least be able to determine whether the SS part ever exceeds 59 or not, which would be very important to know.
var input = "02345612";
int minutes = int.Parse(input.Substring(0, 6));
int seconds = int.Parse(input.Substring(6, 2));
int totalSeconds = minutes * 60 + seconds;

Python math add each number together

I did a math problem today and first attempted it in Python but after getting the wrong answer I used C#. Basically I was to add up all the digits a long number (2^1000). The sum of these digits was the answer. Here is my python script:
#! /usr/bin/env python3
n = 2**1000
count = 0
while (n > 0):
count += n % 10
n = (int)(n/10)
print (count)
This script gives the result 1189. Essentially I'm adding the last digit of the number to count, then removing it from the number and repeating the process. Here is similar code in C#:
//Yes this string is the same output from 2^1000. I had python write the string to file for me.
String str = "10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376";
Int32 answer = 0;
foreach (char c in str)
{
answer += (Convert.ToInt32(c) - 48);
}
lblOutput.Text = answer.ToString();
C# gives the output: 1366 which is the correct answer. I'm just curious as to why my python script gets the wrong answer. Am I looking at the math in the wrong way?
Just do this:
n = 2 ** 1000
count = 0
while n > 0:
count += n % 10
n //= 10
print(count)
Why your code goes wrong is because (int)(n/10) first converts n to a double, divides it by 10 and then truncates. Rounding errors are easily made in this process. In Python 3.X // is used for integer division.
Oh and finally, (int)(n / 10) is a very bad style, we don't use C-style casts in Python. You create a int() object, so you use int(n / 10). This is error prone thanks to rounding errors, so use integer division instead: n // 10. And since we are doing n = n // 10 we can write n //= 10.
Use integer division.
n = n//10
By truncating after, you're losing very large fractions of 1 many times.
I know that this question is really old but after reading over it I couldn't seem to understand the code and felt it was too hard for beginners to understand so I made a more 'noob-friendly' version using a list:
n=2**1000
thelist=list(map(int, str(n)))
counter=0
for x in range(0,len(thelist)):
counter+=thelist[x]
print(counter)
(i understand that this is less efficient btw)

Modular Cubes in C#

I am have difficulties solving this problem:
For a positive number n, define C(n)
as the number of the integers x, for
which 1 < x < n and x^3 = 1 mod n.
When n=91, there are 8 possible values
for x, namely : 9, 16, 22, 29, 53, 74,
79, 81. Thus, C(91)=8.
Find the sum of the positive numbers
n <= 10^11 for which C(n) = 242.
My Code:
double intCount2 = 91;
double intHolder = 0;
for (int i = 0; i <= intCount2; i++)
{
if ((Math.Pow(i, 3) - 1) % intCount2 == 0)
{
if ((Math.Pow(i, 3) - 1) != 0)
{
Console.WriteLine(i);
intHolder += i;
}
}
}
Console.WriteLine("Answer = " + intHolder);
Console.ReadLine();
This works for 91 but when I put in any large number with a lot of 0's, it gives me a lot of answers I know are false. I think this is because it is so close to 0 that it just rounds to 0. Is there any way to see if something is precisely 0? Or is my logic wrong?
I know I need some optimization to get this to provide a timely answer but I am just trying to get it to produce correct answers.
Let me generalize your questions to two questions:
1) What specifically is wrong with this program?
2) How do I figure out where a problem is in a program?
Others have already answered the first part, but to sum up:
Problem #1: Math.Pow uses double-precision floating point numbers, which are only accurate to about 15 decimal places. They are unsuitable for doing problems that require perfect accuracy involving large integers. If you try to compute, say, 1000000000000000000 - 1, in doubles, you'll get 1000000000000000000, which is an accurate answer to 15 decimal places; that's all we guarantee. If you need a perfectly accurate answer for working on large numbers, use longs for results less than about 10 billion billion, or the large integer mathematics class in System.Numerics that will ship with the next version of the framework.
Problem #2: There are far more efficient ways to compute modular exponents that do not involve generating huge numbers; use them.
However, what we've got here is a "give a man a fish" situation. What would be better is to teach you how to fish; learn how to debug a program using the debugger.
If I had to debug this program the first thing I would do is rewrite it so that every step along the way was stored in a local variable:
double intCount2 = 91;
double intHolder = 0;
for (int i = 0; i <= intCount2; i++)
{
double cube = Math.Pow(i, 3) - 1;
double remainder = cube % intCount2;
if (remainder == 0)
{
if (cube != 0)
{
Console.WriteLine(i);
intHolder += i;
}
}
}
Now step through it in the debugger with an example where you know the answer is wrong, and look for places where your assumptions are violated. If you do so, you'll quickly discover that 1000000 cubed minus 1 is not 99999999999999999, but rather 1000000000000000000.
So that's advice #1: write the code so that it is easy to step through in the debugger, and examine every step looking for the one that seems wrong.
Advice #2: Pay attention to quiet nagging doubts. When something looks dodgy or there's a bit you don't understand, investigate it until you do understand it.
Wikipedia has an article on Modular exponentiation that you may find informative. IIRC, Python has it built in. C# does not, so you'll need to implement it yourself.
Don't compute powers modulo n using Math.Pow; you are likely to experience overflow issues among other possible issues. Instead, you should compute them from first principles. Thus, to compute the cube of an integer i modulo n first reduce i modulo n to some integer j so that i is congruent to j modulo n and 0 <= j < n. Then iteratively multiply by j and reduce modulo n after each multiplication; to compute a cube you would perform this step twice. Of course, that's the native approach but you can make this more efficient by following the classic algorithm for exponentiation by using exponentiation by squaring.
Also, as far as efficiency, I note that you are unnecessarily computing Math.Pow(i, 3) - 1 twice. Thus, at a minimum, replace
if ((Math.Pow(i, 3) - 1) % intCount2 == 0) {
if ((Math.Pow(i, 3) - 1) != 0) {
Console.WriteLine(i);
intHolder += i;
}
}
with
int cubed = Math.Pow(i, 3) - 1;
if((cubed % intCount2 == 0) && (cubed != 0)) {
Console.WriteLine(i);
intHolder += i;
}
Well, there's something missing or a typo...
"intHolder1" should presumably be "intHolder" and for intCount2=91 to result in 8 the increment line should be:-
intHolder ++;
I don't have a solution to your problem, but here's just a piece of advice :
Don't use floating point numbers for calculations that only involve integers... Type int (Int32) is clearly not big enough for your needs, but long (Int64) should be enough : the biggest number you will have to manipulate will be (10 ^ 11 - 1) ^ 3, which is less than 10 ^ 14, which is definitely less than Int64.MaxValue. Benefits :
you do all your calculations with 64-bit integers, which should be pretty efficient on a 64-bit processor
all the results of your calculations are exact, since there are no approximations due the internal representation of doubles
Don't use Math.Pow to calculate the cube of an integer... x*x*x is just as simple, and more efficient since it doesn't need a conversion to/from double. Anyway, I'm not very good at math, but you probably don't need to calculate x^3... check the links about modular exponentiation in other answers

Categories