initial checkin
authorClaus Gittinger <cg@exept.de>
Tue, 13 Jun 2017 09:01:30 +0200
changeset 4380 1f4fe7f1c1d3
parent 4379 e547154fa694
child 4381 03b8f1691a02
initial checkin
QDouble.st
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QDouble.st	Tue Jun 13 09:01:30 2017 +0200
@@ -0,0 +1,1539 @@
+"
+ COPYRIGHT (c) 2017 by eXept Software AG
+              All Rights Reserved
+
+ This software is furnished under a license and may be used
+ only in accordance with the terms of that license and with the
+ inclusion of the above copyright notice.   This software may not
+ be provided or otherwise made available to, or used by, any
+ other person.  No title to or ownership of the software is
+ hereby transferred.
+"
+"{ Package: 'stx:libbasic2' }"
+
+"{ NameSpace: Smalltalk }"
+
+LimitedPrecisionReal variableByteSubclass:#QDouble
+	instanceVariableNames:''
+	classVariableNames:'DefaultPrintFormat QDoubleZero QDoubleOne Pi E Ln2 Ln10 Epsilon'
+	poolDictionaries:''
+	category:'Magnitude-Numbers'
+!
+
+!QDouble primitiveDefinitions!
+%{
+#include <stdio.h>
+#include <errno.h>
+
+#define __USE_ISOC9X 1
+#define __USE_ISOC99 1
+#include <math.h>
+
+/*
+ * on some systems, errno is a macro ... check for it here
+ */
+#ifndef errno
+ extern errno;
+#endif
+
+#if !defined (__win32__)
+# include <locale.h>
+#endif
+
+#if defined (__aix__)
+# include <float.h>
+#endif
+
+#if defined(__irix__) || defined(__solaris__) || defined(__sunos__)
+# include <nan.h>
+#endif
+
+#if defined(__linux__)
+# ifndef NAN
+#  include <bits/nan.h>
+# endif
+#endif
+
+struct qd_real {
+    double x[4];    /* The Components. */
+};
+
+struct __quadDoubleStruct {
+        STX_OBJ_HEADER
+#ifdef __NEED_DOUBLE_ALIGN
+        __FILLTYPE_DOUBLE f_filler;
+#endif
+        double d_quadDoubleValue[4];
+};
+
+#define __QuadDoubleInstPtr(obj)      ((struct __quadDoubleStruct *)(__objPtr(obj)))
+
+#ifndef __isQuadDouble
+# define __isQuadDouble(o) \
+        (__Class(o) == @global(QuadDouble))
+#endif
+
+#ifndef __qIsQuadDouble
+# define __qIsQuadDouble(o) \
+        (__qClass(o) == @global(QuadDouble))
+#endif
+
+#define __qNew_qdReal(newQD, d0,d1,d2,d3) { \
+    __qNew(newQD, sizeof(struct __quadDoubleStruct)); \
+    __stx_setClass(newQD, QDouble);                \
+    __QuadDoubleInstPtr(newQD)->d_quadDoubleValue[0] = d0;   \
+    __QuadDoubleInstPtr(newQD)->d_quadDoubleValue[1] = d1;   \
+    __QuadDoubleInstPtr(newQD)->d_quadDoubleValue[2] = d2;   \
+    __QuadDoubleInstPtr(newQD)->d_quadDoubleValue[3] = d3;   \
+}
+
+// qd_real(c0, c1, c2, c3);
+
+#define _QD_SPLITTER 134217729.0               // = 2^27 + 1
+#define _QD_SPLIT_THRESH 6.69692879491417e+299 // = 2^996
+
+#define m_quick_two_sum(rslt, a, b, err) {\
+  double s = a + b;\
+  err = b - (s - a);\
+  rslt = s; \
+}
+
+#define m_two_sum(rslt, a, b, err) {\
+  double s = a + b;\
+  double bb = s - a;\
+  err = (a - (s - bb)) + (b - bb);\
+  rslt = s;\
+}
+
+#define m_three_sum(a, b, c) { \
+  double t1, t2, t3; \
+  m_two_sum(t1, a, b, t2); \
+  m_two_sum(a, c, t1, t3); \
+  m_two_sum(b, t2, t3, c); \
+}
+
+#define m_three_sum2(a, b, c) {\
+  double t1, t2, t3;\
+  m_two_sum(t1, a, b, t2);\
+  m_two_sum(a, c, t1, t3);\
+  b = t2 + t3;\
+}
+
+#ifndef QD_FMS
+
+/* Computes high word and lo word of a */
+#define m_split(a, hi, lo) {\
+  double temp;\
+  if (a > _QD_SPLIT_THRESH || a < -_QD_SPLIT_THRESH) {\
+    a *= 3.7252902984619140625e-09;\
+    temp = _QD_SPLITTER * a;\
+    hi = temp - (temp - a);\
+    lo = a - hi;\
+    hi *= 268435456.0;\
+    lo *= 268435456.0;\
+  } else {\
+    temp = _QD_SPLITTER * a;\
+    hi = temp - (temp - a);\
+    lo = a - hi;\
+  }\
+}
+
+#endif
+
+
+#ifdef QD_FMS
+
+/* Computes fl(a*b) and err(a*b). */
+
+#define m_two_prod(rslt, a, b, err) {\
+  double p = a * b;\
+  err = QD_FMS(a, b, p);\
+  rslt = p; \
+}
+
+#else
+
+#define m_two_prod(rslt, a, b, err) {\
+  double a_hi, a_lo, b_hi, b_lo;\
+  double p = a * b;\
+  m_split(a, a_hi, a_lo);\
+  m_split(b, b_hi, b_lo);\
+  err = ((a_hi * b_hi - p) + a_hi * b_lo + a_lo * b_hi) + a_lo * b_lo;\
+  rslt = p; \
+}
+
+#endif
+
+#ifdef QD_FMS
+
+#define m_two_sqr(rslt, a, err) {\
+  double p = a * a;\
+  err = QD_FMS(a, a, p);\
+  rslt = p;\
+}
+
+#else
+
+#define m_two_sqr(rslt, a, err) {\
+  double hi, lo;\
+  double q = a * a;\
+  m_split(a, hi, lo);\
+  err = ((hi * hi - q) + 2.0 * hi * lo) + lo * lo;\
+  rslt = q;\
+}
+
+#endif
+
+#define m_renorm4(c0, c1, c2, c3) {\
+  double s0, s1, s2 = 0.0, s3 = 0.0;\
+\
+    if (! isinf(c0)) { \
+\
+        m_quick_two_sum(s0, c2, c3, c3);\
+        m_quick_two_sum(s0, c1, s0, c2);\
+        m_quick_two_sum(c0, c0, s0, c1);\
+\
+        s0 = c0;\
+        s1 = c1;\
+        if (s1 != 0.0) {\
+             m_quick_two_sum(s1, s1, c2, s2);\
+            if (s2 != 0.0) {\
+                 m_quick_two_sum(s2, s2, c3, s3);\
+            } else {\
+                 m_quick_two_sum(s1, s1, c3, s2);\
+            }\ 
+        } else {\
+            m_quick_two_sum(s0, s0, c2, s1);\
+            if (s1 != 0.0) {\
+                 m_quick_two_sum(s1, s1, c3, s2);\
+            } else {\
+                 m_quick_two_sum(s0, s0, c3, s1);\
+            }\
+        }\
+\
+        c0 = s0;\
+        c1 = s1;\
+        c2 = s2;\
+        c3 = s3;\
+    }\
+}
+
+#define m_renorm5(c0, c1, c2, c3, c4) { \
+    double s0, s1, s2 = 0.0, s3 = 0.0; \
+\
+    if (! isinf(c0)) { \
+        m_two_sum(s0, c3, c4, c4); \
+        m_quick_two_sum(s0, c2, s0, c3); \
+        m_quick_two_sum(s0, c1, s0, c2); \
+        m_quick_two_sum(c0, c0, s0, c1); \
+\
+        s0 = c0; \
+        s1 = c1; \
+\
+        m_two_sum(s0, c0, c1, s1); \
+        if (s1 != 0.0) { \
+            m_quick_two_sum(s1, s1, c2, s2); \
+            if (s2 != 0.0) { \
+                m_quick_two_sum(s2 ,s2, c3, s3); \
+                if (s3 != 0.0) {\
+                    s3 += c4; \
+                } else {\
+                    s2 += c4;\
+                }\
+            } else { \
+                m_quick_two_sum(s1, s1, c3, s2); \
+                if (s2 != 0.0) {\
+                    m_quick_two_sum(s2, s2, c4, s3); \
+                } else { \
+                    m_quick_two_sum(s1, s1, c4, s2); \
+                } \
+            } \
+        } else { \
+            m_quick_two_sum(s0,s0, c2, s1); \
+            if (s1 != 0.0) { \
+                m_quick_two_sum(s1,s1, c3, s2); \
+                if (s2 != 0.0) {\
+                    m_quick_two_sum(s2,s2, c4, s3); \
+                } else { \
+                    m_quick_two_sum(s1 ,s1, c4, s2); \
+                } \
+            } else { \
+                m_quick_two_sum(s0,s0, c3, s1); \
+                if (s1 != 0.0) { \
+                    m_quick_two_sum(s1,s1, c4, s2); \
+                } else { \
+                    m_quick_two_sum(s0,s0, c4, s1); \
+                } \
+            } \
+        } \
+ \
+        c0 = s0; \
+        c1 = s1; \
+        c2 = s2; \
+        c3 = s3; \
+    } \
+}
+
+%}
+! !
+
+!QDouble primitiveFunctions!
+%{
+
+/*********** Basic Functions ************/
+/* Computes fl(a+b) and err(a+b).  Assumes |a| >= |b|. */
+inline double 
+quick_two_sum(double a, double b, double *errPtr) {
+  double s = a + b;
+  *errPtr = b - (s - a);
+  return s;
+}
+
+/* Computes fl(a-b) and err(a-b).  Assumes |a| >= |b| */
+inline double 
+quick_two_diff(double a, double b, double *errPtr) {
+  double s = a - b;
+  *errPtr = (a - s) - b;
+  return s;
+}
+
+/* Computes fl(a+b) and err(a+b).  */
+inline double 
+two_sum(double a, double b, double *errPtr) {
+  double s = a + b;
+  double bb = s - a;
+  *errPtr = (a - (s - bb)) + (b - bb);
+  return s;
+}
+
+/* Computes fl(a-b) and err(a-b).  */
+inline double 
+two_diff(double a, double b, double *errPtr) {
+  double s = a - b;
+  double bb = s - a;
+  *errPtr = (a - (s - bb)) - (b + bb);
+  return s;
+}
+
+#ifndef QD_FMS
+/* Computes high word and lo word of a */
+inline void 
+split(double a, double *hiPtr, double *loPtr) {
+  double temp;
+  if (a > _QD_SPLIT_THRESH || a < -_QD_SPLIT_THRESH) {
+    a *= 3.7252902984619140625e-09;  // 2^-28
+    temp = _QD_SPLITTER * a;
+    *hiPtr = temp - (temp - a);
+    *loPtr = a - *hiPtr;
+    *hiPtr *= 268435456.0;          // 2^28
+    *loPtr *= 268435456.0;          // 2^28
+  } else {
+    temp = _QD_SPLITTER * a;
+    *hiPtr = temp - (temp - a);
+    *loPtr = a - *hiPtr;
+  }
+}
+#endif
+
+/* Computes fl(a*b) and err(a*b). */
+inline double 
+two_prod(double a, double b, double *errPtr) {
+#ifdef QD_FMS
+  double p = a * b;
+  *errPtr = QD_FMS(a, b, p);
+  return p;
+#else
+  double a_hi, a_lo, b_hi, b_lo;
+  double p = a * b;
+  split(a, &a_hi, &a_lo);
+  split(b, &b_hi, &b_lo);
+  *errPtr = ((a_hi * b_hi - p) + a_hi * b_lo + a_lo * b_hi) + a_lo * b_lo;
+  return p;
+#endif
+}
+
+/* Computes fl(a*a) and err(a*a).  Faster than the above method. */
+inline double 
+two_sqr(double a, double *errPtr) {
+#ifdef QD_FMS
+  double p = a * a;
+  *errPtr = QD_FMS(a, a, p);
+  return p;
+#else
+  double hi, lo;
+  double q = a * a;
+  split(a, &hi, &lo);
+  *errPtr = ((hi * hi - q) + 2.0 * hi * lo) + lo * lo;
+  return q;
+#endif
+}
+
+/* Computes the nearest integer to d. */
+inline double 
+nint(double d) {
+  if (d == floor(d))
+    return d;
+  return floor(d + 0.5);
+}
+
+/* Computes the truncated integer. */
+inline double 
+aint(double d) {
+  return (d >= 0.0) ? floor(d) : ceil(d);
+}
+
+inline void 
+renorm4(double *c0Ptr, double *c1Ptr, double *c2Ptr, double *c3Ptr) {
+  double s0, s1, s2 = 0.0, s3 = 0.0;
+  double c0 = *c0Ptr;
+  
+  if (isinf(c0)) return;
+
+  s0 = quick_two_sum(*c2Ptr, *c3Ptr, c3Ptr);
+  s0 = quick_two_sum(*c1Ptr, s0, c2Ptr);
+  c0 = quick_two_sum(c0, s0, c1Ptr);
+
+  s0 = c0;
+  s1 = *c1Ptr;
+  if (s1 != 0.0) {
+    s1 = quick_two_sum(s1, *c2Ptr, &s2);
+    if (s2 != 0.0)
+      s2 = quick_two_sum(s2, *c3Ptr, &s3);
+    else
+      s1 = quick_two_sum(s1, *c3Ptr, &s2);
+  } else {
+    s0 = quick_two_sum(s0, *c2Ptr, &s1);
+    if (s1 != 0.0)
+      s1 = quick_two_sum(s1, *c3Ptr, &s2);
+    else
+      s0 = quick_two_sum(s0, *c3Ptr, &s1);
+  }
+
+  *c0Ptr = s0;
+  *c1Ptr = s1;
+  *c2Ptr = s2;
+  *c3Ptr = s3;
+}
+
+inline void 
+renorm5(double *c0Ptr, double *c1Ptr, double *c2Ptr, double *c3Ptr, double *c4Ptr) {
+  double s0, s1, s2 = 0.0, s3 = 0.0;
+  
+  if (isinf(*c0Ptr)) return;
+
+  s0 = quick_two_sum(*c3Ptr, *c4Ptr, c4Ptr);
+  s0 = quick_two_sum(*c2Ptr, s0, c3Ptr);
+  s0 = quick_two_sum(*c1Ptr, s0, c2Ptr);
+  *c0Ptr = quick_two_sum(*c0Ptr, s0, c1Ptr);
+
+  s0 = *c0Ptr;
+  s1 = *c1Ptr;
+
+  s0 = quick_two_sum(*c0Ptr, *c1Ptr, &s1);
+  if (s1 != 0.0) {
+    s1 = quick_two_sum(s1, *c2Ptr, &s2);
+    if (s2 != 0.0) {
+      s2 =quick_two_sum(s2, *c3Ptr, &s3);
+      if (s3 != 0.0)
+        s3 += *c4Ptr;
+      else
+        s2 += *c4Ptr;
+    } else {
+      s1 = quick_two_sum(s1, *c3Ptr, &s2);
+      if (s2 != 0.0)
+        s2 = quick_two_sum(s2, *c4Ptr, &s3);
+      else
+        s1 = quick_two_sum(s1, *c4Ptr, &s2);
+    }
+  } else {
+    s0 = quick_two_sum(s0, *c2Ptr, &s1);
+    if (s1 != 0.0) {
+      s1 = quick_two_sum(s1, *c3Ptr, &s2);
+      if (s2 != 0.0)
+        s2 = quick_two_sum(s2, *c4Ptr, &s3);
+      else
+        s1 = quick_two_sum(s1, *c4Ptr, &s2);
+    } else {
+      s0 = quick_two_sum(s0, *c3Ptr, &s1);
+      if (s1 != 0.0)
+        s1 = quick_two_sum(s1, *c4Ptr, &s2);
+      else
+        s0 = quick_two_sum(s0, *c4Ptr, &s1);
+    }
+  }
+
+  *c0Ptr = s0;
+  *c1Ptr = s1;
+  *c2Ptr = s2;
+  *c3Ptr = s3;
+}
+
+inline void 
+three_sum(double *aPtr, double *bPtr, double *cPtr) {
+  double t1, t2, t3;
+  t1 = two_sum(*aPtr, *bPtr, &t2);
+  *aPtr  = two_sum(*cPtr, t1, &t3);
+  *bPtr  = two_sum(t2, t3, cPtr);
+}
+
+inline void three_sum2(double *aPtr, double *bPtr, double *cPtr) {
+  double t1, t2, t3;
+  t1 = two_sum(*aPtr, *bPtr, &t2);
+  *aPtr  = two_sum(*cPtr, t1, &t3);
+  *bPtr = t2 + t3;
+}
+
+
+#if 0
+/* These are provided to give consistent 
+   interface for double with double-double and quad-double. */
+inline void 
+sincosh(double t, double &sinh_t, double &cosh_t) {
+  sinh_t = sinh(t);
+  cosh_t = cosh(t);
+}
+
+inline double 
+sqr(double t) {
+  return t * t;
+}
+
+inline double 
+to_double(double a) { 
+    return a; 
+}
+
+inline int    
+to_int(double a)    { 
+    return static_cast<int>(a); 
+}
+#endif
+
+%}
+! !
+
+!QDouble class methodsFor:'documentation'!
+
+copyright
+"
+ COPYRIGHT (c) 2017 by eXept Software AG
+              All Rights Reserved
+
+ This software is furnished under a license and may be used
+ only in accordance with the terms of that license and with the
+ inclusion of the above copyright notice.   This software may not
+ be provided or otherwise made available to, or used by, any
+ other person.  No title to or ownership of the software is
+ hereby transferred.
+"
+!
+
+documentation
+"
+    QDoubles represent rational numbers with extended, but still limited precision.
+
+    In contrast to Floats (which use the C-compilers native 64bit 'double' format),
+    QDoubles give you 212 bit or approx. 64 decimal digits of precision.
+
+    Representation:
+        QDoubles use 4 IEEE doubles, each keeping 53 bits of precision.
+
+    Range and Precision of Storage Formats: see LimitedPrecisionReal >> documentation
+
+    [author:]
+        Claus Gittinger
+
+    [see also:]
+        Number
+        Float ShortFloat Fraction FixedPoint Integer Complex
+        FloatArray DoubleArray
+"
+! !
+
+!QDouble class methodsFor:'instance creation'!
+
+basicNew
+    "return a new quad-precision double - here we return 0.0
+     Notice that numbers are usually NOT created this way ...
+     It's implemented here to allow things like binary store & load
+     of floats. (but even this support will go away eventually, it's not
+     a good idea to store the bits of a float - the reader might have a
+     totally different representation - so floats should be
+     binary stored in a device independent format."
+
+%{  /* NOCONTEXT */
+#ifdef __SCHTEAM__
+    ERROR("trying to instantiate a quad double");
+#else
+    OBJ newFloat;
+printf("xxx\n");
+    __qNew(newFloat, sizeof(struct __quadDoubleStruct));              
+    __stx_setClass(newFloat, QDouble);                         
+    __QuadDoubleInstPtr(newFloat)->d_quadDoubleValue[0] = 0.0;        
+    __QuadDoubleInstPtr(newFloat)->d_quadDoubleValue[1] = 0.0;        
+    __QuadDoubleInstPtr(newFloat)->d_quadDoubleValue[2] = 0.0;        
+    __QuadDoubleInstPtr(newFloat)->d_quadDoubleValue[3] = 0.0;        
+    RETURN (newFloat);
+#endif /* not SCHTEAM */
+%}
+
+    "
+     self basicNew
+    "
+
+    "Created: / 12-06-2017 / 16:00:38 / cg"
+!
+
+d0:d0 d1:d1 d2:d2 d3:d3
+    "return a new quad-precision double from individual double components"
+
+%{  /* NOCONTEXT */
+#ifdef __SCHTEAM__
+    ERROR("trying to instantiate a quad double");
+#else
+    OBJ newQD;
+
+    if (__isFloatLike(d0) 
+     && __isFloatLike(d1)
+     && __isFloatLike(d2)
+     && __isFloatLike(d3)) {    
+        __qNew_qdReal(newQD, __floatVal(d0), __floatVal(d1),        
+                             __floatVal(d2), __floatVal(d3));        
+        RETURN (newQD);
+    }
+#endif
+%}.
+    self error:'invalid argument'
+
+    "
+     self d0: 3.141592653589793116e+00
+          d1: 1.224646799147353207e-16
+          d2: -2.994769809718339666e-33
+          d3: 1.112454220863365282e-49
+    "
+
+    "Created: / 12-06-2017 / 20:17:14 / cg"
+!
+
+fromDoubleArray:aDoubleArray
+    "return a new quad-precision double from coercing a double array"
+
+%{  /* NOCONTEXT */
+#ifdef __SCHTEAM__
+    ERROR("trying to instantiate a quad double");
+#else
+    OBJ newQD;
+
+    if (__isDoubleArray(aDoubleArray)) {    
+        __qNew_qdReal(newQD, 
+                    __DoubleArrayInstPtr(aDoubleArray)->d_element[0],        
+                    __DoubleArrayInstPtr(aDoubleArray)->d_element[1],        
+                    __DoubleArrayInstPtr(aDoubleArray)->d_element[2],        
+                    __DoubleArrayInstPtr(aDoubleArray)->d_element[3]);        
+        RETURN (newQD);
+    }
+#endif
+%}.
+    self error:'invalid argument'
+
+    "
+     self fromDoubleArray(DoubleArray 
+                                with: 3.141592653589793116e+00
+                                with: 1.224646799147353207e-16
+                                with: -2.994769809718339666e-33
+                                with: 1.112454220863365282e-49)
+    "
+
+    "Created: / 12-06-2017 / 18:25:32 / cg"
+!
+
+fromFloat:aFloat
+    "return a new quad-precision double from coercing aFloat"
+
+%{  /* NOCONTEXT */
+#ifdef __SCHTEAM__
+    ERROR("trying to instantiate a quad double");
+#else
+    double dVal;
+    OBJ newFloat;
+
+    if (__isFloatLike(aFloat)) {
+        dVal = __floatVal(aFloat);
+    } else if (__isShortFloat(aFloat)) {       
+        dVal = __shortFloatVal(aFloat);
+    } else {
+        goto badArg;
+    }    
+        
+    __qNew(newFloat, sizeof(struct __quadDoubleStruct));              
+    __stx_setClass(newFloat, QDouble);                         
+    __QuadDoubleInstPtr(newFloat)->d_quadDoubleValue[0] = dVal;        
+    __QuadDoubleInstPtr(newFloat)->d_quadDoubleValue[1] = 0.0;        
+    __QuadDoubleInstPtr(newFloat)->d_quadDoubleValue[2] = 0.0;        
+    __QuadDoubleInstPtr(newFloat)->d_quadDoubleValue[3] = 0.0;        
+    RETURN (newFloat);
+
+badArg: ;
+
+#endif
+%}.
+    self error:'invalid argument'
+
+    "
+     self fromFloat:1.0
+    "
+
+    "Created: / 12-06-2017 / 16:06:54 / cg"
+!
+
+fromInteger:anInteger
+    "return a new quad-precision double from coercing anInteger"
+
+%{  /* NOCONTEXT */
+#ifndef __SCHTEAM__
+    OBJ newFloat;
+
+    if (__isSmallInteger(anInteger)) {
+        __qNew(newFloat, sizeof(struct __quadDoubleStruct));              
+        __stx_setClass(newFloat, QDouble);                         
+        __QuadDoubleInstPtr(newFloat)->d_quadDoubleValue[0] = (double)(__smallIntegerVal(anInteger));        
+        __QuadDoubleInstPtr(newFloat)->d_quadDoubleValue[1] = 0.0;        
+        __QuadDoubleInstPtr(newFloat)->d_quadDoubleValue[2] = 0.0;        
+        __QuadDoubleInstPtr(newFloat)->d_quadDoubleValue[3] = 0.0;        
+        RETURN (newFloat);
+    }
+#endif
+%}.
+    ^ super fromInteger:anInteger
+
+    "
+     self fromInteger:2
+    "
+
+    "Created: / 12-06-2017 / 16:10:10 / cg"
+! !
+
+!QDouble class methodsFor:'constants'!
+
+e
+    "return the constant e as quad precision double.
+     (returns approx. 212 bits of precision)"
+
+    E isNil ifTrue:[
+        E := self fromDoubleArray(DoubleArray 
+                                    with: 2.718281828459045091e+00
+                                    with: 1.445646891729250158e-16
+                                    with: -2.127717108038176765e-33
+                                    with: 1.515630159841218954e-49)
+    ].    
+    ^ E
+
+    "
+     self e
+    "
+
+    "Created: / 12-06-2017 / 18:29:36 / cg"
+!
+
+ln10
+    "return the constant e as quad precision double.
+     (returns approx. 212 bits of precision)"
+
+    Ln10 isNil ifTrue:[
+        Ln10 := self fromDoubleArray(DoubleArray 
+                                    with: 2.302585092994045901e+00
+                                    with: -2.170756223382249351e-16
+                                    with: -9.984262454465776570e-33
+                                    with: -4.023357454450206379e-49)
+    ].    
+    ^ Ln10
+
+    "
+     self ln10
+    "
+
+    "Created: / 12-06-2017 / 18:32:29 / cg"
+!
+
+ln2
+    "return the constant e as quad precision double.
+     (returns approx. 212 bits of precision)"
+
+    Ln2 isNil ifTrue:[
+        Ln2 := self fromDoubleArray(DoubleArray 
+                                    with: 6.931471805599452862e-01
+                                    with: 2.319046813846299558e-17
+                                    with: 5.707708438416212066e-34
+                                    with: -3.582432210601811423e-50)
+    ].    
+    ^ Ln2
+
+    "
+     self ln2
+    "
+
+    "Created: / 12-06-2017 / 18:31:34 / cg"
+!
+
+pi
+    "return the constant pi as quad precision double.
+     (returns approx. 212 bits of precision)"
+
+    Pi isNil ifTrue:[
+        Pi := self fromDoubleArray(DoubleArray 
+                                    with: 3.141592653589793116e+00
+                                    with: 1.224646799147353207e-16
+                                    with: -2.994769809718339666e-33
+                                    with: 1.112454220863365282e-49)
+    ].    
+    ^ Pi
+
+    "
+     self pi
+    "
+
+    "Created: / 12-06-2017 / 18:27:13 / cg"
+! !
+
+!QDouble class methodsFor:'queries'!
+
+epsilon
+    "return the maximum relative spacing of instances of mySelf
+     (i.e. the value-delta of the least significant bit)"
+
+    ^ Float epsilon
+
+    "
+     Float epsilon
+     ShortFloat epsilon
+     QDouble epsilon
+    "
+
+    "Created: / 12-06-2017 / 18:52:44 / cg"
+!
+
+numBitsInExponent
+    "answer the number of bits in the exponent"
+
+    ^ Float numBitsInExponent
+
+    "
+     1.0 asQDouble class numBitsInExponent
+    "
+
+    "Created: / 12-06-2017 / 11:11:04 / cg"
+!
+
+numBitsInMantissa
+    "answer the number of bits in the mantissa"
+
+    ^ Float precision * 4
+    
+    "
+     1.0 class numBitsInMantissa
+     1.0 asShortFloat class numBitsInMantissa
+     1.0 asLongFloat class numBitsInMantissa
+     1.0 asDDouble class numBitsInMantissa
+     1.0 asQDouble class numBitsInMantissa
+
+     Float numBitsInMantissa
+     ShortFloat numBitsInMantissa
+     QDouble numBitsInMantissa
+    "
+
+    "Created: / 12-06-2017 / 11:13:44 / cg"
+    "Modified: / 12-06-2017 / 18:48:48 / cg"
+!
+
+precision
+    "answer the number of bits in the mantissa"
+
+    ^ Float precision * 4
+    
+    "
+     1.0 class numBitsInMantissa
+     1.0 asShortFloat class numBitsInMantissa
+     1.0 asLongFloat class numBitsInMantissa
+     1.0 asDDouble class numBitsInMantissa
+     1.0 asQDouble class numBitsInMantissa
+
+     Float numBitsInMantissa
+     ShortFloat numBitsInMantissa
+     QDouble numBitsInMantissa
+     QDouble precision
+    "
+
+    "Created: / 12-06-2017 / 18:49:11 / cg"
+!
+
+radix
+    "answer the radix of a Floats exponent
+     This is an IEEE float, which is represented as binary"
+
+    ^ Float radix
+
+    "Created: / 12-06-2017 / 18:50:04 / cg"
+! !
+
+!QDouble methodsFor:'arithmetic'!
+
+* aNumber
+    "return the product of the receiver and the argument, aNumber"
+
+    ^ aNumber productFromQDouble:self
+
+    "
+     ((QDouble fromFloat:1e20) + (QDouble fromFloat:1.0)) asDoubleArray
+    "
+
+    "Created: / 13-06-2017 / 01:00:47 / cg"
+!
+
++ aNumber
+    "return the sum of the receiver and the argument, aNumber"
+
+    ^ aNumber sumFromQDouble:self
+
+    "
+     ((QDouble fromFloat:1e20) + (QDouble fromFloat:1.0)) asDoubleArray
+    "
+
+    "Created: / 12-06-2017 / 16:17:46 / cg"
+    "Modified: / 12-06-2017 / 23:06:22 / cg"
+!
+
+- aNumber
+    "return the sum of the receiver and the argument, aNumber"
+
+    ^ (aNumber negated) sumFromQDouble:self
+
+    "
+     (QDouble fromFloat:1e20) asDoubleArray
+     ((QDouble fromFloat:1e20) - (QDouble fromFloat:1.0)) asDoubleArray
+     (QDouble fromFloat:1e-20) asDoubleArray
+     ((QDouble fromFloat:1e-20) - (QDouble fromFloat:1.0)) asDoubleArray
+     ((QDouble fromFloat:2.0) - (QDouble fromFloat:1.0)) asDoubleArray
+    "
+
+    "Created: / 12-06-2017 / 23:41:39 / cg"
+!
+
+negated
+    ^ self class 
+        d0:(self d0) negated 
+        d1:(self d1) negated 
+        d2:(self d2) negated 
+        d3:(self d3) negated
+
+    "    
+     (QDouble fromFloat:1.0) negated
+     ((QDouble fromFloat:1e20) + (QDouble fromFloat:1.0)) negated asDoubleArray
+
+     (((QDouble fromFloat:1e20) + (QDouble fromFloat:1.0))
+     + ((QDouble fromFloat:1e20) + (QDouble fromFloat:1.0))) asDoubleArray
+    "
+
+    "Created: / 12-06-2017 / 20:14:55 / cg"
+    "Modified (comment): / 12-06-2017 / 23:46:57 / cg"
+! !
+
+!QDouble methodsFor:'coercing & converting'!
+
+asDoubleArray
+    |a|
+
+    a := DoubleArray new:4.
+%{
+    __DoubleArrayInstPtr(a)->d_element[0] = __QuadDoubleInstPtr(self)->d_quadDoubleValue[0]; 
+    __DoubleArrayInstPtr(a)->d_element[1] = __QuadDoubleInstPtr(self)->d_quadDoubleValue[1]; 
+    __DoubleArrayInstPtr(a)->d_element[2] = __QuadDoubleInstPtr(self)->d_quadDoubleValue[2]; 
+    __DoubleArrayInstPtr(a)->d_element[3] = __QuadDoubleInstPtr(self)->d_quadDoubleValue[3]; 
+%}.
+    ^ a
+
+    "
+     (QuadDouble fromFloat:1.0) asDoubleArray
+     (QuadDouble fromFloat:2.0) asDoubleArray
+    "
+
+    "Created: / 12-06-2017 / 18:19:19 / cg"
+!
+
+asFloat
+%{
+    RETURN ( __MKFLOAT(__QuadDoubleInstPtr(self)->d_quadDoubleValue[0]) ); 
+%}
+
+    "
+     (QDouble fromFloat:1.0) asFloat
+     (QDouble fromFloat:2.0) asFloat
+    "
+
+    "Created: / 12-06-2017 / 18:15:27 / cg"
+!
+
+coerce:aNumber
+    "convert the argument aNumber into an instance of the receiver's class and return it."
+
+    ^ aNumber asQDouble
+
+    "Created: / 12-06-2017 / 17:13:47 / cg"
+    "Modified: / 12-06-2017 / 21:09:06 / cg"
+!
+
+generality
+    "return the generality value - see ArithmeticValue>>retry:coercing:"
+
+    ^ 95
+
+    "Created: / 12-06-2017 / 17:13:14 / cg"
+!
+
+negative
+%{
+    RETURN ( __QuadDoubleInstPtr(self)->d_quadDoubleValue[0] < 0 ? true : false ); 
+%}
+
+    "
+     (QDouble fromFloat:0.0) negative
+     (QDouble fromFloat:1.0) negative
+     (QDouble fromFloat:-1.0) negative
+    "
+
+    "Created: / 13-06-2017 / 01:57:39 / cg"
+!
+
+positive
+%{
+    RETURN ( __QuadDoubleInstPtr(self)->d_quadDoubleValue[0] >= 0 ? true : false ); 
+%}
+
+    "
+     (QDouble fromFloat:1.0) positive
+     (QDouble fromFloat:-1.0) positive
+    "
+
+    "Created: / 13-06-2017 / 01:56:53 / cg"
+! !
+
+!QDouble methodsFor:'double dispatching'!
+
+differenceFromFloat:aFloat
+    "aFloat - self"
+    
+    ^ aFloat + (self negated)
+
+    "
+     1.0 - (QDouble fromFloat:1.0)
+     1e20 - (QDouble fromFloat:1.0)
+     (1.0 - (QDouble fromFloat:1.0)) asFloat
+     (1e20 - (QDouble fromFloat:1.0)) asFloat
+
+     (1.0 - (QDouble fromFloat:1.0)) asDoubleArray
+     (1e20 - (QDouble fromFloat:1.0)) asDoubleArray
+     (1e20 - (QDouble fromFloat:1.0) + 1e-20) asDoubleArray
+    "
+
+    "Created: / 12-06-2017 / 23:38:05 / cg"
+!
+
+differenceFromQDouble:aQDouble
+    "aQDouble - self"
+    
+    ^ aQDouble + (self negated)
+
+    "
+     1.0 - (QDouble fromFloat:1.0)
+     1e20 - (QDouble fromFloat:1.0)
+     (1.0 - (QDouble fromFloat:1.0)) asFloat
+     (1e20 - (QDouble fromFloat:1.0)) asFloat
+
+     (1.0 - (QDouble fromFloat:1.0)) asDoubleArray
+     (1e20 - (QDouble fromFloat:1.0)) asDoubleArray
+     (1e20 - (QDouble fromFloat:1.0) + 1e-20) asDoubleArray
+    "
+
+    "Created: / 12-06-2017 / 23:38:19 / cg"
+!
+
+equalFromQDouble:aQDouble
+%{
+    if (__Class(aQDouble) == QDouble) {
+        double *a = __QuadDoubleInstPtr(self)->d_quadDoubleValue;
+        double *b = __QuadDoubleInstPtr(aQDouble)->d_quadDoubleValue;
+
+        RETURN ((a[0] == b[0] 
+                && a[1] == b[1] 
+                && a[2] == b[2] 
+                && a[3] == b[3]) ? true : false);
+    }
+%}.
+    ^ super equalFromQDouble:aQDouble
+    
+    "
+     (QDouble fromFloat:1.0) = (QDouble fromFloat:1.0)
+     (QDouble fromFloat:1.0) = 1.0
+     1.0 = (QDouble fromFloat:1.0)
+   "
+
+    "Created: / 13-06-2017 / 03:01:19 / cg"
+    "Modified (comment): / 13-06-2017 / 08:43:45 / cg"
+!
+
+floor
+%{
+    double *a = __QuadDoubleInstPtr(self)->d_quadDoubleValue;
+    OBJ newQD;
+
+    double x0, x1, x2, x3;
+    x1 = x2 = x3 = 0.0;
+    x0 =floor(a[0]);
+
+    if (x0 == a[0]) {
+        x1 = floor(a[1]);
+
+        if (x1 == a[1]) {
+            x2 = floor(a[2]);
+
+            if (x2 == a[2]) {
+                x3 = floor(a[3]);
+            }
+        }
+
+        m_renorm4(x0, x1, x2, x3);
+        __qNew_qdReal(newQD, x0, x1, x2, x3);
+        RETURN( newQD );
+    }
+
+    __qNew_qdReal(newQD, x0, x1, x2, x3);
+    RETURN( newQD );
+%}.
+
+    "
+     (QDouble fromFloat:4.0) floor
+     (QDouble fromFloat:4.1) floor
+     (QDouble fromFloat:0.1) floor
+     (0.1 + (QDouble fromFloat:1.0)) floor
+     (1e20 + (QDouble fromFloat:1.0)) floor 
+    "
+
+    "Created: / 13-06-2017 / 01:52:44 / cg"
+!
+
+productFromFloat:aFloat
+%{
+    if (__isFloatLike(aFloat)) {
+        double *a = __QuadDoubleInstPtr(self)->d_quadDoubleValue; 
+        double b = __floatVal(aFloat);
+        double p0, p1, p2, p3;
+        double q0, q1, q2;
+        double s0, s1, s2, s3, s4;
+        OBJ newQD;
+        
+        m_two_prod(p0, a[0], b, q0);
+        m_two_prod(p1, a[1], b, q1);
+        m_two_prod(p2, a[2], b, q2);
+        p3 = a[3] * b;
+
+        s0 = p0;
+
+        m_two_sum(s1, q0, p1, s2);
+
+        m_three_sum(s2, q1, p2);
+        
+        m_three_sum2(q1, q2, p3);
+        s3 = q1;
+
+        s4 = q2 + p2;
+
+        m_renorm5(s0, s1, s2, s3, s4);
+        __qNew_qdReal(newQD, s0, s1, s2, s3);
+        RETURN( newQD );
+    }
+%}.
+    ^ super productFromFloat:aFloat.
+
+    "
+     2.0 * (QDouble fromFloat:1.0)
+     1e20 * (QDouble fromFloat:1.0)
+     (2.0 * (QDouble fromFloat:1.0)) asFloat
+     (1e20 * (QDouble fromFloat:1.0)) asFloat
+
+     (1e20 * (QDouble fromFloat:1.0) * 1e-20) asDoubleArray
+    "
+
+    "Created: / 13-06-2017 / 00:58:56 / cg"
+!
+
+productFromQDouble:aQDouble
+%{
+    if (__Class(aQDouble) == QDouble) {
+        double *a = __QuadDoubleInstPtr(self)->d_quadDoubleValue;
+        double *b = __QuadDoubleInstPtr(aQDouble)->d_quadDoubleValue;
+        OBJ newQD;
+// sloppy        
+        double p0, p1, p2, p3, p4, p5;
+        double q0, q1, q2, q3, q4, q5;
+        double t0, t1;
+        double s0, s1, s2;
+
+        m_two_prod(p0, a[0], b[0], q0);
+
+        m_two_prod(p1, a[0], b[1], q1);
+        m_two_prod(p2, a[1], b[0], q2);
+
+        m_two_prod(p3, a[0], b[2], q3);
+        m_two_prod(p4, a[1], b[1], q4);
+        m_two_prod(p5, a[2], b[0], q5);
+
+        /* Start Accumulation */
+        m_three_sum(p1, p2, q0);
+
+        /* Six-Three Sum  of p2, q1, q2, p3, p4, p5. */
+        m_three_sum(p2, q1, q2);
+        m_three_sum(p3, p4, p5);
+        /* compute (s0, s1, s2) = (p2, q1, q2) + (p3, p4, p5). */
+        m_two_sum(s0, p2, p3, t0);
+        m_two_sum(s1, q1, p4, t1);
+        s2 = q2 + p5;
+        m_two_sum(s1, s1, t0, t0);
+        s2 += (t0 + t1);
+
+        /* O(eps^3) order terms */
+        s1 += a[0]*b[3] + a[1]*b[2] + a[2]*b[1] + a[3]*b[0] + q0 + q3 + q4 + q5;
+        m_renorm5(p0, p1, s0, s1, s2);
+
+        __qNew_qdReal(newQD, p0, p1, s0, s1);
+        RETURN( newQD );
+    }
+%}.
+    ^ super productFromQDouble:aQDouble.
+
+    "
+     2.0 * (QDouble fromFloat:1.0)
+     1e20 * (QDouble fromFloat:1.0)
+     (2.0 * (QDouble fromFloat:1.0)) asFloat
+     (1e20 * (QDouble fromFloat:1.0)) asFloat
+
+     (1e20 * (QDouble fromFloat:1.0) * 1e-20) asDoubleArray
+    "
+
+    "Created: / 13-06-2017 / 01:06:22 / cg"
+!
+
+squared
+%{
+    double *a = __QuadDoubleInstPtr(self)->d_quadDoubleValue;
+    double p0, p1, p2, p3, p4, p5;
+    double q0, q1, q2, q3;
+    double s0, s1;
+    double t0, t1;
+    double t;
+    OBJ newQD;
+    
+    m_two_sqr(p0, a[0], q0);
+    t = 2.0 * a[0];
+
+    m_two_prod(p1, t, a[1], q1);
+    m_two_prod(p2, t, a[2], q2);
+    m_two_sqr(p3, a[1], q3);
+
+    m_two_sum(p1, q0, p1, q0);
+
+    m_two_sum(q0, q0, q1, q1);
+    m_two_sum(p2, p2, p3, p3);
+
+    m_two_sum(s0, q0, p2, t0);
+    m_two_sum(s1, q1, p3, t1);
+
+    m_two_sum(s1, s1, t0, t0);
+    t0 += t1;
+
+    m_quick_two_sum(s1, s1, t0, t0);
+    m_quick_two_sum(p2, s0, s1, t1);
+    m_quick_two_sum(p3, t1, t0, q0);
+
+    p4 = 2.0 * a[0] * a[3];
+    p5 = 2.0 * a[1] * a[2];
+
+    m_two_sum(p4, p4, p5, p5);
+    m_two_sum(q2, q2, q3, q3);
+
+    m_two_sum(t0, p4, q2, t1);
+    t1 = t1 + p5 + q3;
+
+    m_two_sum(p3, p3, t0, p4);
+    p4 = p4 + q0 + t1;
+
+    m_renorm5(p0, p1, p2, p3, p4);
+
+    __qNew_qdReal(newQD, p0, p1, s0, s1);
+    RETURN( newQD );
+%}.
+
+    "
+     (QDouble fromFloat:4.0) squared
+     (1e20 + (QDouble fromFloat:1.0)) squared 
+    "
+
+    "Created: / 13-06-2017 / 01:27:58 / cg"
+!
+
+sumFromFloat:aFloat
+%{
+    if (__isFloatLike(aFloat)) {
+        double *a = __QuadDoubleInstPtr(self)->d_quadDoubleValue; 
+        double b = __floatVal(aFloat);
+        double c0, c1, c2, c3;
+        double e;
+        OBJ newQD;
+
+        m_two_sum(c0, a[0], b, e);
+        m_two_sum(c1 ,a[1], e, e);
+        m_two_sum(c2, a[2], e, e);
+        m_two_sum(c3, a[3], e, e);
+
+        m_renorm5(c0, c1, c2, c3, e);
+        __qNew_qdReal(newQD, c0, c1, c2, c3);
+        RETURN( newQD );
+    }
+%}.
+    ^ super sumFromFloat:aFloat.
+
+    "
+     1.0 + (QDouble fromFloat:1.0)
+     1e20 + (QDouble fromFloat:1.0)
+     (1.0 + (QDouble fromFloat:1.0)) asFloat
+     (1e20 + (QDouble fromFloat:1.0)) asFloat
+
+     (1.0 + (QDouble fromFloat:1.0)) asDoubleArray
+     (1e20 + (QDouble fromFloat:1.0)) asDoubleArray
+     (1e20 + (QDouble fromFloat:1.0) + 1e-20) asDoubleArray
+    "
+
+    "Created: / 12-06-2017 / 17:16:41 / cg"
+    "Modified: / 12-06-2017 / 22:57:03 / cg"
+!
+
+sumFromQDouble:aQDouble
+%{
+    if (__Class(aQDouble) == QDouble) {
+        double *a = __QuadDoubleInstPtr(self)->d_quadDoubleValue;
+        double *b = __QuadDoubleInstPtr(aQDouble)->d_quadDoubleValue;
+        OBJ newQD;
+        
+#ifndef QD_IEEE_ADD
+        // sloppy_add...
+
+        /*
+        double s0, s1, s2, s3;
+        double t0, t1, t2, t3;
+
+        m_two_sum(s0, a[0], b[0], t0);
+        m_two_sum(s1, a[1], b[1], t1);
+        m_two_sum(s2, a[2], b[2], t2);
+        m_two_sum(s3, a[3], b[3], t3);
+
+        m_two_sum(s1, s1, t0, t0);
+        m_three_sum(s2, t0, t1);
+        m_three_sum2(s3, t0, t2);
+        t0 = t0 + t1 + t3;
+
+        m_renorm5(s0, s1, s2, s3, t0);
+        return qd_real(s0, s1, s2, s3, t0);
+        */
+
+        /* Same as above, but addition re-organized to minimize
+           data dependency ... unfortunately some compilers are
+           not very smart to do this automatically */
+        double s0, s1, s2, s3;
+        double t0, t1, t2, t3;
+
+        double v0, v1, v2, v3;
+        double u0, u1, u2, u3;
+        double w0, w1, w2, w3;
+        
+        s0 = a[0] + b[0];
+        s1 = a[1] + b[1];
+        s2 = a[2] + b[2];
+        s3 = a[3] + b[3];
+
+        v0 = s0 - a[0];
+        v1 = s1 - a[1];
+        v2 = s2 - a[2];
+        v3 = s3 - a[3];
+
+        u0 = s0 - v0;
+        u1 = s1 - v1;
+        u2 = s2 - v2;
+        u3 = s3 - v3;
+
+        w0 = a[0] - u0;
+        w1 = a[1] - u1;
+        w2 = a[2] - u2;
+        w3 = a[3] - u3;
+
+        u0 = b[0] - v0;
+        u1 = b[1] - v1;
+        u2 = b[2] - v2;
+        u3 = b[3] - v3;
+
+        t0 = w0 + u0;
+        t1 = w1 + u1;
+        t2 = w2 + u2;
+        t3 = w3 + u3;
+
+        m_two_sum(s1, s1, t0, t0);
+        m_three_sum(s2, t0, t1);
+        m_three_sum2(s3, t0, t2);
+        t0 = t0 + t1 + t3;
+
+        /* renormalize */
+        m_renorm5(s0, s1, s2, s3, t0);
+        __qNew_qdReal(newQD, s0, s1, s2, s3);
+        RETURN(newQD);                 
+#else
+        // ieee_add...
+        int i, j, k;
+        double s, t;
+        double u, v;   /* double-length accumulator */
+        double x[4] = {0.0, 0.0, 0.0, 0.0};
+
+        i = j = k = 0;
+        if (abs(a[i]) > abs(b[j]))
+          u = a[i++];
+        else
+          u = b[j++];
+        if (abs(a[i]) > abs(b[j]))
+          v = a[i++];
+        else
+          v = b[j++];
+
+        u = quick_two_sum(u, v, v);
+
+        while (k < 4) {
+          if (i >= 4 && j >= 4) {
+            x[k] = u;
+            if (k < 3)
+              x[++k] = v;
+            break;
+          }
+
+          if (i >= 4)
+            t = b[j++];
+          else if (j >= 4)
+            t = a[i++];
+          else if (abs(a[i]) > abs(b[j])) {
+            t = a[i++];
+          } else
+            t = b[j++];
+
+          s = quick_three_accum(u, v, t);
+
+          if (s != 0.0) {
+            x[k++] = s;
+          }
+        }
+
+        /* add the rest. */
+        for (k = i; k < 4; k++)
+          x[3] += a[k];
+        for (k = j; k < 4; k++)
+          x[3] += b[k];
+
+        m_renorm4(x[0], x[1], x[2], x[3]);
+        __qNew_qdReal(newQD, x[0], x[1], x[2], x[3]);
+        RETURN(newQD);                 
+#endif
+    }
+%}.
+    ^ super sumFromQDouble:aQDouble
+    
+    "
+     (QDouble fromFloat:1.0) + (QDouble fromFloat:1.0)
+     (QDouble fromFloat:1.0) + 1.0
+     1.0 + (QDouble fromFloat:1.0)
+
+     ((QDouble fromFloat:1.0) + (QDouble fromFloat:1.0)) asDoubleArray
+     ((QDouble fromFloat:1.0) + 1.0) asDoubleArray
+     (1.0 + (QDouble fromFloat:1.0)) asDoubleArray
+     (1e-20 + (QDouble fromFloat:1.0)) asDoubleArray
+     (1e20 + (QDouble fromFloat:1.0)) asDoubleArray
+   "
+
+    "Created: / 12-06-2017 / 21:15:43 / cg"
+    "Modified: / 13-06-2017 / 00:30:45 / cg"
+! !
+
+!QDouble methodsFor:'inspecting'!
+
+inspectorExtraAttributes
+    "extra (pseudo instvar) entries to be shown in an inspector."
+
+    ^ super inspectorExtraAttributes
+        add:'-{doubles}' ->
+            [
+                self asDoubleArray printString
+            ];
+        yourself
+
+    "Created: / 12-06-2017 / 23:43:05 / cg"
+! !
+
+!QDouble methodsFor:'printing & storing'!
+
+printString
+    "return a printed representation of the receiver"
+
+    self d1 = 0.0 ifTrue:[
+        ^ self d0 printString
+    ].
+    ^ self d0 printString , '...'
+
+    "Created: / 12-06-2017 / 23:41:04 / cg"
+! !
+
+!QDouble methodsFor:'private accessing'!
+
+d0
+%{
+    RETURN ( __MKFLOAT(__QuadDoubleInstPtr(self)->d_quadDoubleValue[0]) ); 
+%}
+
+    "Created: / 12-06-2017 / 20:15:12 / cg"
+!
+
+d1
+%{
+    RETURN ( __MKFLOAT(__QuadDoubleInstPtr(self)->d_quadDoubleValue[1]) ); 
+%}
+
+    "Created: / 12-06-2017 / 20:15:12 / cg"
+!
+
+d2
+%{
+    RETURN ( __MKFLOAT(__QuadDoubleInstPtr(self)->d_quadDoubleValue[2]) ); 
+%}
+
+    "Created: / 12-06-2017 / 20:15:29 / cg"
+!
+
+d3
+%{
+    RETURN ( __MKFLOAT(__QuadDoubleInstPtr(self)->d_quadDoubleValue[3]) ); 
+%}
+
+    "Created: / 12-06-2017 / 20:15:32 / cg"
+! !
+
+!QDouble class methodsFor:'documentation'!
+
+version
+    ^ '$Header$'
+!
+
+version_CVS
+    ^ '$Header$'
+! !
+