bytevectors: Fix IEEE-754 endianness conversion.
authorLudovic Courtès <ludo@gnu.org>
Sat, 21 Apr 2012 21:08:49 +0000 (23:08 +0200)
committerLudovic Courtès <ludo@gnu.org>
Sun, 22 Apr 2012 18:39:33 +0000 (20:39 +0200)
Fixes <http://bugs.gnu.org/11310>.
Reported by Klaus Stehle <klaus.stehle@uni-tuebingen.de>.

* libguile/ieee-754.h: Remove.
* libguile/Makefile.am (noinst_HEADERS): Remove `ieee-754.h'.

* libguile/bytevectors.c (scm_ieee754_float, scm_ieee754_double): New
  unions.
  (float_to_foreign_endianness, float_from_foreign_endianness,
  double_to_foreign_endianness, double_from_foreign_endianness): Rewrite
  in terms of the new unions.

* test-suite/tests/bytevectors.test ("2.8 Operations on IEEE-754
  Representations")["single, little endian", "single, big endian",
  "double, little endian", "double, big endian"]: New tests.

libguile/Makefile.am
libguile/bytevectors.c
libguile/ieee-754.h [deleted file]
test-suite/tests/bytevectors.test

index be430bf..25cbba7 100644 (file)
@@ -448,7 +448,6 @@ install-exec-hook:
 ## Perhaps we can deal with them normally once the merge seems to be
 ## working.
 noinst_HEADERS = conv-integer.i.c conv-uinteger.i.c            \
-                 ieee-754.h                                    \
                  srfi-14.i.c                                   \
                  quicksort.i.c                                  \
                  win32-uname.h win32-socket.h                  \
index dc326f5..cf41f2f 100644 (file)
@@ -31,7 +31,6 @@
 #include "libguile/bytevectors.h"
 #include "libguile/strings.h"
 #include "libguile/validate.h"
-#include "libguile/ieee-754.h"
 #include "libguile/arrays.h"
 #include "libguile/array-handle.h"
 #include "libguile/uniform.h"
@@ -1567,6 +1566,18 @@ SCM_DEFINE (scm_bytevector_s64_native_set_x, "bytevector-s64-native-set!",
    Section 2.1 of R6RS-lib (in response to
    http://www.r6rs.org/formal-comments/comment-187.txt).  */
 
+union scm_ieee754_float
+{
+  float f;
+  scm_t_uint32 i;
+};
+
+union scm_ieee754_double
+{
+  double d;
+  scm_t_uint64 i;
+};
+
 
 /* Convert to/from a floating-point number with different endianness.  This
    method is probably not the most efficient but it should be portable.  */
@@ -1575,20 +1586,10 @@ static inline void
 float_to_foreign_endianness (union scm_ieee754_float *target,
                             float source)
 {
-  union scm_ieee754_float src;
-
-  src.f = source;
+  union scm_ieee754_float input;
 
-#ifdef WORDS_BIGENDIAN
-  /* Assuming little endian for both byte and word order.  */
-  target->little_endian.negative = src.big_endian.negative;
-  target->little_endian.exponent = src.big_endian.exponent;
-  target->little_endian.mantissa = src.big_endian.mantissa;
-#else
-  target->big_endian.negative = src.little_endian.negative;
-  target->big_endian.exponent = src.little_endian.exponent;
-  target->big_endian.mantissa = src.little_endian.mantissa;
-#endif
+  input.f = source;
+  target->i = bswap_32 (input.i);
 }
 
 static inline float
@@ -1596,16 +1597,7 @@ float_from_foreign_endianness (const union scm_ieee754_float *source)
 {
   union scm_ieee754_float result;
 
-#ifdef WORDS_BIGENDIAN
-  /* Assuming little endian for both byte and word order.  */
-  result.big_endian.negative = source->little_endian.negative;
-  result.big_endian.exponent = source->little_endian.exponent;
-  result.big_endian.mantissa = source->little_endian.mantissa;
-#else
-  result.little_endian.negative = source->big_endian.negative;
-  result.little_endian.exponent = source->big_endian.exponent;
-  result.little_endian.mantissa = source->big_endian.mantissa;
-#endif
+  result.i = bswap_32 (source->i);
 
   return (result.f);
 }
@@ -1614,22 +1606,10 @@ static inline void
 double_to_foreign_endianness (union scm_ieee754_double *target,
                              double source)
 {
-  union scm_ieee754_double src;
+  union scm_ieee754_double input;
 
-  src.d = source;
-
-#ifdef WORDS_BIGENDIAN
-  /* Assuming little endian for both byte and word order.  */
-  target->little_little_endian.negative  = src.big_endian.negative;
-  target->little_little_endian.exponent  = src.big_endian.exponent;
-  target->little_little_endian.mantissa0 = src.big_endian.mantissa0;
-  target->little_little_endian.mantissa1 = src.big_endian.mantissa1;
-#else
-  target->big_endian.negative  = src.little_little_endian.negative;
-  target->big_endian.exponent  = src.little_little_endian.exponent;
-  target->big_endian.mantissa0 = src.little_little_endian.mantissa0;
-  target->big_endian.mantissa1 = src.little_little_endian.mantissa1;
-#endif
+  input.d = source;
+  target->i = bswap_64 (input.i);
 }
 
 static inline double
@@ -1637,18 +1617,7 @@ double_from_foreign_endianness (const union scm_ieee754_double *source)
 {
   union scm_ieee754_double result;
 
-#ifdef WORDS_BIGENDIAN
-  /* Assuming little endian for both byte and word order.  */
-  result.big_endian.negative  = source->little_little_endian.negative;
-  result.big_endian.exponent  = source->little_little_endian.exponent;
-  result.big_endian.mantissa0 = source->little_little_endian.mantissa0;
-  result.big_endian.mantissa1 = source->little_little_endian.mantissa1;
-#else
-  result.little_little_endian.negative  = source->big_endian.negative;
-  result.little_little_endian.exponent  = source->big_endian.exponent;
-  result.little_little_endian.mantissa0 = source->big_endian.mantissa0;
-  result.little_little_endian.mantissa1 = source->big_endian.mantissa1;
-#endif
+  result.i = bswap_64 (source->i);
 
   return (result.d);
 }
diff --git a/libguile/ieee-754.h b/libguile/ieee-754.h
deleted file mode 100644 (file)
index e345efa..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/* Copyright (C) 1992, 1995, 1996, 1999 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
-
-#ifndef SCM_IEEE_754_H
-#define SCM_IEEE_754_H 1
-
-/* Based on glibc's <ieee754.h> and modified by Ludovic Courtès to include
-   all possible IEEE-754 double-precision representations.  */
-
-\f
-/* IEEE 754 simple-precision format (32-bit).  */
-
-union scm_ieee754_float
-  {
-    float f;
-
-    struct
-      {
-       unsigned int negative:1;
-       unsigned int exponent:8;
-       unsigned int mantissa:23;
-      } big_endian;
-
-    struct
-      {
-       unsigned int mantissa:23;
-       unsigned int exponent:8;
-       unsigned int negative:1;
-      } little_endian;
-  };
-
-
-\f
-/* IEEE 754 double-precision format (64-bit).  */
-
-union scm_ieee754_double
-  {
-    double d;
-
-    struct
-      {
-       /* Big endian.  */
-
-       unsigned int negative:1;
-       unsigned int exponent:11;
-       /* Together these comprise the mantissa.  */
-       unsigned int mantissa0:20;
-       unsigned int mantissa1:32;
-      } big_endian;
-
-    struct
-      {
-       /* Both byte order and word order are little endian.  */
-
-       /* Together these comprise the mantissa.  */
-       unsigned int mantissa1:32;
-       unsigned int mantissa0:20;
-       unsigned int exponent:11;
-       unsigned int negative:1;
-      } little_little_endian;
-
-    struct
-      {
-       /* Byte order is little endian but word order is big endian.  Not
-          sure this is very wide spread.  */
-       unsigned int mantissa0:20;
-       unsigned int exponent:11;
-       unsigned int negative:1;
-       unsigned int mantissa1:32;
-      } little_big_endian;
-
-  };
-
-
-#endif /* SCM_IEEE_754_H */
index 3007434..4ba5012 100644 (file)
@@ -1,6 +1,6 @@
 ;;;; bytevectors.test --- R6RS bytevectors. -*- mode: scheme; coding: utf-8; -*-
 ;;;;
-;;;; Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
+;;;; Copyright (C) 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
 ;;;; Ludovic Courtès
 ;;;;
 ;;;; This library is free software; you can redistribute it and/or
 \f
 (with-test-prefix/c&e "2.8 Operations on IEEE-754 Representations"
 
+  (pass-if "single, little endian"
+    ;; http://bugs.gnu.org/11310
+    (let ((b (make-bytevector 4)))
+      (bytevector-ieee-single-set! b 0 1.0 (endianness little))
+      (equal? #vu8(0 0 128 63) b)))
+
+  (pass-if "single, big endian"
+    ;; http://bugs.gnu.org/11310
+    (let ((b (make-bytevector 4)))
+      (bytevector-ieee-single-set! b 0 1.0 (endianness big))
+      (equal? #vu8(63 128 0 0) b)))
+
   (pass-if "bytevector-ieee-single-native-{ref,set!}"
     (let ((b (make-bytevector 4))
           (number 3.00))
       (equal? (bytevector-ieee-single-ref b 1 (endianness little))
               (bytevector-ieee-single-ref b 5 (endianness big)))))
 
+  (pass-if "double, little endian"
+    ;; http://bugs.gnu.org/11310
+    (let ((b (make-bytevector 8)))
+      (bytevector-ieee-double-set! b 0 1.0 (endianness little))
+      (equal? #vu8(0 0 0 0 0 0 240 63) b)))
+
+  (pass-if "double, big endian"
+    ;; http://bugs.gnu.org/11310
+    (let ((b (make-bytevector 8)))
+      (bytevector-ieee-double-set! b 0 1.0 (endianness big))
+      (equal? #vu8(63 240 0 0 0 0 0 0) b)))
+
   (pass-if "bytevector-ieee-double-native-{ref,set!}"
     (let ((b (make-bytevector 8))
           (number 3.14))
   (pass-if "bitvector > 8"
     (let ((bv (uniform-array->bytevector (make-bitvector 9 #t))))
       (= (bytevector-length bv) 2))))
+
+;;; Local Variables:
+;;; eval: (put 'with-test-prefix/c&e 'scheme-indent-function 1)
+;;; End: