Example #1
0
        // Verify that a given 'step_move' matches the actual step times
        int check_line(ref step_move move)
        {
            if (!Stepcompress.CHECK_LINES)
            {
                return(0);
            }
            if (move.count == 0 || (move.interval == 0 && move.add == 0 && move.count > 1) || move.interval >= 0x80000000)
            {
                //errorf("stepcompress o=%d i=%d c=%d a=%d: Invalid sequence"
                //		 , sc->oid, move.interval, move.count, move.add);
                return(Stepcompress.ERROR_RET);
            }
            uint   interval = move.interval, p = 0;
            ushort i;

            for (i = 0; i < move.count; i++)
            {
                points point = minmax_point(queue_pos + i);
                p += interval;
                if (p < point.minp || p > point.maxp)
                {
                    //errorf("stepcompress o=%d i=%d c=%d a=%d: Point %d: %d not in %d:%d"
                    //		 , sc.oid, move.interval, move.count, move.add
                    //		 , i + 1, p, point.minp, point.maxp);
                    return(Stepcompress.ERROR_RET);
                }
                if (interval >= 0x80000000)
                {
                    //errorf("stepcompress o=%d i=%d c=%d a=%d:"+
                    //		 " Point %d: interval overflow %d"
                    //		 , sc.oid, move.interval, move.count, move.add
                    //		 , i + 1, interval);
                    return(Stepcompress.ERROR_RET);
                }
                interval += (ushort)move.add;
            }
            return(0);
        }
Example #2
0
        // Find a 'step_move' that covers a series of step times
        step_move compress_bisect_add()
        {
            uint *qlast = queue_next;

            if (qlast > queue_pos + 65535)
            {
                qlast = queue_pos + 65535;
            }
            points point = minmax_point(queue_pos);
            int    outer_mininterval = point.minp, outer_maxinterval = point.maxp;
            int    add = 0, minadd = -0x8000, maxadd = 0x7fff;
            int    bestinterval = 0, bestcount = 1, bestadd = 1, bestreach = int.MinValue;
            int    zerointerval = 0, zerocount = 0;

            int count, addfactor, nextaddfactor, c;

            while (true)
            {
                // Find longest valid sequence with the given 'add'
                points nextpoint;
                int    nextmininterval = outer_mininterval;
                int    nextmaxinterval = outer_maxinterval, interval = nextmaxinterval;
                int    nextcount = 1;
                for (; ;)
                {
                    nextcount++;
                    if (&queue_pos[nextcount - 1] >= qlast)
                    {
                        count = nextcount - 1;
                        return(new step_move((uint)interval, (ushort)count, (short)add));
                    }
                    nextpoint     = minmax_point(queue_pos + nextcount - 1);
                    nextaddfactor = nextcount * (nextcount - 1) / 2;
                    c             = add * nextaddfactor;
                    if (nextmininterval * nextcount < nextpoint.minp - c)
                    {
                        nextmininterval = Stepcompress.DIV_ROUND_UP(nextpoint.minp - c, nextcount);
                    }
                    if (nextmaxinterval * nextcount > nextpoint.maxp - c)
                    {
                        nextmaxinterval = (nextpoint.maxp - c) / nextcount;
                    }
                    if (nextmininterval > nextmaxinterval)
                    {
                        break;
                    }
                    interval = nextmaxinterval;
                }

                // Check if this is the best sequence found so far
                count     = nextcount - 1;
                addfactor = count * (count - 1) / 2;
                int reach = add * addfactor + interval * count;
                if (reach > bestreach ||
                    (reach == bestreach && interval > bestinterval))
                {
                    bestinterval = interval;
                    bestcount    = count;
                    bestadd      = add;
                    bestreach    = reach;
                    if (add == 0)
                    {
                        zerointerval = interval;
                        zerocount    = count;
                    }
                    if (count > 0x200)
                    {
                        // No 'add' will improve sequence; avoid integer overflow
                        break;
                    }
                }

                // Check if a greater or lesser add could extend the sequence
                nextaddfactor = nextcount * (nextcount - 1) / 2;
                int nextreach = add * nextaddfactor + interval * nextcount;
                if (nextreach < nextpoint.minp)
                {
                    minadd            = add + 1;
                    outer_maxinterval = nextmaxinterval;
                }
                else
                {
                    maxadd            = add - 1;
                    outer_mininterval = nextmininterval;
                }

                // The maximum valid deviation between two quadratic sequences
                // can be calculated and used to further limit the add range.
                if (count > 1)
                {
                    int errdelta = (int)max_error * Stepcompress.QUADRATIC_DEV / (count * count);
                    if (minadd < add - errdelta)
                    {
                        minadd = add - errdelta;
                    }
                    if (maxadd > add + errdelta)
                    {
                        maxadd = add + errdelta;
                    }
                }

                // See if next point would further limit the add range
                c = outer_maxinterval * nextcount;
                if (minadd * nextaddfactor < nextpoint.minp - c)
                {
                    minadd = Stepcompress.idiv_up(nextpoint.minp - c, nextaddfactor);
                }
                c = outer_mininterval * nextcount;
                if (maxadd * nextaddfactor > nextpoint.maxp - c)
                {
                    maxadd = Stepcompress.idiv_down(nextpoint.maxp - c, nextaddfactor);
                }

                // Bisect valid add range and try again with new 'add'
                if (minadd > maxadd)
                {
                    break;
                }
                add = maxadd - (maxadd - minadd) / 4;
            }
            if (zerocount + zerocount / 16 >= bestcount)
            {
                // Prefer add=0 if it's similar to the best found sequence
                return(new step_move((uint)zerointerval, (ushort)zerocount, 0));
            }
            return(new step_move((uint)bestinterval, (ushort)bestcount, (short)bestadd));
        }