[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