[Ecls-list] Wrong multiplication on 32-bit mazchine

Waldek Hebisch hebisch at math.uni.wroc.pl
Thu Dec 27 16:40:31 UTC 2012


The following code:

(deftype machine-int () '(unsigned-byte 64))

(defun |Qsmuladd| (x y z)
    (the machine-int
         (+ (the machine-int
               (* (the (unsigned-byte 32) x)
                  (the (unsigned-byte 32) y)))
            (the machine-int z))))

compiled as:

(require 'cmp)
(proclaim '(optimize (safety 0)))
(compile-file "comb.lisp" :c-file "f1.c")

gives wrong code:

(load "comb.fas")
> (|Qsmuladd| 4010020 4010020 4010019)

4201821491

while the correct result is 16080264410419.
AFAICS this is due to the following part in C output:

static cl_object L1_qsmuladd_(cl_object V1, cl_object V2, cl_object V3)
{
 const cl_env_ptr cl_env_copy = ecl_process_env();
 cl_object value0;
TTL:
 {
  ecl_ulong_long_t V4;
  V4 = (ecl_to_uint(V1))*(ecl_to_uint(V2));
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  value0 = ecl_make_ulong_long((V4)+(ecl_to_ulong_long(V3)));
  cl_env_copy->nvalues = 1;
  return value0;
 }
}

Above ecl is doing multiplication using 32 bit precision, while
correct result requires 64 bits.  It is nice that ecl tries to
use native C multiplication, however it gets wrong requested
precision.

Ecl is from ecl-12.12.1.tgz tarball, configured using:

./configure --disable-threads --enable-rpath

BTW1: AFAICS code on 64-bit machines is not fully correct, the
critical line beeing:

  V4= (ecl_fix(V1))*(ecl_fix(V2));

however, since ecl fixnum is 64-bit in this case the code
is working.

BTW2: If that matters the 32-bit machine is Raspberry Pi
running Raspbian from October 28.

-- 
                              Waldek Hebisch
hebisch at math.uni.wroc.pl 




More information about the ecl-devel mailing list