Why the zero case in fabs()?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Martin

    Why the zero case in fabs()?

    In Plauger's THE STANDARD C LIBRARY (1992) there is the source code for
    fabs.c (p140).

    /* fabs function */
    #include "xmath.h"
    double (fabs)(double x)
    {
    switch (_Dtest(&x))
    { /* test for special codes */
    case NAN:
    errno = EDOM;
    return (x);
    case INF:
    errno = ERANGE;
    return (_Inf._D);
    case 0:
    return (0.0);
    default: /* finite */
    return (x < 0.0 ? -x : x);
    }
    }

    This is not necessarily a question about fabs() in particular, but rather a
    question about the *technique* Plauger has employed, and if there is a
    subtlety involved.

    My question is: why is there a case for 0, which simply returns 0.0? Without
    it, the default case will trap it anyway, and return 0, which will be
    converted to double - the return type of the function.

    Also, I'm puzzled by the superfluous use of parentheses around the return
    expressions.

    Martin




  • Dan Pop

    #2
    Re: Why the zero case in fabs()?

    In <CD6Yb.28368$a% 6.9593@fe04.use netserver.com> "Martin" <martin.o_brien @[no-spam]which.net> writes:
    [color=blue]
    >In Plauger's THE STANDARD C LIBRARY (1992) there is the source code for
    >fabs.c (p140).
    >
    >/* fabs function */
    >#include "xmath.h"
    >double (fabs)(double x)
    >{
    > switch (_Dtest(&x))
    > { /* test for special codes */
    > case NAN:
    > errno = EDOM;
    > return (x);
    > case INF:
    > errno = ERANGE;
    > return (_Inf._D);
    > case 0:
    > return (0.0);
    > default: /* finite */
    > return (x < 0.0 ? -x : x);
    > }
    >}
    >
    >This is not necessarily a question about fabs() in particular, but rather a
    >question about the *technique* Plauger has employed, and if there is a
    >subtlety involved.
    >
    >My question is: why is there a case for 0, which simply returns 0.0? Without
    >it, the default case will trap it anyway, and return 0, which will be
    >converted to double - the return type of the function.[/color]

    No conversion to double is needed or would occur in that case: the
    function would return x which is already of type double.

    However, I don't know why Plauger handled 0.0 as a special case.
    [color=blue]
    >Also, I'm puzzled by the superfluous use of parentheses around the return
    >expressions.[/color]

    They were mandatory, back when Plauger started to use C. Old habits die
    hard...

    Dan
    --
    Dan Pop
    DESY Zeuthen, RZ group
    Email: Dan.Pop@ifh.de

    Comment

    • lawrence.jones@ugsplm.com

      #3
      Re: Why the zero case in fabs()?

      Martin <martin.o_brien @[no-spam]which.net> wrote:[color=blue]
      >
      > My question is: why is there a case for 0, which simply returns 0.0? Without
      > it, the default case will trap it anyway, and return 0, which will be
      > converted to double - the return type of the function.[/color]

      The subtlety you're missing is signed zeros. On implementations that
      have such things, -0.0 is not < 0.0, so the default case would return it
      as-is (i.e., -0.0) rather than returning the correct +0.0.
      [color=blue]
      > Also, I'm puzzled by the superfluous use of parentheses around the return
      > expressions.[/color]

      Style. Or lack thereof, if we're making value judgments. :-)

      -Larry Jones

      I don't think that question was very hypothetical at all. -- Calvin

      Comment

      • Martin Dickopp

        #4
        Re: Why the zero case in fabs()?

        "Martin" <martin.o_brien @[no-spam]which.net> writes:
        [color=blue]
        > In Plauger's THE STANDARD C LIBRARY (1992) there is the source code for
        > fabs.c (p140).
        >
        > /* fabs function */
        > #include "xmath.h"
        > double (fabs)(double x)
        > {
        > switch (_Dtest(&x))
        > { /* test for special codes */
        > case NAN:
        > errno = EDOM;
        > return (x);
        > case INF:
        > errno = ERANGE;
        > return (_Inf._D);
        > case 0:
        > return (0.0);
        > default: /* finite */
        > return (x < 0.0 ? -x : x);
        > }
        > }
        >
        > This is not necessarily a question about fabs() in particular, but
        > rather a question about the *technique* Plauger has employed, and if
        > there is a subtlety involved.
        >
        > My question is: why is there a case for 0, which simply returns 0.0?
        > Without it, the default case will trap it anyway, and return 0, which
        > will be converted to double - the return type of the function.[/color]

        I don't know what `_Dtest' does, but presumably it returns 0 if `x' is
        0.0. If it is already known that `x' is 0.0, there is no reason to
        compare it with 0.0 again, which would only (slightly) degrade the
        performance.
        [color=blue]
        > Also, I'm puzzled by the superfluous use of parentheses around the
        > return expressions.[/color]

        So am I.

        Martin

        Comment

        • Gordon Burditt

          #5
          Re: Why the zero case in fabs()?

          >This is not necessarily a question about fabs() in particular, but rather a[color=blue]
          >question about the *technique* Plauger has employed, and if there is a
          >subtlety involved.
          >
          >My question is: why is there a case for 0, which simply returns 0.0? Without
          >it, the default case will trap it anyway, and return 0, which will be
          >converted to double - the return type of the function.[/color]

          Is negative zero an issue here? Are there some implementations
          (possibly buggy by current floating point standards) where negative
          zero tests as less than 0? Perhaps it was desired that fabs() never
          return anything that tests less than zero, not even negative zero,
          even for implementations of what later became IEEE floating point
          that didn't quite handle all the corner cases involving negative
          zero according to the current floating point standard.

          Gordon L. Burditt

          Comment

          • Christian Bau

            #6
            Re: Why the zero case in fabs()?

            In article <CD6Yb.28368$a% 6.9593@fe04.use netserver.com>,
            "Martin" <martin.o_brien @[no-spam]which.net> wrote:
            [color=blue]
            > In Plauger's THE STANDARD C LIBRARY (1992) there is the source code for
            > fabs.c (p140).
            >
            > /* fabs function */
            > #include "xmath.h"
            > double (fabs)(double x)
            > {
            > switch (_Dtest(&x))
            > { /* test for special codes */
            > case NAN:
            > errno = EDOM;
            > return (x);
            > case INF:
            > errno = ERANGE;
            > return (_Inf._D);
            > case 0:
            > return (0.0);
            > default: /* finite */
            > return (x < 0.0 ? -x : x);
            > }
            > }
            >
            > This is not necessarily a question about fabs() in particular, but rather a
            > question about the *technique* Plauger has employed, and if there is a
            > subtlety involved.
            >
            > My question is: why is there a case for 0, which simply returns 0.0? Without
            > it, the default case will trap it anyway, and return 0, which will be
            > converted to double - the return type of the function.[/color]

            One possibility is that he wanted floating point numbers in IEEE 754
            format to be handled correctly: In that format, there are two different
            representations for +0.0 and -0.0; both produce values that compare
            equal to x, but you would want fabs (-0.0) to be +0.0.
            [color=blue]
            > Also, I'm puzzled by the superfluous use of parentheses around the return
            > expressions.
            >
            > Martin
            > http://martinobrien.co.uk/
            >
            >
            >[/color]

            Comment

            • P.J. Plauger

              #7
              Re: Why the zero case in fabs()?

              "Christian Bau" <christian.bau@ cbau.freeserve. co.uk> wrote in message
              news:christian. bau-BB7C6A.20133416 022004@slb-newsm1.svr.pol. co.uk...
              [color=blue]
              > In article <CD6Yb.28368$a% 6.9593@fe04.use netserver.com>,
              > "Martin" <martin.o_brien @[no-spam]which.net> wrote:
              >[color=green]
              > > In Plauger's THE STANDARD C LIBRARY (1992) there is the source code for
              > > fabs.c (p140).
              > >
              > > /* fabs function */
              > > #include "xmath.h"
              > > double (fabs)(double x)
              > > {
              > > switch (_Dtest(&x))
              > > { /* test for special codes */
              > > case NAN:
              > > errno = EDOM;
              > > return (x);
              > > case INF:
              > > errno = ERANGE;
              > > return (_Inf._D);
              > > case 0:
              > > return (0.0);
              > > default: /* finite */
              > > return (x < 0.0 ? -x : x);
              > > }
              > > }
              > >
              > > This is not necessarily a question about fabs() in particular, but[/color][/color]
              rather a[color=blue][color=green]
              > > question about the *technique* Plauger has employed, and if there is a
              > > subtlety involved.
              > >
              > > My question is: why is there a case for 0, which simply returns 0.0?[/color][/color]
              Without[color=blue][color=green]
              > > it, the default case will trap it anyway, and return 0, which will be
              > > converted to double - the return type of the function.[/color]
              >
              > One possibility is that he wanted floating point numbers in IEEE 754
              > format to be handled correctly: In that format, there are two different
              > representations for +0.0 and -0.0; both produce values that compare
              > equal to x, but you would want fabs (-0.0) to be +0.0.[/color]

              Correct.
              [color=blue][color=green]
              > > Also, I'm puzzled by the superfluous use of parentheses around the[/color][/color]
              return[color=blue][color=green]
              > > expressions.[/color][/color]

              It's a style I settled on many years ago. (FWIW and IIRC, there was a
              brief period when the parentheses were required by an early Ritchie
              compiler.) We made it part of the shop standard at Whitesmiths and
              I've stuck with it over the years.

              P.J. Plauger
              Dinkumware, Ltd.



              Comment

              • Martin

                #8
                Re: Why the zero case in fabs()?

                Christian Bau wrote:[color=blue][color=green]
                > > One possibility is that he wanted floating point numbers in IEEE 754
                > > format to be handled correctly: In that format, there are two different
                > > representations for +0.0 and -0.0; both produce values that compare
                > > equal to x, but you would want fabs (-0.0) to be +0.0.[/color][/color]

                "P.J. Plauger" commented:[color=blue]
                > Correct.[/color]

                I wrote:[color=blue][color=green][color=darkred]
                > > > Also, I'm puzzled by the superfluous use of parentheses around the
                > > > return expressions.[/color][/color][/color]

                "P.J. Plauger" replied[color=blue]
                > It's a style I settled on many years ago. (FWIW and IIRC, there was a
                > brief period when the parentheses were required by an early Ritchie
                > compiler.) We made it part of the shop standard at Whitesmiths and
                > I've stuck with it over the years.[/color]

                My thanks to P.J. Plauger, Christian, Gordon, Martin Dicksopp, Lawrence, and
                Dan for your reponses.

                THE STANDARD C LIBRARY is packed with much information I know, and is a
                large enough book, but perhaps that subtlety with the IEEE 754 should have
                been pointed out (brief comment in the code?).

                --
                Martin




                Comment

                • CBFalconer

                  #9
                  Re: Why the zero case in fabs()?

                  Martin wrote:[color=blue]
                  >
                  > In Plauger's THE STANDARD C LIBRARY (1992) there is the source
                  > code for fabs.c (p140).
                  >
                  > /* fabs function */
                  > #include "xmath.h"
                  > double (fabs)(double x)
                  > {
                  > switch (_Dtest(&x))
                  > { /* test for special codes */
                  > case NAN:
                  > errno = EDOM;
                  > return (x);
                  > case INF:
                  > errno = ERANGE;
                  > return (_Inf._D);
                  > case 0:
                  > return (0.0);
                  > default: /* finite */
                  > return (x < 0.0 ? -x : x);
                  > }
                  > }
                  >
                  > This is not necessarily a question about fabs() in particular,
                  > but rather a question about the *technique* Plauger has employed,
                  > and if there is a subtlety involved.
                  >
                  > My question is: why is there a case for 0, which simply returns
                  > 0.0? Without it, the default case will trap it anyway, and return
                  > 0, which will be converted to double - the return type of the
                  > function.[/color]

                  The switch is not testing x, but whatever the return value of
                  _Dtest(&x) happens to be. That obviously involves some magic
                  incantations, and is outside the users name space. It might well
                  have something to do with the existance of -ve 0 in that
                  particular arithmetic system.
                  [color=blue]
                  >
                  > Also, I'm puzzled by the superfluous use of parentheses around
                  > the return expressions.[/color]

                  Superfluous is in the eye of the beholder. Plauger, and others,
                  feel that there is no further need to ration parentheses and that
                  they can be neatly used to delimit expressions.

                  --
                  Chuck F (cbfalconer@yah oo.com) (cbfalconer@wor ldnet.att.net)
                  Available for consulting/temporary embedded and systems.
                  <http://cbfalconer.home .att.net> USE worldnet address!


                  Comment

                  • Dan Pop

                    #10
                    Re: Why the zero case in fabs()?

                    In <nrf7g1-88t.ln1@jones.h omeip.net> lawrence.jones@ ugsplm.com writes:
                    [color=blue]
                    >Martin <martin.o_brien @[no-spam]which.net> wrote:[color=green]
                    >>
                    >> My question is: why is there a case for 0, which simply returns 0.0? Without
                    >> it, the default case will trap it anyway, and return 0, which will be
                    >> converted to double - the return type of the function.[/color]
                    >
                    >The subtlety you're missing is signed zeros. On implementations that
                    >have such things, -0.0 is not < 0.0, so the default case would return it
                    >as-is (i.e., -0.0) rather than returning the correct +0.0.[/color]

                    If -0.0 is not < 0.0, why is it an error to return it as such?

                    Dan
                    --
                    Dan Pop
                    DESY Zeuthen, RZ group
                    Email: Dan.Pop@ifh.de

                    Comment

                    • lawrence.jones@ugsplm.com

                      #11
                      Re: Why the zero case in fabs()?

                      Dan Pop <Dan.Pop@cern.c h> wrote:[color=blue]
                      >
                      > If -0.0 is not < 0.0, why is it an error to return it as such?[/color]

                      I won't defend the vagaries of signed zeros, but although -0.0 and +0.0
                      compare equal (obviously), -0.0 is nonetheless negative whereas the
                      result of fabs() should (obviously) be non-negative. Despite comparing
                      equal, -0.0 and +0.0 can still be distingished (e.g., by the signbit()
                      or copysign() functions).

                      -Larry Jones

                      I don't need to improve! Everyone ELSE does! -- Calvin

                      Comment

                      • Christian Bau

                        #12
                        Re: Why the zero case in fabs()?

                        In article <c0t9jq$dss$12@ sunnews.cern.ch >, Dan.Pop@cern.ch (Dan Pop)
                        wrote:
                        [color=blue]
                        > In <nrf7g1-88t.ln1@jones.h omeip.net> lawrence.jones@ ugsplm.com writes:
                        >[color=green]
                        > >Martin <martin.o_brien @[no-spam]which.net> wrote:[color=darkred]
                        > >>
                        > >> My question is: why is there a case for 0, which simply returns 0.0?
                        > >> Without
                        > >> it, the default case will trap it anyway, and return 0, which will be
                        > >> converted to double - the return type of the function.[/color]
                        > >
                        > >The subtlety you're missing is signed zeros. On implementations that
                        > >have such things, -0.0 is not < 0.0, so the default case would return it
                        > >as-is (i.e., -0.0) rather than returning the correct +0.0.[/color]
                        >
                        > If -0.0 is not < 0.0, why is it an error to return it as such?[/color]

                        If the implementor guarantees that the compiler implements not only the
                        C Standard, but also for example the IEEE 754 Standard then returning
                        -0.0 as the result of fabs (-0.0) is an error. It would violate the IEEE
                        754 Standard.

                        Comment

                        Working...