0

I'm stumped on this right now, and I don't know why it's happening. In this class, I have a function that loops over all the numbers before a decimal point to cull extra zeroes off the end, and does it for the numbers after the decimal point as well. The second part (removing the extra zeroes before the decimal point) works fine, but the first part (removing the extra zeroes after the decimal point) doesn't.

I have to call the function multiple times for it to cull all of the extra zeroes on the right-hand end of the number, and I don't know why. I suspect it might have something to do with checking whether a byte is == 0, but I'm not sure yet.

FYI: The function is called in the constructor at the very end.

public class GiantNumber
{
    //constructor and some other functions...

    public bool IsNegative { get; }
    public bool HasDecimal { get; }
    public List<byte> NumbersBeforeDecimal;
    public List<byte> NumbersAfterDecimal;

    public void CullZeroes()
    {
        for (int i = 0; i < NumbersBeforeDecimal.Count; i++)
        {
            byte number = NumbersBeforeDecimal[i];

            if (number == 0)
            {
                NumbersBeforeDecimal.RemoveAt(i);
            }
            else
            {
                break;
            }
        }

        for (int i = NumbersAfterDecimal.Count - 1; i >= 0; i--)
        {
            byte number = NumbersAfterDecimal[i];

            if (number == 0)
            {
                NumbersAfterDecimal.RemoveAt(i);
            }
            else
            {
                break;
            }
        }
    }
}
  • 5
    The problem is `NumbersBeforeDecimal.RemoveAt(i)` removes the current element, while `i` is still incremented. So the next iteration would check not the next element but the one after it. – Alex Skalozub Feb 22 '20 at 23:34
  • 1
    Loop backwards! [Possible to modify a List while iterating through it?](https://stackoverflow.com/questions/17767161/possible-to-modify-a-list-while-iterating-through-it) (dupe) – Ňɏssa Pøngjǣrdenlarp Feb 22 '20 at 23:34
  • Oh ok, that makes sense! I kind of want to only remove the zeroes at the beginning (before there are significant figures), so do you have any suggestions to this? Edit: What if I just leave the iterator in the for loop blank? Edit #2: It works if I leave it blank! – Christopher Tan Feb 22 '20 at 23:40
  • 1
    The dumb way is something like `while (NumbersBeforeDecimal.Count > 1 && NumbersBeforeDecimal[0] == 0) NumbersBeforeDecimal.RemoveAt(0);`. Better way is to find index of the first non-zero and then remove entire range from 0 to that index. The best way is not to store big numbers that way at all. – Alex Skalozub Feb 22 '20 at 23:46
  • The reason I want to store big numbers this way is because I want to have an equivalent to BigInteger but with decimal values; in fact, I'm using two BigIntegers to do operations. I don't really care too much about performance here since this is just a hobby project in which I want to calculate Euler's Number to as precise of a number as I can. – Christopher Tan Feb 23 '20 at 00:10
  • You can store your number as `BigInteger` value and `int` exponent, so that `x = n * 10^-e`. Then multiplication of your numbers would be simply multiplication of `BigInteger`s and addition of exponents, and addition would be addition of `BigInteger`s where one of the values is multiplied by the difference between exponents. – Alex Skalozub Feb 23 '20 at 00:19
  • BTW, there’s existing [BigRational](https://github.com/microsoftarchive/bcl/blob/master/Libraries/BigRational/BigRationalLibrary/BigRational.cs) implementation, so you may want to use it. – Alex Skalozub Feb 23 '20 at 00:31
  • Oh, thank you for the BigRational post! I will definitely be using that now. – Christopher Tan Feb 23 '20 at 00:58

2 Answers2

1

I figured this out with the help of Ňɏssa Pøngjǣrdenlarp; since I'm deleting the index and iterating over the next one, I'm skipping an index every time I loop. If I leave the iterator blank:

for (int i = 0; i < NumbersBeforeDecimal.Count; )
{
    //stuff
}

It won't skip over lines! This could be a better idea compared to iterating backwards when you want simpler code (in my case it's a lot better).

1

You should not do that this way at all. RemoveAt is O(n), that means, that removing 10M digits would take roughly half an hour. It is about half an hour more than is really needed, as it can be done in miliseconds. You can remove the whole range in one step:

int j = 0;
while (j < NumbersBeforeDecimal.Count 
        && NumbersBeforeDecimal[j] == 0)
{
    ++j;
}
NumbersBeforeDecimal.RemoveRange(0, j);
Antonín Lejsek
  • 6,003
  • 2
  • 16
  • 18