Lisp HUG Maillist Archive

Fastest way to turn 4 bytes into a 32 bit number?


I have 4 bytes, each 8 bits long.  I wish to turn these into a single
32 bit number.  What's the fastest way to do that in LispWorks on
Linux?

I tried a number of different approaches and looked at the disassemble
output and ran some micro benchmarks and the best I could come up with
is the PACK-4-BYTES-V0¨function below.  Is there a better way?

There are some other versions below for your entertainment.

Thanks for any tips you might have,
Chris Dean


(defun pack-4-bytes-v0 (b0 b1 b2 b3)
  (declare (optimize (speed 3) (debug 0) (space 0) (safety 0)
                     (hcl:fixnum-safety 0)
                     (compilation-speed 0))
           (type (unsigned-byte 8) b0 b1 b2 b3))
  (the (unsigned-byte 32) 
    (logior (ash b0 24)
            (ash b1 16)
            (ash b2 8)
            b3)))

(defun pack-4-bytes-v1 (b0 b1 b2 b3)
  (declare (optimize (speed 3) (debug 0) (space 0) (safety 0)
                     (hcl:fixnum-safety 0)
                     (compilation-speed 0))
           (type (unsigned-byte 8) b0 b1 b2 b3))
  (ldb (byte 32 0) 
       (logior (ash b0 24)
               (ash b1 16)
               (ash b2 8)
               b3)))

(defun pack-4-bytes-v2 (b0 b1 b2 b3)
  (declare (optimize (speed 3) (debug 0) (space 0) (safety 0)
                     (hcl:fixnum-safety 0)
                     (compilation-speed 0))
           (type (unsigned-byte 8) b0 b1 b2 b3))
  (let ((res 0))
    (declare (type (unsigned-byte 32) res))
    (setf (ldb (byte 8 24) res) b0
          (ldb (byte 8 16) res) b1
          (ldb (byte 8  8) res) b2
          (ldb (byte 8  0) res) b3)
    res))


Re: Fastest way to turn 4 bytes into a 32 bit number?

>>>>> On Thu, 11 May 2006 12:04:17 -0700, Chris Dean <ctdean@sokitomi.com> said:
> 
> I have 4 bytes, each 8 bits long.  I wish to turn these into a single
> 32 bit number.  What's the fastest way to do that in LispWorks on
> Linux?
> 
> I tried a number of different approaches and looked at the disassemble
> output and ran some micro benchmarks and the best I could come up with
> is the PACK-4-BYTES-V0¨function below.  Is there a better way?

Beware fixnum-safety 0 -- PACK-4-BYTES-V0 is only fastest because it doesn't
do all the work :-)  The intermediate ash results are not fixnums.

I suspect something like below might be the fastest, because it can safely
compute two 16 bit quuantities as fixnums.

(defun pack-4-bytes-v3 (b0 b1 b2 b3)
  (declare (optimize (speed 3) (debug 0) (space 0) (safety 0)
                     (compilation-speed 0))
           (type (unsigned-byte 8) b0 b1 b2 b3))
  (logior (the (unsigned-byte 32)
               (ash (logior (the (unsigned-byte 16) (ash b0 8)) b1) 16))
	  (logior (the (unsigned-byte 16) (ash b2 8)) b3)))

(defun pack-4-bytes-v4 (b0 b1 b2 b3)
  (declare (optimize (speed 3) (debug 0) (space 0) (safety 0)
                     (compilation-speed 0))
           (type (unsigned-byte 8) b0 b1 b2 b3))
  (dpb (logior (the (unsigned-byte 16) (ash b0 8)) b1) (byte 16 16)
       (logior (the (unsigned-byte 16) (ash b2 8)) b3)))


> 
> There are some other versions below for your entertainment.
> 
> Thanks for any tips you might have,
> Chris Dean
> 
> 
> (defun pack-4-bytes-v0 (b0 b1 b2 b3)
>   (declare (optimize (speed 3) (debug 0) (space 0) (safety 0)
>                      (hcl:fixnum-safety 0)
>                      (compilation-speed 0))
>            (type (unsigned-byte 8) b0 b1 b2 b3))
>   (the (unsigned-byte 32) 
>     (logior (ash b0 24)
>             (ash b1 16)
>             (ash b2 8)
>             b3)))
> 
> (defun pack-4-bytes-v1 (b0 b1 b2 b3)
>   (declare (optimize (speed 3) (debug 0) (space 0) (safety 0)
>                      (hcl:fixnum-safety 0)
>                      (compilation-speed 0))
>            (type (unsigned-byte 8) b0 b1 b2 b3))
>   (ldb (byte 32 0) 
>        (logior (ash b0 24)
>                (ash b1 16)
>                (ash b2 8)
>                b3)))
> 
> (defun pack-4-bytes-v2 (b0 b1 b2 b3)
>   (declare (optimize (speed 3) (debug 0) (space 0) (safety 0)
>                      (hcl:fixnum-safety 0)
>                      (compilation-speed 0))
>            (type (unsigned-byte 8) b0 b1 b2 b3))
>   (let ((res 0))
>     (declare (type (unsigned-byte 32) res))
>     (setf (ldb (byte 8 24) res) b0
>           (ldb (byte 8 16) res) b1
>           (ldb (byte 8  8) res) b2
>           (ldb (byte 8  0) res) b3)
>     res))
> 

__Martin


Re: Fastest way to turn 4 bytes into a 32 bit number?


Martin Simmons <martin@lispworks.com> writes:
> Beware fixnum-safety 0 -- PACK-4-BYTES-V0 is only fastest because it doesn't
> do all the work :-)  

Good catch!  I eventually figured that out after a while :).

> The intermediate ash results are not fixnums.
>
> I suspect something like below might be the fastest, because it can
> safely compute two 16 bit quantities as fixnums.

Great, thanks - I'll use a variant of the ones below.

Regards,
Chris Dean


Updated at: 2020-12-10 08:48 UTC