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
BigNumber
s. - Add some support for Linq (would that even work for
Sum
?)
Any other suggestions?
System.Numerics.BigInteger
? \$\endgroup\$