[CLN-list] A silly program

Richard B. Kreckel kreckel at thep.physik.uni-mainz.de
Wed Nov 24 00:27:03 CET 2004


On Sat, 20 Nov 2004, Richard B. Kreckel wrote:
> On Fri, 19 Nov 2004, Isidro [iso-8859-15] Cachadiña Gutiérrez wrote:
> > I don't know if I'm wrong, but why are not defined elsewhere
> >
> > cln::operator-(const float , const cln::cl_R&)
> >
> > and some with double, etc. to compile this silly program.
> >
> > #include <cln/real.h>
> > int main(int argc, char **argv)
> > {
> >   cln::cl_F a,b;
> >   a=1;
> >   b=1.0-a;
> > }
>
> Hmm, good question.  Did you notice that b=1-a works because there is
> oerator-(int, const cl_F&)?  So, this looks like an omission to me. I'm
> just wondering if it wouldn't be better to templatize the fallthrough case
> after all the special integer inline helpers, like this:
>
> template< typename T >
> inline const cl_F operator+ (const T& x, const cl_F& y)
> { return cl_F(x) + y; }
>
> and so on.  That should match anything that can be converted to cl_F,
> then, in particular double and float.  I'm also wondering whether that
> would be safe enough: maybe one could apply some cute traits-trick?  Or
> maybe one shouldn't try to be clever and just write down the operators
> in a straightfoward way since there are only two interesting cases?

Actually, the situation is more involved.  This is due to CLN's type
system, automatic conversions and all that syntactic sugar of
overloading operator@, where @ stands for `+', `-', `*' or `/'.  *)

First, you dodged the question of the return type.  What should
cln::operator@(float, const cln::cl_R&) return?  Is it just to
conveniently save a few keystrokes and should hence return a cln::cl_R?
No, wait!  cln::cl_R can have arbitrary precision but we do know the
resulting precision cannot be better than that of float or double,
respectively.  It would be wrong to return anything other than cl_FF or
cl_DF; why return a base type?  Okay, that'ld leave us with implementing:

inline const cl_FF operator@ (const cl_R& x, const float y)
	{ return float_approx(x) @ y; }
inline const cl_FF operator@ (const float x, const cl_R& y)
	{ return x @ float_approx(y); }

and the same for double.  And possibly for cl_F due to efficiency
concerns.  In any case, that operator@ can hardly be said to be an
operation in cl_R any more, because it always reduces its arguments
precision-wise and does so even by declaration!  This is why I am
reluctant about such operators.  If a user wants his nice 1000 digit
precision computation to decay he should be forced to state so
explicitly.


Second, there are two cages in CLN's type zoo where the helper operator+
you propose would make perfect sense.  The beasts therein are cl_FF and
cl_DF, where there are no doubts about the intent of:

    cl_DF a,b;
    a = 1.;
    b = 1. @ a;

But that turns out to be not possible to write.  I think that it was
Bruno's intent that such code should be legal.  After all, there is
conversion from float/double to cl_FF/cl_DF via (non-explicit) ctors and
assignment operators.  The last line is actually:

    b.cl_DF::operator=(operator+(double,cl_DF))

and then automatic conversion from double to cl_DF should kick in and
presto.  However, as soon as the header <cln/dfloat.h> is mixed with
<cln/float.h>, some ambiguousitis arises.  The compiler tells us that it
doesn't know which of these candidates to pick:

const cln::cl_F cln::operator@(const cln::cl_F&, const cln::cl_F&)
const cln::cl_F cln::operator@(const cln::cl_RA&, const cln::cl_F&)
const cln::cl_F cln::operator@(const cln::cl_I&, const cln::cl_F&)
const cln::cl_F cln::operator@(int, const cln::cl_F&)
const cln::cl_F cln::operator@(unsigned int, const cln::cl_F&)
const cln::cl_F cln::operator@(long int, const cln::cl_F&)
const cln::cl_F cln::operator@(long unsigned int, const cln::cl_F&)
const cln::cl_F cln::operator@(const cln::cl_F&, int) <near match>
const cln::cl_F cln::operator@(const cln::cl_F&, unsigned int) <near match>
const cln::cl_F cln::operator@(const cln::cl_F&, long int) <near match>
const cln::cl_F cln::operator@(const cln::cl_F&, long unsigned int) <near match>
const cln::cl_DF cln::operator@(const cln::cl_DF&, const cln::cl_DF&)

Note that the one we want occurs in the last line and isn't even a near
match.  Unfortunately, <cln/dfloat.h> pulls in <cln/float.h> all by
itself.  :-(

Well, then.  Should we be able to write that?  I take the stance that
yes, we should.  After all, this seems to be just a glitch where the
intented conversion fails due to unforseen interferences.  I've
attached a patch.  It hasn't received much testing.  Does that patch
look reasonable?

Regards
   -richy.

*) "Syntactic sugar causes cancer of the semicolon." -- Alan Perlis
-- 
Richard B. Kreckel
<http://www.ginac.de/~kreckel/>
-------------- next part --------------
diff -Naur cln.orig/include/cln/dfloat.h cln/include/cln/dfloat.h
--- cln.orig/include/cln/dfloat.h       2004-11-23 22:57:11.000000000 +0100
+++ cln/include/cln/dfloat.h    2004-11-24 00:08:11.000000000 +0100
@@ -47,18 +47,38 @@
 
 // Liefert zu zwei Double-Float x und y : (+ x y), ein DF.
 extern const cl_DF operator+ (const cl_DF& x, const cl_DF& y);
+// The C++ compiler may be confused about the following:
+inline const cl_DF operator+ (const cl_DF& x, const double y)
+       { return x + cl_DF(y); }
+inline const cl_DF operator+ (const double x, const cl_DF& y)
+       { return cl_DF(x) + y; }
 
 // Liefert zu zwei Double-Float x und y : (- x y), ein DF.
 extern const cl_DF operator- (const cl_DF& x, const cl_DF& y);
+// The C++ compiler may be confused about the following:
+inline const cl_DF operator- (const cl_DF& x, const double y)
+       { return x - cl_DF(y); }
+inline const cl_DF operator- (const double x, const cl_DF& y)
+       { return cl_DF(x) - y; }
 
 // Liefert zu zwei Double-Float x und y : (* x y), ein DF.
 extern const cl_DF operator* (const cl_DF& x, const cl_DF& y);
+// The C++ compiler may be confused about the following:
+inline const cl_DF operator* (const cl_DF& x, const double y)
+       { return x * cl_DF(y); }
+inline const cl_DF operator* (const double x, const cl_DF& y)
+       { return cl_DF(x) * y; }
 
 // Liefert zu einem Double-Float x : (* x x), ein DF.
 inline const cl_DF square (const cl_DF& x) { return x*x; }
 
 // Liefert zu zwei Double-Float x und y : (/ x y), ein DF.
 extern const cl_DF operator/ (const cl_DF& x, const cl_DF& y);
+// The C++ compiler may be confused about the following:
+inline const cl_DF operator/ (const cl_DF& x, const double y)
+       { return x / cl_DF(y); }
+inline const cl_DF operator/ (const double x, const cl_DF& y)
+       { return cl_DF(x) / y; }
 
 // Liefert zu einem Double-Float x>=0 : (sqrt x), ein DF.
 extern const cl_DF sqrt (const cl_DF& x);
diff -Naur cln.orig/include/cln/ffloat.h cln/include/cln/ffloat.h
--- cln.orig/include/cln/ffloat.h       2004-11-23 22:57:11.000000000 +0100
+++ cln/include/cln/ffloat.h    2004-11-22 23:46:30.000000000 +0100
@@ -47,18 +47,38 @@
 
 // Liefert zu zwei Single-Float x und y : (+ x y), ein FF.
 extern const cl_FF operator+ (const cl_FF& x, const cl_FF& y);
+// The C++ compiler may be confused about the following:
+inline const cl_FF operator+ (const cl_FF& x, const float y)
+       { return x + cl_FF(y); }
+inline const cl_FF operator+ (const float x, const cl_FF& y)
+       { return cl_FF(x) + y; }
 
 // Liefert zu zwei Single-Float x und y : (- x y), ein FF.
 extern const cl_FF operator- (const cl_FF& x, const cl_FF& y);
+// The C++ compiler may be confused about the following:
+inline const cl_FF operator- (const cl_FF& x, const float y)
+       { return x - cl_FF(y); }
+inline const cl_FF operator- (const float x, const cl_FF& y)
+       { return cl_FF(x) - y; }
 
 // Liefert zu zwei Single-Float x und y : (* x y), ein FF.
 extern const cl_FF operator* (const cl_FF& x, const cl_FF& y);
+// The C++ compiler may be confused about the following:
+inline const cl_FF operator* (const cl_FF& x, const float y)
+       { return x * cl_FF(y); }
+inline const cl_FF operator* (const float x, const cl_FF& y)
+       { return cl_FF(x) * y; }
 
 // Liefert zu einem Single-Float x : (* x x), ein FF.
 inline const cl_FF square (const cl_FF& x) { return x*x; }
 
 // Liefert zu zwei Single-Float x und y : (/ x y), ein FF.
 extern const cl_FF operator/ (const cl_FF& x, const cl_FF& y);
+// The C++ compiler may be confused about the following:
+inline const cl_FF operator/ (const cl_FF& x, const float y)
+       { return x / cl_FF(y); }
+inline const cl_FF operator/ (const float x, const cl_FF& y)
+       { return cl_FF(x) / y; }
 
 // Liefert zu einem Single-Float x>=0 : (sqrt x), ein FF.
 extern const cl_FF sqrt (const cl_FF& x);


More information about the CLN-list mailing list