views:

219

answers:

1

Consider a routine that counts by successive divide w/ remainder operations.

Starting with a 64-bit dividend, the routine divides by a constant divisor.
If the remainder is 0, the routine returns.
Otherwise, a new dividend is constructed by multiplying the remainder by 2^32 and adding the integer quotient.

In code:

/// ULong - 64 bit, unsigned 
/// UInt  - 32 bit, unsigned 
const UInt Divisor; 
int TrickyCounter( ULong Dividend)
{
    int count = 0;
    Ulong Quotient;
    UInt Remainder;

    do {
        Quotient = Dividend/Divisor;
        Remainder = Dividend%Divisor;
        assert((Quotient >> 32) == 0);
        count = count + 1;
        Dividend = ((ULong)Remainder << 32) + Quotient;
    } while (Remainder != 0);
    return count;
}

With an arbitrary Divisor, is there a preferably non-iterating method to calculate the necessary Dividend to get the desired count?
For many initial dividends, this seems to quickly hit the "Assert" condition. Would some dividends cause this to loop forever?


If, instead of a count, the routine returns the quotient, can I calculate the Dividend to produce the number I want returned?

Uint TrickyNumber( ULong Dividend, int count)
{
    Ulong Quotient = 0;
    UInt Remainder;

    while (count > 0)
        Quotient = Dividend/Divisor;
        Remainder = Dividend%Divisor;
        assert((Quotient >> 32) == 0);
        count = count - 1;
        Dividend = ((ULong)Remainder << 32) + Quotient;
    } 
    return (UInt)Quotient;
}
+1  A: 

Would some dividends cause this to loop forever?

Dividend = 0x1ffffffffL, Divisor = 2 is a fairly obvious example, and the whole family (Divisor<<32)-1, Divisor are fixed points.

Working from these, many cyclic combinations of initial dividend and divisor can be found, and I'm sure there are more:

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>


size_t tricky_counter( uint64_t dividend, const uint32_t divisor )
{
    const size_t cycle_buffer_size = 1024;
    size_t count = 0;
    uint64_t quotient;
    uint32_t remainder;

    uint64_t pre[cycle_buffer_size];

    do {
        pre[ count % cycle_buffer_size ] = dividend;

        quotient = dividend/divisor;
        remainder = dividend%divisor;

        if ( (quotient >> 32) != 0) {
           printf("quotient: 0x%" PRIx64 "\n", quotient);
        }

        count = count + 1;

        dividend = ((uint64_t)remainder << 32) + quotient;

        for (size_t i = 0; i < count && i<cycle_buffer_size;++i) {
            if (pre[i] == dividend) {
                size_t cycle = 0;

                printf("dividend repeats: \n");

                while (i != count % cycle_buffer_size) {
                    //~ printf("  0x%" PRIx64 " / %" PRId32 " \n", pre[i], divisor);
                    i = (i + 1) % cycle_buffer_size;
                    ++cycle;
                }

                printf("  0x%" PRIx64 " / %" PRId32 "  cycle size %zd \n", dividend, divisor, cycle);

                return 0;
            }
        }

    } while (remainder != 0);

    return count;
}


int main ( void )
{
    for (uint64_t k = 1; k < 256; ++k) 
        for (uint64_t x = 2; x < 1024; ++x) 
            tricky_counter( (x-1 << 32) + 0x01010101L * k, x);    
}
Pete Kirkham