[comp.lang.c] Help with function

veenu@cbnewsj.ATT.COM (veenu.r.rashid) (01/06/90)

	On the compiler I'm using, abs() and strtol() seem to generate incorrect
or at least inaccurate results.  I'm using the following code:

---
main(int argc, char *argv[])
{
	double temp;

	temp = strtod(argv[1]);		/* get the argument as a double	*/
	printf("Absolute value of %g is %g\n", temp, abs(temp));
}

---

While, to myself at least, this seems like simple code, which
should be rather straightforward, the results are far from
correct -- or, at least they're correct only part of the time.

compile with:
	cc t1.c -ot1

I get the following results, based on random input:

>t1 98.0
98			/* fine		*/

>t1 685944.32
685944.320327		/* some roundoff error	*/

>t1 75433.983
-0.12325946e+11		/* ???		*/

The program produces truly screwy output at the least
provocation.  The strange thing about it that the
last input lies *in-between* the other two values, those
which produce correct output.

So, are there any theories which might explain why this
happens.  Better yet, does anyone have PD code to replace
abs() and/or strtod() ??  (Yes, I *know* abs(x) defined
as (x<0 ? x : -(x)) is not the culprit, since I tried it with
 (how can something so *simple* screw up??!?)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
my own implementation, and other than the roundoff (sigh)
it seems to work fine.)

BTW, I'm using UNIX System V version 4.0 on an AT&T machine.


Any code, suggestions, comments greatly appreciated.


Navruze Rashid
ruze@mtfmi.att.com	--or--	att!mtfmi!ruze
Bell Laboratories	MT 3F-129

Disclaimer: There is no proprietary material in here,
if I mention UNIX is registered with AT&T.

pat@rwing.UUCP (Pat Myrto) (01/08/90)

In article <3198@cbnewsj.ATT.COM>, veenu@cbnewsj.ATT.COM (veenu.r.rashid) writes:
> 	On the compiler I'm using, abs() and strtol() seem to generate incorrect
> or at least inaccurate results.  I'm using the following code:
> 
> ---
> main(int argc, char *argv[])
> {
> 	double temp;
> 
> 	temp = strtod(argv[1]);		/* get the argument as a double	*/
> 	printf("Absolute value of %g is %g\n", temp, abs(temp));
> }
> 
> ---
> 
> The program produces truly screwy output at the least
> provocation.  The strange thing about it that the

Your problem is incorrect usage of strtod().  First, it takes a second
argument, a pointer to a string pointer, which will contain the point
where strtod stops its scan.  Present code will write this to some
undefined place.  But the reason you got screwey output, is because the
compiler thinks strtod() returns an INTEGER (int), because nobody told
it different.

Change the line "double temp;" to "double temp, strtod();" and the
results will be better.  The output from strtod() was treated as an
int, and then cast to double by the compiler.  Shoving a double
through an int almost always mangles it.  But also add in the
variable definitions a "char *stopstr;" or somthing like that, and
call strtod() like

    temp = strtod(argv[1], &stopstr);

Because not doing so will corrupt something else in your data space,
causing a hard-to-find bug in a real program.

I verified the above by copying the code, compiling it, and running
it.  Adding the declaration that strtod() returns a double fixed it.

-- 
pat@rwing                                       (Pat Myrto),  Seattle, WA
                     ...!uunet!pilchuck!rwing!pat
             ...!uw-beaver!sumax!polari!/
WISDOM:    "Travelling unarmed is like boating without a life jacket" 

bts@sas.UUCP (Brian T. Schellenberger) (01/09/90)

Aside from the fact, ast pointed out already, that strtod() is
returning a decimal rather than a double, abs() returns, and expects,
a decimal as well.  Use fabs().*

*Actually, abs() on many systems is "generic," but it isn't required to be.
strtod never is.
-- 
-- Brian, the Man from Babble-on.		...!mcnc!rti!sas!bts
-- (Brian Schellenberger)
"No one will ever write a song called 'Nitro Burning Funny Cars'"
                 -- THE DEAD MILKMEN, "Nitro Burning Funny Cars"

bright@Data-IO.COM (Walter Bright) (01/09/90)

In article <3198@cbnewsj.ATT.COM> veenu@cbnewsj.ATT.COM (veenu.r.rashid) writes:
<	On the compiler I'm using, abs() and strtol() seem to generate incorrect
<or at least inaccurate results.  I'm using the following code:
<main(int argc, char *argv[])
<{	double temp;
<	temp = strtod(argv[1]);		/* get the argument as a double	*/
<	printf("Absolute value of %g is %g\n", temp, abs(temp));
<}

Errors:
	You need the double abs which is called fabs().
	You need to #include:
		#include <stdio.h>	/* for printf	*/
		#include <math.h>	/* for fabs	*/
		#include <stdlib.h>	/* for strtod	*/

randolph@ektools.UUCP (Gary L. Randolph) (01/11/90)

In article <3198@cbnewsj.ATT.COM> veenu@cbnewsj.ATT.COM (veenu.r.rashid) writes:
>	On the compiler I'm using, abs() and strtol() seem to generate incorrect
>or at least inaccurate results.  I'm using the following code:
>main(int argc, char *argv[])
>{
>	double temp;
>
>	temp = strtod(argv[1]);		/* get the argument as a double	*/
>	printf("Absolute value of %g is %g\n", temp, abs(temp));
>}
>Any code, suggestions, comments greatly appreciated.

Well, I can't duplicate the problem.  I am using cfront 2.0 on a Sun and
all seems to work fine but I did have to make the following changes to
the code:

       I used fabs() rather than abs()
       I called strtod as follows:

               temp = strtod(argv[1], NULL)  /*ANSI definition*/ your
results was impossible.  If that's all you are missing, I would be
dissappointed that the compiler didn't generate an error.
This is the sort of thing that would cause the described flakey 
behavior.

:
-
)

Gary

randolph@ektools.UUCP (Gary L. Randolph) (01/11/90)

In article <3198@cbnewsj.ATT.COM> veenu@cbnewsj.ATT.COM (veenu.r.rashid) writes:
>main(int argc, char *argv[])
>	temp = strtod(argv[1]);		/* get the argument as a double	*/
		^^^^^^^^^^^^^
     TRY temp = strtod(argv[1],NULL);  /*ANSI definition takes 2 args*/

Gary

will@charyb.COM (Will Crowder) (01/13/90)

In article <2385@ektools.UUCP> randolph@ektools.UUCP (Gary L. Randolph) writes:
>In article <3198@cbnewsj.ATT.COM> veenu@cbnewsj.ATT.COM (veenu.r.rashid) writes:
>>
>> [description of strtod() problem I'm sure everyone's seen by now]
>
>Well, I can't duplicate the problem.  I am using cfront 2.0 on a Sun and
>all seems to work fine but I did have to make the following changes to
>the code:
>
>       I used fabs() rather than abs()
>       I called strtod as follows:
>
>               temp = strtod(argv[1], NULL)  /*ANSI definition*/ your
>results was impossible.  If that's all you are missing, I would be
>dissappointed that the compiler didn't generate an error.
>This is the sort of thing that would cause the described flakey 
>behavior.
>Gary

The compiler (a non-ANSI *NIX compiler) has no business generating an error 
since it knows nothing of the strtod() function.  An ANSI compiler would
generate an error in the presence of a conflicting prototype, but it's
all-important to remember that non-ANSI compilers don't have the slightest
idea what you're doing, so you'd better have some idea yourself.

Will

P.S. (Of course, lint would have trapped this error, but the compiler
      wouldn't have.)

f
o
d
d
e
r

karl@haddock.ima.isc.com (Karl Heuer) (01/20/90)

In article <3477@cbnewsj.ATT.COM> veenu@cbnewsj.ATT.COM (veenu.r.rashid,mt,) writes:
>As it turns out, the abs() macro definition tends to return int, (but not
>always!), while fabs() returns the correct floating point value.  Now, is
>this just a macro characteristic or is it the compiler I'm using.

|abs| is a standard library function that expects an |int| and returns an
|int|.  I don't know anything about the macro definition on your machine, and
neither should you, if you're interested in writing portable programs.
Passing it a non-|int| value is undefined behavior; all bets are off.

Karl W. Z. Heuer (karl@haddock.isc.com or ima!haddock!karl), The Walking Lint
________
I'm assuming you have a sane implementation.  If |abs| is defined as
	#define abs(x) ((x) < 0 ? -(x) : (x))
then you should file a bug report, since it will break code like |abs(*p++)|.