Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

long double versions of functions in gcc under Cygwin

14 views
Skip to first unread message

lcw1964

unread,
Aug 7, 2006, 7:33:32 PM8/7/06
to
Greetings, all,

I am trying to port a little bit of math code to gcc, that in the
original version used the long double version of several functions (in
particular, atanl, fabsl, and expl).

I get a complie-time "unidentified reference" error to the expl()
calls, but gcc seems to digest atanl and fabsl just fine. Changing expl
to exp cures the compile time problem, but I get at best double
precision in the final results. I am assuming that the use of exp() vs.
expl() is the weak link.

The GCC documentation seems to imply that expl() is supported, but I
have no idea where to find it or how to link it in properly. For that
matter, I can't seem to find prototypes in math.h for fabsl or atanl,
and they don't make gcc cough at all.

I hope this tenderfoot can find some direction, or I may resort to
singing the praises of the egregiously un-portable lcc-win32 with its
impressive 100+ digit precision qfloat library ;)

cheers,

Les

p.s. I am trying to keep this simple, so if there is a solution within
the main gcc offerings without me having to turn to the GSL, I would
like to try that first.

Keith Thompson

unread,
Aug 7, 2006, 7:51:40 PM8/7/06
to

gcc is a compiler, not a complete C implementation. (Actually gcc is
a collection of compilers, but for our purposes here we can consider
only the C compiler.) The math functions are implemented by the
runtime library, not by the compiler.

In some implementations, the compiler and the runtime library are
provided together. gcc, however, generally uses whatever runtime
library is provided by the underlying operating system. On some
systems, the C runtime library happens to be one that, like gcc, is
also provided by the GNU project. I suspect you're using a system
where that isn't the case.

I suggest you ask in a newsgroup that deals with your operating system
(probably MS Windows given your mention of lcc-win32 as an
alternative).

(I don't know whether lcc-win32 provides its own C runtime library;
check the web site or ask in comp.compilers.lcc if you want more
information.)

--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.

lcw1964

unread,
Aug 7, 2006, 8:58:35 PM8/7/06
to
Keith Thompson wrote:
>
> In some implementations, the compiler and the runtime library are
> provided together. gcc, however, generally uses whatever runtime
> library is provided by the underlying operating system. On some
> systems, the C runtime library happens to be one that, like gcc, is
> also provided by the GNU project. I suspect you're using a system
> where that isn't the case.
>


I think you are right, and I was afraid it had something to do with
that.

I am learning quickly that if I wish to make the most out of higher
precision math programming, it behooves me to expand my horizons and
develop some facility with a high or even arbitrary precision package,
though I must admit that some of the source code I have contemplated
looks daunting indeed for this beginner.

In the meantime, lcc-win32 seems a reasonable, though admittedly
non-portable option. Messr. Navia's implementation of the Cephes qfloat
library seems pretty robust and at least in my barely ept hands
produces prodigious results with surprising little change to code. For
example, the very code that I am having trouble getting full long
double results with gcc/Cygwin with lcc-win32/qfloat routinely gives
102-105 digit accuracy most of the time, and at least 100 digits all of
the time. It is simply a matter of including qfloat.h, change various
commands to their qfloat equivalents (atoq, expq, atanq, etc.),
appending a q to floating point constants, and properly formatting the
output strings for printf or whatever. For my limited personal
purposes, it is about the best option I have hit upon so far, though I
do admit that cross-platform and cross-compiler compatibility would be
much more vital if my interests were less parochial.

Thanks for the feedback, though I must admit it leaves me with 3.1 gigs
of Cygwin on my hard drive that I don't know quite what to do with ;)

Les

Dann Corbit

unread,
Aug 7, 2006, 10:38:14 PM8/7/06
to
"lcw1964" <leslie...@alumni.uwo.ca> wrote in message
news:1154993612.2...@m73g2000cwd.googlegroups.com...

> Greetings, all,
>
> I am trying to port a little bit of math code to gcc, that in the
> original version used the long double version of several functions (in
> particular, atanl, fabsl, and expl).
>
> I get a complie-time "unidentified reference" error to the expl()
> calls, but gcc seems to digest atanl and fabsl just fine. Changing expl
> to exp cures the compile time problem, but I get at best double
> precision in the final results. I am assuming that the use of exp() vs.
> expl() is the weak link.
>
> The GCC documentation seems to imply that expl() is supported, but I
> have no idea where to find it or how to link it in properly. For that
> matter, I can't seem to find prototypes in math.h for fabsl or atanl,
> and they don't make gcc cough at all.
>
> I hope this tenderfoot can find some direction, or I may resort to
> singing the praises of the egregiously un-portable lcc-win32 with its
> impressive 100+ digit precision qfloat library ;)

The qfloat library is by S. Moshier. You can find qfloat along with the
Cephes collection (which has tons of long double math functions) here:

http://www.moshier.net/#Cephes

lcw1964

unread,
Aug 7, 2006, 11:28:38 PM8/7/06
to

Dann Corbit wrote:
>
> The qfloat library is by S. Moshier. You can find qfloat along with the
> Cephes collection (which has tons of long double math functions) here:
>
> http://www.moshier.net/#Cephes
>

Thank you! I should have given Mr. Moshier proper credit. I am also
aware of the link you referred me to, my right now porting those
libraries to GCC is a little beyond my skill set, so being able to
access the qfloat functionality thru Mr. Navia's lcc-win32 "wrapper" is
a good start.

Les

Dann Corbit

unread,
Aug 8, 2006, 12:11:08 AM8/8/06
to
"lcw1964" <leslie...@alumni.uwo.ca> wrote in message
news:1155007718.7...@n13g2000cwa.googlegroups.com...

You don't have to know anything. They come with their own makefiles.

At most, you will have to know what kind of machine you are compiling on (if
it is not a 32 bit platform or has odd endianness or something).

The standard makefile will probably fit your situation.

Just expand this archive:
http://www.moshier.net/qlib.zip
and type "make"

The Cephes functions are even the default math functions used in some linux
distributions (IIRC).


jaysome

unread,
Aug 8, 2006, 4:04:27 AM8/8/06
to
On Mon, 7 Aug 2006 21:11:08 -0700, "Dann Corbit" <dco...@connx.com>
wrote:

There are 477 usages of "goto" in this source. That gives me a queasy
feeling.

One part of me sees me sitting through a code review and vehemently
rebuking this code after coming across about the 5th goto statement.
The other part of me sees me reviewing the black box test results that
passed and not caring about how this was coded, as long as it was
coded in Standard C. Oh the dichotomy.

--
Jay

jacob navia

unread,
Aug 8, 2006, 4:37:54 AM8/8/06
to
jaysome a écrit :

> There are 477 usages of "goto" in this source. That gives me a queasy
> feeling.
>

I rewrote all the basic functions in 386 and AMD64 assembly.
The speed gain is considerable, and the gotos are even worst:

Who hasn't written a

jmp label

in assembly?

Seriously, the code is well written, and if you look at the
dates in there you will se code from eighties. And it still runs,
twenty years later.

I would like to see what code you have written in 20 years, even
if it doesn't use gotos.

Stephen Moshier has written a very good package.


> One part of me sees me sitting through a code review and vehemently
> rebuking this code after coming across about the 5th goto statement.

This is just dogmatic. gotos arre part of C. And they are used in
the Cephes library in a reasonable and very clear way.

pete

unread,
Aug 8, 2006, 7:37:42 AM8/8/06
to
lcw1964 wrote:

> expl()

#include <float.h>

long double fs_expl(long double x);
long double fs_logl(long double x);
long double fs_sqrtl(long double x);

long double fs_expl(long double x)
{
long unsigned n, square;
long double b, e;
static long double x_max, x_min;

if (1 > x_max) {
x_max = fs_logl(LDBL_MAX);
x_min = fs_logl(LDBL_MIN);
}
if (x_max >= x && x >= x_min) {
for (square = 0; x > 1; x /= 2) {
++square;
}
while (-1 > x) {
++square;
x /= 2;
}
e = b = n = 1;
do {
b /= n++;
b *= x;
e += b;
b /= n++;
b *= x;
e += b;
} while (b > LDBL_EPSILON / 4);
while (square-- != 0) {
e *= e;
}
} else {
e = x > 0 ? LDBL_MAX : 0;
}
return e;
}

long double fs_logl(long double x)
{
long int n;
long double a, b, c, epsilon;
static long double A, B, C;

if (LDBL_MAX >= x && x > 0) {
if (1 > A) {
A = fs_sqrtl(2);
B = A / 2;
C = fs_logl(A);
}
for (n = 0; x > A; x /= 2) {
++n;
}
while (B > x) {
--n;
x *= 2;
}
a = (x - 1) / (x + 1);
x = C * n + a;
c = a * a;
n = 1;
epsilon = LDBL_EPSILON * x;
if (0 > a) {
if (epsilon > 0) {
epsilon = -epsilon;
}
do {
n += 2;
a *= c;
b = a / n;
x += b;
} while (epsilon > b);
} else {
if (0 > epsilon) {
epsilon = -epsilon;
}
do {
n += 2;
a *= c;
b = a / n;
x += b;
} while (b > epsilon);
}
x *= 2;
} else {
x = -LDBL_MAX;
}
return x;
}

long double fs_sqrtl(long double x)
{
long int n;
long double a, b;

if (LDBL_MAX >= x && x > 0) {
for (n = 0; x > 2; x /= 4) {
++n;
}
while (0.5 > x) {
--n;
x *= 4;
}
a = x;
b = (1 + x) / 2;
do {
x = b;
b = (a / x + x) / 2;
} while (x > b);
while (n > 0) {
x *= 2;
--n;
}
while (0 > n) {
x /= 2;
++n;
}
} else {
if (x != 0) {
x = LDBL_MAX;
}
}
return x;
}

--
pete

jacob navia

unread,
Aug 8, 2006, 8:22:07 AM8/8/06
to
pete a écrit :

I find this code well DOCUMENTED isn't it?

The source of the code (who wrote it originally), the algorithms
used are well explained, the places in the code where you have to
watch for accuracy are pointed out, a nice package.

fs_sqrt is approximately 20 times slower
than the library function.

pete

unread,
Aug 8, 2006, 8:41:06 AM8/8/06
to
jacob navia wrote:
>
> pete a écrit :

> > long double fs_sqrtl(long double x);

> fs_sqrt is approximately 20 times slower
> than the library function.

OP didn't say if sqrtl was available.

--
pete

lcw1964

unread,
Aug 8, 2006, 11:09:20 AM8/8/06
to

jacob navia wrote:
>
> I find this code well DOCUMENTED isn't it?
>
> The source of the code (who wrote it originally), the algorithms
> used are well explained, the places in the code where you have to
> watch for accuracy are pointed out, a nice package.
>
> fs_sqrt is approximately 20 times slower
> than the library function.

i appreciate this code being shared. I don't want to get get caught in
the middle of barbed repartee, but I have to admit some editorial
comments would have been helpful, especially for a neophyte like me.

i must admit i am a little perplexed that my initial question, which i
thought was straightforward, was not answered--namely, when I use gcc
under Cygwin and try to call long double expl(long double), a function
that works perfectly well when I compile under Borland C++ or
lcc-win32, I get an unknown identifier error, whereas fabsl and sqrtl
work fine. Forgive my naivete, but I thought that expl() was a standard
C function, and if I am including the wrong files or should be linking
in something else, I would like to know.

if i have already been given my answer please forgive me for missing
the point and I will try to reread what has been offered and change my
ways.

many thanks,

Les

Kenny McCormack

unread,
Aug 8, 2006, 11:24:57 AM8/8/06
to
In article <1155049760....@p79g2000cwp.googlegroups.com>,
lcw1964 <leslie...@alumni.uwo.ca> wrote:
...

>i must admit i am a little perplexed that my initial question, which i
>thought was straightforward, was not answered--namely, when I use gcc
>under Cygwin and try to call long double expl(long double), a function
>that works perfectly well when I compile under Borland C++ or
>lcc-win32, I get an unknown identifier error, whereas fabsl and sqrtl

Anything that involves brand names is OT here.

Richard

unread,
Aug 8, 2006, 11:33:43 AM8/8/06
to
gaz...@xmission.xmission.com (Kenny McCormack) writes:

Even if a "standards" solution solves his issues? Frequently using the
correct way fixes issues with the "platorm special" way - its why many
people ask C questions here I would have thought.

Frederick Gotham

unread,
Aug 8, 2006, 12:50:31 PM8/8/06
to

Troll Alert: Kenny McCormack

The only way to deal with trolls is to limit your reaction to reminding
others not to respond to trolls.

Information on trolls: http://members.aol.com/intwg/trolls.htm

--

Frederick Gotham

jacob navia

unread,
Aug 8, 2006, 1:49:41 PM8/8/06
to
lcw1964 wrote:

> i must admit i am a little perplexed that my initial question, which i
> thought was straightforward, was not answered--namely, when I use gcc
> under Cygwin and try to call long double expl(long double), a function
> that works perfectly well when I compile under Borland C++ or
> lcc-win32, I get an unknown identifier error, whereas fabsl and sqrtl
> work fine. Forgive my naivete, but I thought that expl() was a standard
> C function, and if I am including the wrong files or should be linking
> in something else, I would like to know.
>
> if i have already been given my answer please forgive me for missing
> the point and I will try to reread what has been offered and change my
> ways.
>
> many thanks,
>
> Les
>

Obviously this is a bug. You could report it to them, maybe they
are interested in knowing about it. There must be some mailing
list in the cygwin docs. I was subscribed ages ago.

Under linux:
[root@gateway tmp]# cat texpl.c
#include <stdio.h>
#include <math.h>
int main(void)
{
long double n = expl(1.0L);
printf("%Lg\n",n);
return 0;
}
[root@gateway tmp]# gcc texpl.c -lm
[root@gateway tmp]# ./a.out
2.71828
[root@gateway tmp]#

this works, so it must be a bug in the cygwin environment/library.

lcw1964

unread,
Aug 8, 2006, 3:44:02 PM8/8/06
to


Messr. Navia, that worked for me.

The key is the addition of the -lm parameter to the command line, which
I did not have before.

I suspect that I have made an embarassing beginner's error and have
stirred up a lot of hubbub unnecessarily!

I have no idea what those three little characters mean (-lm), but
something tells me that before I post my next newbie question I do a
little more homework first.

Les

Keith Thompson

unread,
Aug 8, 2006, 3:49:10 PM8/8/06
to
"lcw1964" <leslie...@alumni.uwo.ca> writes:
[...]

> i must admit i am a little perplexed that my initial question, which i
> thought was straightforward, was not answered--namely, when I use gcc
> under Cygwin and try to call long double expl(long double), a function
> that works perfectly well when I compile under Borland C++ or
> lcc-win32, I get an unknown identifier error, whereas fabsl and sqrtl
> work fine. Forgive my naivete, but I thought that expl() was a standard
> C function, and if I am including the wrong files or should be linking
> in something else, I would like to know.

expl() is defined by the C99 standard, but not by the older C90
standard. Since C99 is not yet implemented as widely as C90, a given
implementation might not support expl(). (C90 has exp() which takes
and returns a double; C99 adds expf() and expl().)

You might find that exp() is good enough. If not, you'll have to find
another solution.

For more information, try the Cygwin mailing list; see www.cygwin.com
for links.

Dann Corbit

unread,
Aug 8, 2006, 3:03:11 PM8/8/06
to
"jaysome" <jay...@spamcop.net> wrote in message
news:58ggd29fb960dal5t...@4ax.com...

I'm in the Knuth camp:
http://portal.acm.org/citation.cfm?id=356640&dl=&coll=GUIDE&CFID=15151515&CFTOKEN=6184618


> One part of me sees me sitting through a code review and vehemently
> rebuking this code after coming across about the 5th goto statement.
> The other part of me sees me reviewing the black box test results that
> passed and not caring about how this was coded, as long as it was
> coded in Standard C. Oh the dichotomy.

I think Moshier's code is beautiful. It was originally written in 1984, and
later reworked so that you could compile it with ANSI style prototypes.

At the top of every file is a detailed explanation of what the code does,
which equations are used to solve the problem, and what the measured errors
were in calibration of the function's useful range.

Here is a sample, complete with goto (which could be removed, of course):

/* psi.c

* Psi (digamma) function
*
*
* SYNOPSIS:
*
* double x, y, psi();
*
* y = psi( x );
*
*
* DESCRIPTION:
*
* d -
* psi(x) = -- ln | (x)
* dx
*
* is the logarithmic derivative of the gamma function.
* For integer x,
* n-1
* -
* psi(n) = -EUL + > 1/k.
* -
* k=1
*
* This formula is used for 0 < n <= 10. If x is negative, it
* is transformed to a positive argument by the reflection
* formula psi(1-x) = psi(x) + pi cot(pi x).
* For general positive x, the argument is made greater than 10
* using the recurrence psi(x+1) = psi(x) + 1/x.
* Then the following asymptotic expansion is applied:
*
* inf. B
* - 2k
* psi(x) = log(x) - 1/2x - > -------
* - 2k
* k=1 2k x
*
* where the B2k are Bernoulli numbers.
*
* ACCURACY:
* Relative error (except absolute when |psi| < 1):
* arithmetic domain # trials peak rms
* DEC 0,30 2500 1.7e-16 2.0e-17
* IEEE 0,30 30000 1.3e-15 1.4e-16
* IEEE -30,0 40000 1.5e-15 2.2e-16
*
* ERROR MESSAGES:
* message condition value returned
* psi singularity x integer <=0 MAXNUM
*/


/*
Cephes Math Library Release 2.8: June, 2000
Copyright 1984, 1987, 1992, 2000 by Stephen L. Moshier
*/

#include "mconf.h"

#ifdef UNK
static double A[] =
{
8.33333333333333333333E-2,
-2.10927960927960927961E-2,
7.57575757575757575758E-3,
-4.16666666666666666667E-3,
3.96825396825396825397E-3,
-8.33333333333333333333E-3,
8.33333333333333333333E-2
};
#endif

#ifdef DEC
static unsigned short A[] =
{
0037252, 0125252, 0125252, 0125253,
0136654, 0145314, 0126312, 0146255,
0036370, 0037017, 0101740, 0174076,
0136210, 0104210, 0104210, 0104211,
0036202, 0004040, 0101010, 0020202,
0136410, 0104210, 0104210, 0104211,
0037252, 0125252, 0125252, 0125253
};
#endif

#ifdef IBMPC
static unsigned short A[] =
{
0x5555, 0x5555, 0x5555, 0x3fb5,
0x5996, 0x9599, 0x9959, 0xbf95,
0x1f08, 0xf07c, 0x07c1, 0x3f7f,
0x1111, 0x1111, 0x1111, 0xbf71,
0x0410, 0x1041, 0x4104, 0x3f70,
0x1111, 0x1111, 0x1111, 0xbf81,
0x5555, 0x5555, 0x5555, 0x3fb5
};
#endif

#ifdef MIEEE
static unsigned short A[] =
{
0x3fb5, 0x5555, 0x5555, 0x5555,
0xbf95, 0x9959, 0x9599, 0x5996,
0x3f7f, 0x07c1, 0xf07c, 0x1f08,
0xbf71, 0x1111, 0x1111, 0x1111,
0x3f70, 0x4104, 0x1041, 0x0410,
0xbf81, 0x1111, 0x1111, 0x1111,
0x3fb5, 0x5555, 0x5555, 0x5555
};
#endif

#define EUL 0.57721566490153286061

#ifdef ANSIPROT
extern double floor(double);
extern double log(double);
extern double tan(double);
extern double polevl(double, void *, int);
#else
double floor(), log(), tan(), polevl();
#endif
extern double PI,
MAXNUM;


double psi(x)
double x;
{
double p,
q,
nz,
s,
w,
y,
z;
int i,
n,
negative;

negative = 0;
nz = 0.0;

if (x <= 0.0) {
negative = 1;
q = x;
p = floor(q);
if (p == q) {
mtherr("psi", SING);
return (MAXNUM);
}
/* Remove the zeros of tan(PI x)
* by subtracting the nearest integer from x
*/
nz = q - p;
if (nz != 0.5) {
if (nz > 0.5) {
p += 1.0;
nz = q - p;
}
nz = PI / tan(PI * nz);
} else {
nz = 0.0;
}
x = 1.0 - x;
}
/* check for positive integer up to 10 */
if ((x <= 10.0) && (x == floor(x))) {
y = 0.0;
n = x;
for (i = 1; i < n; i++) {
w = i;
y += 1.0 / w;
}
y -= EUL;
goto done;
}
s = x;
w = 0.0;
while (s < 10.0) {
w += 1.0 / s;
s += 1.0;
}

if (s < 1.0e17) {
z = 1.0 / (s * s);
y = z * polevl(z, A, 6);
} else
y = 0.0;

y = log(s) - (0.5 / s) - y - w;

done:

if (negative) {
y -= nz;
}
return (y);
}

> --
> Jay
>


lcw1964

unread,
Aug 8, 2006, 4:29:53 PM8/8/06
to

Actually I spoke too soon!

The following variant of M. Navia's example generates the error too:

#include <stdio.h>
#include <math.h>
int main(void)

{ long double x;
x = 1.0L;
long double n = expl(x);
printf("%.20Lg\n",n);
return 0;
}

So too does this variant, where the argument is other than 1.0L:

#include <stdio.h>
#include <math.h>
int main(void)
{

long double n = expl(3.789L);


printf("%Lg\n",n);
return 0;
}

Now I am no C god, and I present myself to you as a lowly plebeian as a
superstitious emperor presents himself to the Oracle of Delphi, but
something tells me that the compiler recognizes the string "expl(1.0L)"
as the constant 2.7182818284590452354, NOT as a call to the long
double version of exp. Try to put anything else between those
parentheses except 1.0L, 1.0, 1--a long double variable or some other
long double constant other than unity--and the compiler regurgitates it
back contemptuously.

It could be a bug in my platform or setup, but if M. Navia or someone
else could experiment with this in gcc under Linux or any other
platform, I would be much obliged. This is driving me bonkers now!!!!!

Les

Keith Thompson

unread,
Aug 8, 2006, 4:44:31 PM8/8/06
to
"lcw1964" <leslie...@alumni.uwo.ca> writes:
> jacob navia wrote:
[...]

>> Obviously this is a bug. You could report it to them, maybe they
>> are interested in knowing about it. There must be some mailing
>> list in the cygwin docs. I was subscribed ages ago.
>>
>> Under linux:
>> [root@gateway tmp]# cat texpl.c
>> #include <stdio.h>
>> #include <math.h>
>> int main(void)
>> {
>> long double n = expl(1.0L);
>> printf("%Lg\n",n);
>> return 0;
>> }
>> [root@gateway tmp]# gcc texpl.c -lm
>> [root@gateway tmp]# ./a.out
>> 2.71828
>> [root@gateway tmp]#
>>
>> this works, so it must be a bug in the cygwin environment/library.
>
> Messr. Navia, that worked for me.
>
> The key is the addition of the -lm parameter to the command line, which
> I did not have before.
>
> I suspect that I have made an embarassing beginner's error and have
> stirred up a lot of hubbub unnecessarily!
>
> I have no idea what those three little characters mean (-lm), but
> something tells me that before I post my next newbie question I do a
> little more homework first.

That's a reasonable conclusion, but I'm afraid it happens to be wrong.

The "-lm" option, in some (mostly Unix-like) implementations, tells
the linker to link in the math library. This is question 14.3 in the
comp.lang.c FAQ, <http://www.c-faq.com/>.

But that's not what's going on here. The following is mostly specific
to Cygwin, and therefore only marginally topical.

Cygwin's implementation happens to be smart enough that it doesn't
need the "-lm" option; it links the math library without being asked
if it needs it.

jacob's program works for me under Cygwin, but only because the
compiler itself is smart enough to replace the expression expl(1.0L)
with its value during compilation. If you change the line


long double n = expl(1.0L);

to
long double one = 1.0L;
long double n = expl(one)
then it fails. If you declare one as "const" and compile with "-O1"
or higher, then it works again.

The compiler is capable of evaluating expl() in some very limited
circumstances. If that fails, it generates a call to expl(), which
doesn't exist in the runtime library (regardless of whether you use
"-lm").

The point is that the compiler and the runtime libraries are two
different part of the implementation. If they're provided separately,
you can see odd behavior if one of them supports a given feature and
the other doesn't.

If "double" precision is good enough, use exp(). If not you'll need
to find another solution. (You might be able to use exp() to create a
close approximation to the correct long double result, but I don't
know how to refine that to the required precision.)

There are open-source C libraries including glibc. You might be able
to extract an expl() implementation from one of them. Google is your
friend.

Keith Thompson

unread,
Aug 8, 2006, 4:54:08 PM8/8/06
to
"Dann Corbit" <dco...@connx.com> writes:
> "jaysome" <jay...@spamcop.net> wrote in message
> news:58ggd29fb960dal5t...@4ax.com...
[...]

>> There are 477 usages of "goto" in this source. That gives me a queasy
>> feeling.
>
> I'm in the Knuth camp:
> http://portal.acm.org/citation.cfm?id=356640&dl=&coll=GUIDE&CFID=15151515&CFTOKEN=6184618
[...]

The link is to Knuth's article "Structured Programming with go to
Statements", from the December 1974 issue of ACM Computing Surveys.

In my humble opinion, most instances of goto statements point to a
missing feature in the language. In C, the major missing features are
named break (which could be used to break out of a specified loop
rather than the nearest enclosing one) and a decent exception
mechanism.

All code can be written with conditional and unconditional gotos; all
the structured control constructs are, in a sense, syntactic sugar.
In my opinion, C would benefit from just a couple more such constructs
that could nearly eliminate the need for gotos. (Of course it would
be a very long time before any such change could become sufficiently
widely supported that we could actually use it.)

In the meantime, here in the real world, a goto is sometimes the
cleanest available solution to a problem. (I haven't studied the code
in question, so I can't comment on whether it turned out to be the
cleanest solution 477 times.)

lcw1964

unread,
Aug 8, 2006, 5:32:17 PM8/8/06
to

Thanks for sharing this, Pete, but already I have hit a snag.

My configuration of gcc/Cygwin (which includes EVERYTHING since in the
download I didn't know what to exclude) does not define any of those
important long double constants in math.h. And as for float.h, the only
such file I seem to have is the one with the MinGW package that I am
specifically not using here--moreover, it doesn't seem to have any
prototypes or defines I need to refer to. Yes, I know I should do some
research and define those constants myself, since they are no doubt
platform dependent, but my point is that you have clearly composed
these routines in an implementation that may not generalize to other
situations without adjustments being made. This speaks to the very
issue of portability and standardization that is so important to this
group!

Thanks for sharing the routines though. I think I am figuring out that
if I want to compute these elementary math functions to the high degree
of precision I crave, I am going to have to go outside the gcc "box" to
get them, or try my hand at writing them myself!

boy, I have a lot to learn. I appreciate everyone's indulgence.

Les

Keith Thompson

unread,
Aug 8, 2006, 5:48:30 PM8/8/06
to
"lcw1964" <leslie...@alumni.uwo.ca> writes:
[...]

> Actually I spoke too soon!
>
> The following variant of M. Navia's example generates the error too:
>
> #include <stdio.h>
> #include <math.h>
> int main(void)
> { long double x;
> x = 1.0L;
> long double n = expl(x);
> printf("%.20Lg\n",n);
> return 0;
> }

See my other followups in this thread.

lcw1964

unread,
Aug 8, 2006, 6:01:47 PM8/8/06
to

Keith Thompson wrote:

>
> See my other followups in this thread.
>
> --


Thanks, Mr. Thompson--it looks like while you were replying I was
figuring it out on my own concomitantly. Thanks for your consideration.

Les

Keith Thompson

unread,
Aug 8, 2006, 6:09:58 PM8/8/06
to
"lcw1964" <leslie...@alumni.uwo.ca> writes:
[snip]

> My configuration of gcc/Cygwin (which includes EVERYTHING since in the
> download I didn't know what to exclude) does not define any of those
> important long double constants in math.h. And as for float.h, the only
> such file I seem to have is the one with the MinGW package that I am
> specifically not using here--moreover, it doesn't seem to have any
> prototypes or defines I need to refer to.

The constants LDBL_MAX and so forth are defined in <float.h>, not
<math.h>

Don't waste your time search for a file called "float.h". Just write
code that uses it, and see if it works. For example, this works for
me under Cygwin:

#include <float.h>
#include <stdio.h>
int main(void)
{
long double max = LDBL_MAX;
printf("max = %Lg\n", max);
return 0;
}

The manner in which the compiler finds and processes whatever file or
other entity corresponds to the file.h header is system-specific, and
for the most part you just shouldn't worry about it.

[...]

> Thanks for sharing the routines though. I think I am figuring out that
> if I want to compute these elementary math functions to the high degree
> of precision I crave, I am going to have to go outside the gcc "box" to
> get them, or try my hand at writing them myself!

Out of curiousity, why do you want such high precision? Are you sure
that double (as opposed to long double) won't meet your needs?

pete

unread,
Aug 8, 2006, 7:06:21 PM8/8/06
to

The code that I posted, is completely portable C code,
for both hosted and freestanding implementations of C.

--
pete

lcw1964

unread,
Aug 8, 2006, 8:01:10 PM8/8/06
to
pete wrote:

> The code that I posted, is completely portable C code,
> for both hosted and freestanding implementations of C.
>

I am duly humbled. It compiles to an object file just beautifully.

Now, for my next trick, the newbie must learn the command line
parameters to create an executable from more than one object file!

Yes, Google is a great thing. And so are the FAQs, so I think I don't
need any more hand holding. I will take it from here.

As for my answer to Mr. Thompson's question of "why?", I am an
irritating dilettante who can only offer my version of Sir Edmund
Hilary's justification--"because" :)

Les

Keith Thompson

unread,
Aug 8, 2006, 8:21:33 PM8/8/06
to
"lcw1964" <leslie...@alumni.uwo.ca> writes:
[...]

> As for my answer to Mr. Thompson's question of "why?", I am an
> irritating dilettante who can only offer my version of Sir Edmund
> Hilary's justification--"because" :)

Good enough!

lcw1964

unread,
Aug 8, 2006, 9:23:44 PM8/8/06
to
lcw1964 wrote:
> pete wrote:
>
> > The code that I posted, is completely portable C code,
> > for both hosted and freestanding implementations of C.
> >
>
> I am duly humbled. It compiles to an object file just beautifully.
>
> Now, for my next trick, the newbie must learn the command line
> parameters to create an executable from more than one object file!
>

The challenge of the multifile project is too daunting to contemplate
at this moment, but I did cut and past Pete's code and prototypes to my
code and put everything in a single file for now and, yes indeed, it
improved my desired results greatly.

The exp() routine does start to lose digits as the argument gets higher
and the output has very large magnitude. I don't know if this due to
propagated rounding error in Pete's code, or if this is just the nature
of the beast when dealing with the long double type on my platform. I
understand that there are computational strategies that one can use to
improve the results of exponential functions as the absolute value of
the argument increases, and I should research this further.

Thank you so much for sharing this and supporting my meandering.

Les

p.s. I know I have been advised not to worry, and I won't, but the
curiosity is killing me--if their is no float.h header file, where the
heck is all that good information, and why doesn't the compiler rebel
when I include an *.h file that really doesn't seem to exist? There is
some zen wisdom in all of this I am sure....

Keith Thompson

unread,
Aug 8, 2006, 10:02:35 PM8/8/06
to
"lcw1964" <leslie...@alumni.uwo.ca> writes:
[...]

> p.s. I know I have been advised not to worry, and I won't, but the
> curiosity is killing me--if their is no float.h header file, where the
> heck is all that good information, and why doesn't the compiler rebel
> when I include an *.h file that really doesn't seem to exist? There is
> some zen wisdom in all of this I am sure....

<OT>
You can ask gcc to tell you where it searchs for headers. Use the
"-v" option. Don't assume that the float.h that it uses is under
/usr/include.
</OT>

More generally, system headers aren't necessarily implemented as
files; they can be implemented magically in the compiler itself, or by
some sort of precompiled thingie that isn't a C source file. <OT>As
far as I know, gcc doesn't do this.</OT>

Chris Torek

unread,
Aug 8, 2006, 11:36:42 PM8/8/06
to
In article <lnd5baa...@nuthaus.mib.org>

Keith Thompson <ks...@mib.org> wrote:
>More generally, system headers aren't necessarily implemented as
>files; they can be implemented magically in the compiler itself, or by
>some sort of precompiled thingie that isn't a C source file. <OT>As
>far as I know, gcc doesn't do this.</OT>

Regarding the OT bit: no, but it does something just as sneaky.
The compiler pre-defines a bunch of underscore-prefixed names that
can then be used in the actual headers (which are often squirreled
away all over the file system) to decide how the compiler was
invoked. This can in turn change the way various types work,
including wchar_t. (Note that "wchar_t" has to match the compiler's
type for L"string"s, so this is actually quite a reasonable thing
to do in the first place.)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.

ena8...@yahoo.com

unread,
Aug 9, 2006, 12:00:30 AM8/9/06
to

Keith Thompson wrote:
>
> In my humble opinion, most instances of goto statements point to a
> missing feature in the language. In C, the major missing features are
> named break (which could be used to break out of a specified loop
> rather than the nearest enclosing one) and a decent exception
> mechanism.

I don't agree with the basic premise, but for the
sake of discussion let's say I do. Do you really
think most gotos would be eliminated by C having
the features you named? In my experience most gotos
arise in one of three circumstances: bad coding,
branch to end of function to preserve single return
point, and machine generated C code (eg, YACC/LEX).
Breaking out of multiple loops seems like a distant
fourth (and usually remediable by putting the multiple
loops in their own function and using return); and
exception handling, it's hard to see how that's even
on the radar. It may be that C would benefit from
these features (personally I don't think it would,
but that's a separate issue), but even if it had
them it doesn't seem like goto usage would be affected
much.

My question above wasn't meant to be rhetorical;
I'm interested to hear your reactions.

Keith Thompson

unread,
Aug 9, 2006, 1:16:53 AM8/9/06
to

Bad coding obviously won't be affected. Yacc and Lex raise another
issue, which I'll come back to.

Branching to the end of a function (for example because you need to
execute some cleanup code rather than doing an immediate return) is
something that's usually done in, ahem, *exceptional* circumstances.
I'm not sure that C++-style exceptions would be a good fit for C. As
I recall, any C++ object can be thrown as an exception. Ada's
exception mechanism might be worth considering. In the 1983 version
of the language, it's simpler than C++'s mechanism; an exception is
just an exception, and a handler can handle either named exception or
all exceptions. Of course, any such mechanism would have to be very
lightweight.

The idea is to work with named entities that relate to the problem
domain rather than jumping to a named point in the code.

Getting back to Yacc and Lex, I haven't taken much of a look at the
code they generate. But a finite state machine is one of the few
places where gotos make sense. Ok, that was too strong; it's a case
where they make more sense than in most places.

Most control constructs correspond to something in the problem domain:
if/then/else makes a decision, a loop iterates over some set of
thingies, a function performs some part of the problem, etc. But a
goto just operates on the control flow of your program.

The one time when a goto statement matches something in the problem
domain is in a finite state machine, where a goto represents a
transition to a specified state (and the state is represented by a
chunk of code).

On the other hand, a finite state machine can also be implemented as a
case statement in a loop, with the state being represented by the
value of a variable.

Anyway, it's not terribly likely that any such changes are going to be
made.

ena8...@yahoo.com

unread,
Aug 9, 2006, 2:21:07 AM8/9/06
to
> Branching to the end of a function (for example because you need to
> execute some cleanup code rather than doing an immediate return) is
> something that's usually done in, ahem, *exceptional* circumstances.
> I'm not sure that C++-style exceptions would be a good fit for C. As
> I recall, any C++ object can be thrown as an exception. Ada's
> exception mechanism might be worth considering. In the 1983 version
> of the language, it's simpler than C++'s mechanism; an exception is
> just an exception, and a handler can handle either named exception or
> all exceptions. Of course, any such mechanism would have to be very
> lightweight.
>
> The idea is to work with named entities that relate to the problem
> domain rather than jumping to a named point in the code.

The pattern I was talking about looks something like
the following:

int typfun()
{
int rc;
...
x = get_resource_one();
if(x==NULL){ rc = -1; goto BAIL1; }

y = get_resource_two();
if(y==NULL){ rc = -2; goto BAIL2; }

z = get_resource_three();
if(z=NULL){ rc = -3; goto BAIL3; }

rc = 0;
release_resource(z);

BAIL3:
release_resource(y);

BAIL2:
release_resource(x);

BAIL3:
return rc;
}

Obviously there are variations, and I've written
the if()'s on one line to save space, but I
think you get the idea.

A pattern like this doesn't map very well onto
try/catch blocks, or other exception handling
mechanisms. I've used languages with exception
handling built in going back to the 1970's and
I think I'm pretty familiar with the landscape;
for expressing this pattern of control structure
(and this pattern is one of the common ones for
goto), just using goto allows a simpler and more
more clear function structure than try/catch
blocks. Or would you say otherwise?

pete

unread,
Aug 9, 2006, 2:21:16 AM8/9/06
to
lcw1964 wrote:
>
> lcw1964 wrote:
> > pete wrote:
> >
> > > The code that I posted, is completely portable C code,
> > > for both hosted and freestanding implementations of C.
> > >
> >
> > I am duly humbled. It compiles to an object file just beautifully.
> >
> > Now, for my next trick, the newbie must learn the command line
> > parameters to create an executable from more than one object file!
> >
>
> The challenge of the multifile project is too daunting to contemplate
> at this moment,
> but I did cut and past Pete's code and prototypes to my
> code and put everything in a single file for now and, yes indeed, it
> improved my desired results greatly.
>
> The exp() routine does start to lose digits as
> the argument gets higher
> and the output has very large magnitude. I don't know if this due to
> propagated rounding error in Pete's code,
> or if this is just the nature
> of the beast when dealing with the long double type on my platform. I
> understand that there are computational strategies that one can use to
> improve the results of exponential functions as the absolute value of
> the argument increases, and I should research this further.
>
> Thank you so much for sharing this and supporting my meandering.

http://groups.google.com/group/comp.lang.c/msg/e7cff29955d4971b

"We used to do successive multiplication, until we discovered
that accuracy degrades quickly with that approach.
The only really safe way to evaluate pow(x, y) accurately
is to compute exp(y * ln(x)) to extra internal precision.
(Took us a lot of rewrites, and a lot of careful testing,
to find that out.)" -- P.J. Plauger, Dinkumware, Ltd.

--
pete

jaysome

unread,
Aug 9, 2006, 3:02:13 AM8/9/06
to

This pattern maps very well onto try/catch blocks. First consider a
re-write of your example code (z=NULL corrected).

int typfun(void)
{
int rc;
...
x=y=z=NULL;
x = get_resource_one();
if(x==NULL){ rc = -1; goto CLEANUP; }
y = get_resource_two();
if(y==NULL){ rc = -2; goto CLEANUP; }
z = get_resource_three();
if(z==NULL){ rc = -3; goto CLEANUP; }

rc = 0;

CLEANUP:
release_resource(x);
release_resource(y);
release_resource(z);

return rc;
}

Now consider how it might be written in a language that provides
try/catch, and assumes release_resource() handles NULL, like it
should, like free() and delete and delete [] do:

int typfun()
{
int rc = 0;
...
x=y=z=NULL;
try
{
x = get_resource_one();
if(x==NULL){ rc = -1; throw rc; }
y = get_resource_two();
if(y==NULL){ rc = -2; throw rc; }
z = get_resource_three();
if(z==NULL){ rc = -3; throw rc; }
}
catch(int i)
{
rc = i;
}

release_resource(x);
release_resource(y);
release_resource(z);

return rc;
}

There's not much difference.

--
jay

Keith Thompson

unread,
Aug 9, 2006, 3:19:00 AM8/9/06
to
ena8...@yahoo.com writes:
[...]

> The pattern I was talking about looks something like
> the following:
>
> int typfun()
> {
> int rc;
> ...
> x = get_resource_one();
> if(x==NULL){ rc = -1; goto BAIL1; }
>
> y = get_resource_two();
> if(y==NULL){ rc = -2; goto BAIL2; }
>
> z = get_resource_three();
> if(z=NULL){ rc = -3; goto BAIL3; }
>
> rc = 0;
> release_resource(z);
>
> BAIL3:
> release_resource(y);
>
> BAIL2:
> release_resource(x);
>
> BAIL3:
> return rc;
> }
>
> Obviously there are variations, and I've written
> the if()'s on one line to save space, but I
> think you get the idea.

Sure. (The last label should be BAIL1, not BAIL3).

Just off the top of my head ...

With exception handlers, that would probably be written as three
nested blocks rather than straight-line code with gotos. As long as
you're creating nested blocks, I suppose you might as well just use
if-then-elses.

The code could be a bit simpler if you could assume that
release_resource() does nothing with a null pointer, as free() does.

Something that just occurred to me is that exceptions (in Ada or C++)
propagate across function calls. If we're (hypothetically) doing this
just to handle control flow within functions, that's not necessary.
Perhaps one answer is, rather than exception handling, to allow a
named break to exit from any scope, not just a loop or switch
statement.

So maybe something like this:

int typfun() /* This is not C. */
{
int rc;
...
USE_RESOURCE_ONE:
{
x = get_resource_one();
if(x==NULL){ rc = -1; break USE_RESOURCE_ONE };

USE_RESOURCE_TWO:
{
y = get_resource_two();
if(y==NULL){ rc = -2; break USE_RESOURCE_TWO; }

USE_RESOURCE_THREE:
{
z = get_resource_three();
if(z=NULL){ rc = -3; break USE_RESOURCE_THREE; }

rc = 0;
release_resource(z);
}

release_resource(y);
}

release_resource(x);
}

return rc;
}

Or, if release_resource() works correctly with a null pointer argument:

int typfun() /* This is not C. */
{
int rc;
...
USE_RESOURCES:
{
x = get_resource_one();
if(x==NULL){ rc = -1; break USE_RESOURCES; }

y = get_resource_two();
if(y==NULL){ rc = -2; break USE_RESOURCES; }

z = get_resource_three();
if(z=NULL){ rc = -3; break USE_RESOURCES; }

rc = 0;
} /* end of USE_RESOURCES block */

release_resource(z);
release_resource(y);
release_resource(x);

return rc;

Richard Bos

unread,
Aug 9, 2006, 4:16:48 AM8/9/06
to
ena8...@yahoo.com wrote:

It works better if you manage to write release_resource() to do nothing
on a null pointer (like malloc(), and unfortunately unlike fclose()).
You can then write this, which IMO looks cleaner:

int typfun()
{
int rc;
...
x = get_resource_one();

if(x==NULL){ rc = -1; goto BAIL; }

y = get_resource_two();
if(y==NULL){ rc = -2; goto BAIL; }

z = get_resource_three();
if(z==NULL){ rc = -3; goto BAIL; }

rc = 0;

BAIL:


release_resource(z);
release_resource(y);
release_resource(x);
return rc;
}

That is probably more amenable to being converted to a try/catch
mechanism, too - though I still wouldn't choose that conversion myself.

Richard

ena8...@yahoo.com

unread,
Aug 9, 2006, 4:19:23 AM8/9/06
to

Yes thank you for the correction.

Two comments. First, not all resource allocation/release can be
rewritten in the style you suggest using release(NULL). [*]
Second, why would someone use throw when what's it's doing
basically just a goto in disguise? If the release(NULL) technique
works, it seems better to dispense with try/catch altogether:

int typfun()
{
int rc = 0;
...
x=y=z=NULL;

do {
x = get_resource_one();
if(x==NULL){ rc = -1; break; }
y = get_resource_two();
if(y==NULL){ rc = -2; break; }
z = get_resource_three();
if(z==NULL){ rc = -3; break; }
} while(0);

release_resource(x);
release_resource(y);
release_resource(z);

return rc;
}

[*] For performance reasons, among others.

ena8...@yahoo.com

unread,
Aug 9, 2006, 4:25:43 AM8/9/06
to

Yes, thank you for the correction.

The goto version is shorter, has the same number of labels,
and doesn't exhibit the crawling indentation property.
This version doesn't seem like an improvement to me.

> Or, if release_resource() works correctly with a null pointer argument:
>
> int typfun() /* This is not C. */
> {
> int rc;
> ...
> USE_RESOURCES:
> {
> x = get_resource_one();
> if(x==NULL){ rc = -1; break USE_RESOURCES; }
>
> y = get_resource_two();
> if(y==NULL){ rc = -2; break USE_RESOURCES; }
>
> z = get_resource_three();
> if(z=NULL){ rc = -3; break USE_RESOURCES; }
>
> rc = 0;
> } /* end of USE_RESOURCES block */
>
> release_resource(z);
> release_resource(y);
> release_resource(x);
>
> return rc;
> }

Since there is only one level of nesting, this
structure can be achieved using a do/while(0)
block:

int typfun() /* C, not counting some missing declarations. */
{
int rc;
...
x = y = z = NULL;
do {
x = get_resource_one();
if(x==NULL){ rc = -1; break; }

y = get_resource_two();


if(y==NULL){ rc = -2; break; }

z = get_resource_three();
if(z==NULL){ rc = -3; break; }

rc = 0;
} while(0);

release_resource(z);
release_resource(y);
release_resource(x);

return rc;
}

So under the assumption that release(NULL) works,
the gotos in the original I would put under the
"bad coding" category more than needing a new
language control structure.

Maybe there are better motivating examples;
I just don't know what they are.

ena8...@yahoo.com

unread,
Aug 9, 2006, 4:36:49 AM8/9/06
to
x = y = z = NULL;
> x = get_resource_one();
> if(x==NULL){ rc = -1; goto BAIL; }
>
> y = get_resource_two();
> if(y==NULL){ rc = -2; goto BAIL; }
>
> z = get_resource_three();
> if(z==NULL){ rc = -3; goto BAIL; }
>
> rc = 0;
>
> BAIL:
> release_resource(z);
> release_resource(y);
> release_resource(x);
> return rc;
> }

Yes, I prefer this approach myself, when workable.
Sometimes it isn't, which is why I wrote it the
other way in the first place. (Sadly, performance
concerns are sometimes of paramount interest,
and measurements showed they couldn't be
neglected in some of these situations.)

lcw1964

unread,
Aug 9, 2006, 9:23:33 AM8/9/06
to

pete wrote:
>
> http://groups.google.com/group/comp.lang.c/msg/e7cff29955d4971b
>
> "We used to do successive multiplication, until we discovered
> that accuracy degrades quickly with that approach.
> The only really safe way to evaluate pow(x, y) accurately
> is to compute exp(y * ln(x)) to extra internal precision.
> (Took us a lot of rewrites, and a lot of careful testing,
> to find that out.)" -- P.J. Plauger, Dinkumware, Ltd.
>

Thanks Pete. That makes sense.

On my machine, ln(LDBL_MAX) is a little over 11653. fs_expl(11653)
returns a result that matches the Maple output to 16 digits within 1
ulp, and with rounding matches perfectly to 15 digits. Considering the
vicissitudes of computing exp() as the argument gets large, I don't
think this is anything to sneeze at, since my experience has been on my
machine that a really good long double result usually means 18 digits
tops, occasionally 19 if the rounding error works in my favour.

Thanks for sharing your work.

Les

Chris Torek

unread,
Aug 9, 2006, 3:32:17 PM8/9/06
to
(this needs a new "subject" line but I could not think of something
suitable yet short)

In article <1155104467.7...@b28g2000cwb.googlegroups.com>,


<ena8...@yahoo.com> wrote:
>The pattern I was talking about looks something like
>the following:
>
> int typfun()
> {
> int rc;
> ...
> x = get_resource_one();
> if(x==NULL){ rc = -1; goto BAIL1; }
>
> y = get_resource_two();
> if(y==NULL){ rc = -2; goto BAIL2; }
>
> z = get_resource_three();

> if(z==NULL){ rc = -3; goto BAIL3; }


>
> rc = 0;
> release_resource(z);
>
> BAIL3:
> release_resource(y);
>
> BAIL2:
> release_resource(x);
>
> BAIL3:
> return rc;
> }
>
>Obviously there are variations, and I've written
>the if()'s on one line to save space, but I
>think you get the idea.
>
>A pattern like this doesn't map very well onto
>try/catch blocks, or other exception handling

>mechanisms. ...

Maybe not; but over time I have been convinced to (usually) rewrite
the above as (note that most of the "get resource" functions in this
particular system return an error code, so take an address for their
"successful result" if any):

int typfun()
{
int error = 0;
T x = NULL, y = NULL, z = NULL;
...
error = get_resource_one(&x);
if (error == 0)
error = get_resource_two(&y);
if (error == 0)
error = get_resource_three(&y);
if (error == 0)
... do the work ...
release_resource(z);
release_resource(y);
release_resource(x);
return error;
}

This is "less efficient" in the error case (because "if (error==0)"
test is repeated, assuming the compiler does not rearrange it away)
but "equally efficient" in the non-error case (because all three
tests are required no matter what). Thus, if the error case is a
little slower ... well, this is often not a big deal. :-)

Flash Gordon

unread,
Aug 9, 2006, 3:05:11 PM8/9/06
to

Why use a for loop when it is just a while loop in disguise? Why use a
while loop when it is just a conditional goto and an unconditional goto
in disguise? Why use a do-while loop when it is just a conditional goto
in disguise? Why use a break when it is just a goto in disguise?

> If the release(NULL) technique
> works, it seems better to dispense with try/catch altogether:
>
> int typfun()
> {
> int rc = 0;
> ...
> x=y=z=NULL;
> do {
> x = get_resource_one();
> if(x==NULL){ rc = -1; break; }
> y = get_resource_two();
> if(y==NULL){ rc = -2; break; }
> z = get_resource_three();
> if(z==NULL){ rc = -3; break; }
> } while(0);
>
> release_resource(x);
> release_resource(y);
> release_resource(z);
>
> return rc;
> }

Or, if one had try/catch


int typfun()
{
int rc = 0;
...
x=y=z=NULL;
try {
x = get_resource_one();

if(x==NULL) throw -1;
y = get_resource_two();
if(y==NULL) throw -2;
z = get_resource_three();
if(z==NULL) throw -3;
}
catch( int i )
rc = i;

release_resource(x);
release_resource(y);
release_resource(z);

return rc;
}

I'm sure it is a few characters less typing ;-)

> [*] For performance reasons, among others.

Premature optimisation is the root of quite a lot of problems. Anyway,
as someone else suggested you can always nest the blocks.

try/catch which propagates outside the function can be even more useful.
Especially for library functions.

int mylibfunc(whatever)
{
/* do stuff */
if (condition)
/* This is a fundamental problem and it is not safe to continue
doing anything unless it is dealt with */
throw 1;
}

Unlike the return value if the caller ignores it then it propagates
until the program exits with an error code or it is caught. I've done a
lot of programming in a Pascal variant that had this and made a lot of
use of it and it makes handling exceptional conditions a lot easier.
Like most things it can also be abused ;-)
--
Flash Gordon
Still sigless on this computer.

av

unread,
Aug 10, 2006, 2:04:19 AM8/10/06
to
On 8 Aug 2006 18:23:44 -0700, lcw1964 wrote:
>lcw1964 wrote:
>> pete wrote:

>The exp() routine does start to lose digits as the argument gets higher
>and the output has very large magnitude. I don't know if this due to
>propagated rounding error in Pete's code, or if this is just the nature
>of the beast when dealing with the long double type on my platform.

i have the same problem. it seems it is common problem for the "pow"
functions. The only solution i find is a "steps function" for grow the
precision in the way at end the result should be exact in the request
digit precision. (but i think it is not 100% ok for all input in "my"
function pow())

jaysome

unread,
Aug 10, 2006, 2:48:48 AM8/10/06
to
On Wed, 09 Aug 2006 20:05:11 +0100, Flash Gordon

[snip]

>Or, if one had try/catch
>int typfun()
>{
> int rc = 0;
> ...
> x=y=z=NULL;
> try {
> x = get_resource_one();
> if(x==NULL) throw -1;
> y = get_resource_two();
> if(y==NULL) throw -2;
> z = get_resource_three();
> if(z==NULL) throw -3;
> }
> catch( int i )
> rc = i;
>
> release_resource(x);
> release_resource(y);
> release_resource(z);
>
> return rc;
>}
>
>I'm sure it is a few characters less typing ;-)

Admittedly better. I retained the assignment to rc to strengthen the
parallelism. And to further the improvements, this is what I would do:

if (!x)

instead of

if (x==NULL)

The C standard guarantees that the two expressions yield identical
results, and there's even an FAQ on this.

>
>> [*] For performance reasons, among others.
>
>Premature optimisation is the root of quite a lot of problems. Anyway,
>as someone else suggested you can always nest the blocks.

Indeed. Probably the biggest problem with premature optimization is a
waste of time. And that can figure significantly into missing a
schedule deadline.

On my current main project, we still compile with the debug option. So
far so good. Should the day come where there is a throughput problem,
the first step I'll perform is to make a simple change to scripts and
project settings that result in compilation without the debug option
and optimizations enabled. I've already tested this, and am confident
that the only change will be in increased throughput. In the meantime,
I have to deal with the possibility that someone else screws up and
I'll be the one troubleshooting the crash. Hence debug with no
optimizations--core dumps and crashes need debuggers.

--
jay

pete

unread,
Aug 10, 2006, 6:34:10 AM8/10/06
to
jaysome wrote:

> And to further the improvements, this is what I would do:
>
> if (!x)
>
> instead of
>
> if (x==NULL)
>
> The C standard guarantees that the two expressions yield identical
> results, and there's even an FAQ on this.

That doesn't explain why you think (!x) is better than (x==NULL).

(x==NULL) gives me enough context to know that x is a pointer.

(!x) only tells me that x is a scalar type.

--
pete

ena8...@yahoo.com

unread,
Aug 10, 2006, 3:08:20 PM8/10/06
to

Yes, where workable a form like the above is preferable.
My intention was to talk about cases where it isn't
workable, but I agree here wholeheartedly.

ena8...@yahoo.com

unread,
Aug 10, 2006, 3:13:05 PM8/10/06
to

Those are reasonable questions, but most of them have obvious
answers.

A reason for preferring goto to throw (when possible) is that
goto is guaranteed to be local; throw isn't. I don't see
any reason to use throw, except to avoid the bugaboo of using
goto. And that doesn't strike me as much of a reason.

Same comments as above apply here. More mental
effort is required for try/throw/catch than
for do/break/while(0);

> > [*] For performance reasons, among others.
>
> Premature optimisation is the root of quite a lot of problems.

The optimization was not premature in the cases
I was referring to.

> Anyway,
> as someone else suggested you can always nest the blocks.

Yes, and nesting the blocks produces a less satisfactory
result, as my response to that suggestion explained.

Flash Gordon

unread,
Aug 10, 2006, 4:38:52 PM8/10/06
to
ena8...@yahoo.com wrote:
> Flash Gordon wrote:
>> ena8...@yahoo.com wrote:
>>> jaysome wrote:

<snip alternative versions of code and discussions of the merits>

>>> Two comments. First, not all resource allocation/release can be
>>> rewritten in the style you suggest using release(NULL). [*]
>>> Second, why would someone use throw when what's it's doing
>>> basically just a goto in disguise?
>
> Those are reasonable questions, but most of them have obvious
> answers.
>
> A reason for preferring goto to throw (when possible) is that
> goto is guaranteed to be local; throw isn't. I don't see
> any reason to use throw, except to avoid the bugaboo of using
> goto. And that doesn't strike me as much of a reason.

To me throw would be the more natural. The problem is you have hit an
exceptional situation that you have to deal with not that you need to
clean up. I can accept, however, that others may not see it that way. I
also don't see the locality as a problem because with any sensible (to
me) sized code block you can see at a glance that it is enclosed in a
local try block.

I'm not saying you are wrong, this is a matter of personal preference in
my opinion, not who is right or wrong.

For me it does not require more mental effort. If anything it is less
because after seeing the do I don't have to check the end to know it is
just there to allow breaking out.

Of course, I spent years using a try/catch type system so I'm so
familiar with it that it requires no more thinking than understanding
for (;;) {
/* whatever */
}

>>> [*] For performance reasons, among others.
>> Premature optimisation is the root of quite a lot of problems.
>
> The optimization was not premature in the cases
> I was referring to.

That was not clear in your previous post. You've since said that you had
found you had a performance problem, measured, and found this a
significant saving. In such conditions it is reasonable to make the
optimisation.

>> Anyway,
>> as someone else suggested you can always nest the blocks.
>
> Yes, and nesting the blocks produces a less satisfactory
> result, as my response to that suggestion explained.

Again, very much a matter of personal preference.

lcw1964

unread,
Aug 12, 2006, 7:48:53 AM8/12/06
to
Dann Corbit wrote:

> I think Moshier's code is beautiful. It was originally written in 1984, and
> later reworked so that you could compile it with ANSI style prototypes.
>
> At the top of every file is a detailed explanation of what the code does,
> which equations are used to solve the problem, and what the measured errors
> were in calibration of the function's useful range.

I am a very amateur hobbyist program so I am not qualified to comment
on either the aesthetics of the code or the virtues (or not) of goto
statements, but I know enough to be impressed by the math of it.

Mr. Corbit was quite correct to comment earlier in the thread that the
qlib package was easy to make, and, with a little research on my part,
is not so inscrutable to use. I have been particularly impressed with
Moshier's code for the high precision version of the gamma function.
This function is not something that is easily computed to very high
precision--the asymptotic Stirling series uses Bessel numbers which in
the higher terms get huge--but Moshier's code is painstakingly
thorough, with the requisite constants to dozes of digits rendered in
the code.

With a little practice I have been able to write a little
implementation that computes this function to over 100 digits. That
impresses me. As a user, I think I could forgive the evil gotos if
they get the job done :)

Les

ena8...@yahoo.com

unread,
Aug 12, 2006, 5:50:30 PM8/12/06
to

Reasonable comments.

Just a few points in reply.

It's true for short functions that there isn't much difference
between the try/catch form and the goto form (or do/while(0)
form). Unfortunately the real cases where these come up (based on
my experience) tend to have longer than average function bodies,
and it isn't always easy to scan the whole function.

Two, whatever one's personal reaction, adding exception handling
to C would produce a bigger language than C is now. A bigger
language means more mental effort to understand programs written
in that language.

Three, exceptions are as easy to misuse as goto is, and in my
experience misused more often.

Adding these up, getting rid of gotos still doesn't make a good
argument for introducing exception handling into C. It might
(or might not) be good to introduce it for other reasons, but
getting rid of gotos isn't one of them.

0 new messages