Robert Millan <[EMAIL PROTECTED]> writes:

> On Thu, Jul 24, 2003 at 12:14:57AM +0100, Roger Leigh wrote:
>> Robert Millan <[EMAIL PROTECTED]> writes:
>> 
>> > Some days ago I posted this small patch for building wanna-build on
>> > GNU, and asked for revision, but didn't get any response.
>> >
>> > It attempts to replace the linux-specific sysinfo() with getloadavg(),
>> > but there's a type conversion issue and i'd like to make sure i did it
>> > correctly, please could anyone verify this:
>> >
>> > --- wanna-build.old/buildd-mail-wrapper.c  1999-07-21 14:53:22.000000000 
>> > +0200
>> > +++ wanna-build/buildd-mail-wrapper.c      2003-07-15 21:06:59.000000000 
>> > +0200
>> [...]
>> 
>> This seems rather complex!  Why not just do something like:
>>                 waittime = (long) (loadavg[0] / 16384) * 6 + 20;
>> 
>> If you don't need SI_LOAD_SHIFT (Linux-specific??), it can probably be
>> even simpler.
>
> Can I cast a double to long like that? What kind of truncating happens if
> loadavg[0] is bigger than LONG_MAX? Does a division with 2^14 garantee it
> will fit nicely?

I've written a simple test program.  It seems any cast from
double->long will set LONG_MIN/LONG_MAX if it would result in an
double->overflow.  Thus,

+               if (loadavg[0] > LONG_MAX)
+                       load = LONG_MAX;
+               else
+                       load = (long) loadavg[0];

can be replaced with

load = (long) loadavg[0].

This was tested on Debian unstable (Linux 2.4.21 with glibc 2.3.1).
For some reason, I only ever got LONG_MIN to be returned, even when
the overflow was positive!  I'm not sure if this is a problem with my
code, or a glibc bug, or whatever.

Here's the test program.  You'll need to link with -lreadline.

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <errno.h>

#include <readline/readline.h>

int main(void)
{
  char *input = NULL;
  double big;
  long fixed;

  while(1)
    {
      if (input)
        {
          free(input);
          input = NULL;
        }
      input = readline("Enter a number: ");

      big = strtod(input, NULL);

      if (errno == ERANGE)
        {
          fprintf(stderr, "Number is out of range: ");
          if (big == 0)
            fprintf(stderr, "FP underflow\n");
          else
            fprintf(stderr, "FP overflow\n");
          continue;
        }

      printf("double: %g\n", big);

      fixed = (long) big;

      if (fixed == LONG_MIN || fixed == LONG_MAX)
        {
          fprintf(stderr, "Number is out of range for type \"long\": ");
          if (fixed == LONG_MIN)
            fprintf(stderr, "LONG_MIN");
          else
            fprintf(stderr, "LONG_MAX");
          fprintf(stderr, ": %ld\n", fixed);
          continue;
        }

      printf("long: %ld\n", fixed);
    }

  return 0;
}


-- 
Roger Leigh

                Printing on GNU/Linux?  http://gimp-print.sourceforge.net/
                GPG Public Key: 0x25BFB848 available on public keyservers


Reply via email to