0

I'm looking for a way to shift a bit from a positive fixnum into the sign position. Basically, what I want is a predictable (not undefined) way to perform a fixnum left shift without overflow checks.

An inefficient implementation looks like this:

(define shift-left
  (lambda (value shift)
    (let ([unsigned-to-signed
       (lambda (value width)
         (let* ([sign-mask (bitwise-arithmetic-shift-left
                1 (- width 1))]
            [sign (bitwise-and value sign-mask)])
           (bitwise-ior
        (bitwise-bit-field value 0 width)
        (- sign))))])
      (unsigned-to-signed
       (bitwise-arithmetic-shift-left value shift)
       (fixnum-width)))))

(shift-left 1 59) ⇒ 576460752303423488
(shift-left 1 60) ⇒ -1152921504606846976
(shift-left 1 61) ⇒ 0

Ideally, this would compile down to a single CPU instruction (at least for constant shifts; CPUs differ in the way treat shifts as wide as the register or wider).

Florian Weimer
  • 32,022
  • 3
  • 48
  • 92
  • You have no guarentee a number is a fixnum or that it stores the sign as it's msb. R6RS will automatically make more room for a higher number as you add 1 to it. – Sylwester Nov 17 '20 at 23:44
  • I do not think that this matters. The R6RS libraries have `(fixnum-width)` and the fixnum operations require two's complement, so the behavior of the procedure would be well-defined. – Florian Weimer Nov 18 '20 at 05:22
  • This probably doesn't help but in Racket I think what you want is `unsafe-fxlshift` which comes from `racket/unsafe/ops`. –  Nov 18 '20 at 14:42

1 Answers1

0

IN scheme it won't work unless you look for implementation defined features.

In scheme it's standardized the tower of arithmetic types which makes very inconvenient for you to control the inner sides of number representations.

What you try to do makes sense only if you understand the internals of some implementation, otherwise you waste your time.

alinsoar
  • 15,386
  • 4
  • 57
  • 74