Write a function accepting a natural number n and returning the smallest number larger than n having the same number of one bits.
$ cat slp.rkt #lang racket (require srfi/1) (define (explode n) ; Return a list of bits in the given natural number in little-endian order ; (lsb leftmost) and a trailing zero bit appended. (let loop ((n n) (bits '())) (if (zero? n) (reverse (cons 0 bits)) (let-values (((q r) (quotient/remainder n 2))) (loop q (cons r bits)))))) (define (implode bits) ; Return the natural number represented by the give list of bits in ; little-endian order (lsb leftmost). (let loop ((bits bits) (po2 1) (n 0)) (if (null? bits) n (loop (cdr bits) (* po2 2) (+ (* (car bits) po2) n))))) (define (slp n) ; Return the smallest value larger than n with the same number of 1s in its ; binary representation. ; The idea is to find the rightmost 01 bit pair in n (explode make sure such ; a pair exists) and swap them to get 10. This produces n' the smallest ; number larger than n that can be produced by swapping a 01 pair. n' can be ; made smaller but still greater than n by shifting all 1 bits to the right ; of the 01 pair to the right end of the number (shifting 0s in the opposite ; direction). (let count-0s ((bits (explode n)) (zero-count 0)) (if (= (car bits) 0) (count-0s (cdr bits) (+ zero-count 1)) (let count-1s ((bits (cdr bits)) (one-count 1)) (if (= (car bits) 1) (count-1s (cdr bits) (+ one-count 1)) (implode (append (make-list (- one-count 1) 1) (make-list zero-count 0) '(0 1) (cdr bits)))))))) (define (slp-2 n) ; Return the smallest value larger than n with the same number of 1s in its ; binary representation. ; This code is way stupid (a.k.a. super-exponential) , but it's "obviously ; correct" (generate all permutations of an n-bit number with i 1 bits) and ; useful for testing if the numbers don't get too big. (define (swap! v i j) (let ((t (vector-ref v i))) (vector-set! v i (vector-ref v j)) (vector-set! v j t))) (let* ((bits (list->vector (explode n))) (bc (vector-length bits)) (best (expt 2 bc))) (let outer-loop ((i 0)) (if (= i (- bc 1)) (let ((candidate (implode (vector->list bits)))) (when (and (> candidate n) (< candidate best)) (set! best candidate))) (let inner-loop ((j (+ i 1))) (unless (= j bc) (swap! bits i j) (outer-loop (+ i 1)) (swap! bits i j) (outer-loop (+ i 1)) (inner-loop (+ j 1)))))) best)) (require rackunit) (define (count-1s n) (foldr + 0 (explode n))) (do ((i 0 (+ i 1))) ((> i 100) #t) (let ((n (random 1000000000))) (check-eq? n (implode (explode n))))) (do ((i 0 (+ i 1))) ((> i 10) #t) (let* ((n (+ (random (expt 2 8)) 1)) (slp-n (slp n))) (check-eq? slp-n (slp-2 n)) (check-eq? (count-1s slp-n) (count-1s n)) (check-true (> slp-n n)))) $ racket slp.rkt #t #t $