I've written some code to solve this problem:
Work out the first ten digits of the sum of the following one-hundred 50-digit numbers.
My solution functions correctly, but I'm having some trouble deciding how I should be handling exceptions, especially with regards to the class's constructor.
I went the route of creating a BigNumber class, even though it's not necessary, as I've never solved a problem involving arbitrary-length numbers before. Here's the class, sans constructors:
class BigNumber
{
public static int MaxComponentValue = 999999999;
public static int MaxComponentDigits = MaxComponentValue.ToString().Length;
public bool Add(string source)
{
List<int> comps = this.SplitIntoComponents(source);
// Not sure about this
if (comps == null)
return false;
this.AllocateComponentSpace(comps.Count);
for (int i = 0; i < comps.Count; i++)
{
int componentSpace = MaxComponentValue - this.components[i];
int amountToCarry = comps[i] - componentSpace;
if (amountToCarry > 0)
{
while (amountToCarry > MaxComponentValue)
{
amountToCarry -= MaxComponentValue + 1;
this.components[i + 1]++;
}
this.components[i] = 0;
this.components[i + 1]++;
this.components[i] += amountToCarry - 1;
}
else
this.components[i] += comps[i];
}
return true;
}
public override string ToString()
{
if (this.components.Count() > 1)
{
StringBuilder output = new StringBuilder();
var activeComponents = this.components.Reverse().SkipWhile(i => i == 0).ToList();
output.Append(activeComponents[0].ToString());
// Skip the first element as we've already added output for it.
foreach (var c in activeComponents.Skip(1))
output.Append(String.Format("{0:000000000}", c));
return output.ToString();
}
return this.components[0].ToString();
}
private List<int> SplitIntoComponents(string source)
{
if (source == null)
throw new ArgumentNullException("source");
List<int> comps = new List<int>();
for (int i = source.Length; i > 0; i -= MaxComponentDigits)
{
string token;
if (i < MaxComponentDigits)
token = source.Substring(0, i);
else
token = source.Substring(i - MaxComponentDigits, MaxComponentDigits);
int comp;
if (int.TryParse(token, out comp))
comps.Add(comp);
else
return null;
}
return comps;
}
private void AllocateComponentSpace(int count)
{
// The + 1 accounts for the possibility that there
// will be an amount to carry over from the last token.
// E.g 99 + 99 would result in the need for two components
// to store the result 198 - the first one for 98 and the second for 1.
if (this.components.Length < count)
Array.Resize(ref this.components, count + 1);
}
private int[] components = new int[1];
}
Problem 1
In the private method SplitIntoComponents, if int.TryParse fails, I'm failing early and returning null. In the Add method, I call SplitIntoComponents, check if it has returned null and then return false to the caller if it has. The consequence of that is the Add method fails early, before modifying the data stored in the BigNumber instance.
I have two questions. Firstly, should SplitIntoComponents be throwing instead of returning null? Secondly, should Add return false to the caller, or should that really be throwing an ArgumentException? I'm thinking SplitIntoComponents should stay as it is and then I should throw from Add.
Problem 2
I want to define a constructor that takes a string argument. This is what I have so far:
public BigNumber(string source)
{
if (source == null)
throw new ArgumentNullException("source");
List<int> comps = this.SplitIntoComponents(source);
if (comps == null)
throw new ArgumentException();
// Not implemented yet
}
In this case, I feel as though I should be throwing the ArgumentException because I'm unable to return anything to the caller. The problem here is obviously the inconsistency between how I'm handling the return value of SplitIntoComponents in the constructor and in the Add method.
Should I opt for that and throw ArgumentException?
General Observations
- I should overload the '+' operator to allow addition of multiple
BigNumbers. - Add some support for Linq (would that even work for
Sum?)
Any other suggestions?
System.Numerics.BigInteger? \$\endgroup\$