thanks and bugs

Dec 9, 2009 at 5:11 PM

As i posted in "reviews":

"Thank you dude for your library!I've made cool app based on it:

http://zcn.ru/tmp/palc.exe

A calculator similar to the one from the Dos Navigator - old and lovely file manager. Three number representations, no silly buttons and other unnecessary stuff.

My sources: http://zcn.ru/tmp/palc.rar"

Now about those bugs I discovered:

1. division breaks if one of operators is: 

x such as 1>x>-1, i.e. we try to execute this using W3b.Sine.Sample:

1>0.1/1
        Exception during evaluation
        System.IndexOutOfRangeException - Index was outside the bounds of the ar
ray.
           at W3b.Sine.BigNumDec.ToString() in C:\work\w3b\W3b.Sine\BigNumDec.cs
:line 276
           at W3b.Sine.Program.EvaluateExpression(String expression) in C:\work\
w3b\W3b.Sine.Sample\Program.cs:line 186

I suppose this is caused by lines 551 and 552 in BigNumDec.cs. When the number is less than one, the first zero indicating integer part of the number increases digit count by one.

i.e. shifting _exp to 0 causes dividend to become "01". Later that leading zero hurts all.

I solved it by removing those zeroes from both divisor and dividend before shifting radix point:

int ii = divisor.Length - 1;
            while (divisor[ii] == 0)
            {
                divisor._data.RemoveAt(ii);
                ii--;
            }
            ii = dividend.Length - 1;
            while (dividend[ii] == 0)
            {
                dividend._data.RemoveAt(ii);
                ii--;
            }

the second issue:

"0.02/1" will give us "2"

the problem is in "ToString" (BigNumDec.cs, line 260)

radix point occurs to be shifted too far, so this is never occurs:

             if( i + _exp + 1 == 0 ) { // if reached radix point

(line 273, BigNumDec.cs) 

In that condition I manually insert the dot and the zeroes. I.E. I added the following from line 268:

if(_exp<-Length)
            {
                sb.Append('.');
                for (int patch = 0; patch < (-_exp - Length); patch++) sb.Append('0');
            }

 

So, those are two bugs I discovered, though maybe its' reasons are not quite what I think they are.  

And there's one else little thing: expression handling fails if there's more than one dot between operators. Like, the expression "1..2" parsed as "2".

 

This is it. Well, I'd like to thank you again W3b for your library, and for expression handling especially. If you gonna upgrade it further, would u please add bitwise operations, XOR, AND, OR, NOT? ;)

Sergey.

Coordinator
Dec 9, 2009 at 11:27 PM
Edited Dec 9, 2009 at 11:28 PM

Hey there,

Thanks for the feedback and proposed fixes, they'll help a lot (especially as it's been over a year and a half since I last took a proper look at the BigNumDec code, I'm ashamed to say I've forgotten how it all works now). I'll look into submitting some patches over the Christmas holiday.

As for the operations you proposed at the bottom: the following boolean logical operations are already defined:

x AND y == x && y
x OR y == x || y
x XOR y == x ^^ y
NOT x  = !x

These operations only work when both operands are either numeric 1 (true) or 0 (false). Behaviour is undefined when either operand is not a valid value.

Dec 11, 2009 at 10:17 AM

Dont you think it could be useful to turn those logical operations into full fledged bitwise?
I've made conversion routines for that, decimal to hexademical and back, tested it a little, so let me help you with XOR:



        protected override BigNum XOR(BigNum operand2)
        {
            BigNumDec a = this;
            BigNumDec b = (BigNumDec)operand2;
            if((a._exp<0)||(b._exp<0))throw new FormatException("XOR requires integer operands");
            List<byte> ah=dec2hex(a._data);
            List<byte> bh = dec2hex(b._data);
            if (ah.Count > bh.Count)
            {
                for (int x = 0; x < bh.Count; x++)
                    ah[x] ^= bh[x];
                b._data = hex2dec(ah);
            }
            else
            {
                for (int x = 0; x < ah.Count; x++)
                    bh[x] ^= ah[x];
                b._data = hex2dec(bh);
            }
            return b;
        }

/********************* dec2hex ***********************/
        static List<List<uint>> bht2 = new List<List<uint>>();
        static List<byte> dec2hex(List<SByte> x)
        {
            int i;
            int di = x.Count;
            CalcDec2HexTableUpTo(di);
            List<uint> r = new List<uint>();
            for (i = 0; i < di; i++)
            {
                for (int j = 0; j < (x[i]); j++) addhecks2(i, ref r);
            }
            List<byte> hb = new List<byte>();
            for (i = 0; i < r.Count; i++)
            {
                hb.Add((byte)(r[i] >> 0));
                hb.Add((byte)(r[i] >> 8));
                hb.Add((byte)(r[i] >> 16));
                hb.Add((byte)(r[i] >> 24));
            }
            return hb;
        }
        static void CalcDec2HexTableUpTo(int y)
        {

            if (bht2.Count == 0)
            {
                List<uint> L = new List<uint>();
                L.Add(1);
                bht2.Add(L);
            }

            int x = bht2.Count;
            for (; x < y + 1; x++)
            {
                List<uint> L = new List<uint>();
                bht2.Add(L);
                bht2[x] = mult10(bht2[x - 1]);
            }
        }
        static void addhecks2(int n, ref List<uint> L)
        {
            int x;
            ulong res;
            uint c = 0;
            for (x = L.Count; x < bht2[n].Count; x++)
                L.Add(0);
            int len = L.Count;
            for (x = 0; x < len; x++)
            {


                if (bht2[n].Count > x)
                    res = (ulong)L[x] + bht2[n][x] + c;
                else
                    res = (ulong)L[x] + c;
                L[x] = (uint)res;
                c = (uint)(res >> 32);
            }
            if (c != 0)
            {
                L.Add(c);
            }
        }
        static List<uint> mult10(List<uint> src)
        {
            int x;
            List<uint> dst = new List<uint>();

            for (x = 0; x < src.Count; x++)
                dst.Add(0);
            ulong res;
            uint carry = 0;
            for (x = 0; x < dst.Count; x++)
            {
                res = (ulong)src[x] * 10 + carry;
                dst[x] = (uint)res;
                carry = (uint)((ulong)(res) >> 32);
            }
            if (carry > 0)
            {
                dst.Add(carry);
            }
            return dst;
        }
/********************* hex2dec ***********************/
        static List<sbyte> hex2dec(List<Byte> b)
        {
            List<sbyte> res = new List<sbyte>();
            int len = b.Count;
            List<byte> pow2 = new List<byte>();
            List<byte> resb = new List<byte>();
            pow2.Add(1);
            int x;
            int num;
            for (x = 0; x < len; x++)
            {
                num = b[x] % 16;
                for (int y = 0; y < num; y++)
                {
                    addbint(ref resb, ref pow2);
                }
                mult16(ref pow2);

                num = b[x] / 16;
                for (int y = 0; y < num; y++)
                {
                    addbint(ref resb, ref pow2);
                }
                mult16(ref pow2);
            }
            for (x = 0; x < resb.Count; x++)
            {
                if (resb[resb.Count - x - 1] != 0) break;
            }
            len = resb.Count - x;
            for (x = 0; x < len; x++)
                res.Add((sbyte)resb[x]);
            return res;
        }
        static void mult16(ref List<byte> a)
        {
            int x;
            int res;
            int c = 0;
            for (x = 0; x < a.Count; x++)
            {
                res = a[x] * 4 + c;
                a[x] = (byte)(res % 10);
                c = res / 10;
            }
            if (c != 0) a.Add((byte)c);
            c = 0;
            for (x = 0; x < a.Count; x++)
            {
                res = a[x] *4 + c;
                a[x] = (byte)(res % 10);
                c = res / 10;
            }
            if (c != 0) a.Add((byte)c);
        }
        static void addbint(ref List<byte> b, ref List<byte> a)
        {
            int x;
            int res;
            int c = 0;
            for (x = b.Count;x < a.Count; x++)
                b.Add(0);
            for (x = 0; x < b.Count; x++)
            {
                if(a.Count>x)
                    res = (a[x] + b[x] + c);
                else
                    res = (b[x] + c);
                b[x] = (byte)(res % 10);
                c = res / 10;
            }
            if (c != 0)
                b.Add((byte)c);
        }



will that help?

Jan 8, 2012 at 4:32 AM

The BigNumDec.Subtract method can return a result with multiple leading zeroes.  This breaks the comparison operators.

  prec.ToString "0.00000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 
  Base.ToString "12345678987654321" 
  Test.tostring "12345678987654321.00000000000000000000000000000000000000000000000000000000000000000023834098950110192137166820000000000000000000000000000000000000000000000000000000000115033015464703892842429343054761"
Diff = BigNumDec.Subtract(Test, Base)
  Diff.Tostring "00000000000000000.00000000000000000000000000000000000000000000000000000000000000000023834098950110192137166820000000000000000000000000000000000000000000000000000000000115033015464703892842429343054761" 
Loop Until Diff < Prec
  diff < Prec False 

  prec.ToString "0.00000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 
  Base.ToString "12345678987654321" String
  Test.tostring "12345678987654321.00000000000000000000000010848928695462042036189410913805651783624392026389405334100268432944848201988435033324843558274348874639541420511106110431684603325101054864001507475186926564" 
Diff = BigNumDec.Subtract(Test, Base)
  Diff.Tostring "0.0000000000000000000000001084892869546204203618941091380565178362439202638940533410026843294484820198843503332484355827434887463954142051110611043168460332510105486400150747518692656400"
Loop Until Diff < Prec
  diff < Prec True 

CompareTo suffers from the same problem, but also seems to have issues of its own.