Rounding double

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

    #31
    Re: Rounding double

    jacob navia wrote:
    James Kuyper wrote:
    ....
    Probably. Your solution is always the best since you did not
    propose any
    ?
    I suggesting using sprintf() and sscanf(). I left the details to be
    worked out by the reader. Was that too obscure a hint for you?

    Comment

    • jacob navia

      #32
      Re: Rounding double

      Richard Heathfield wrote:
      >
      That, at least, is true. The best solution is to understand the inherent
      limitations in representing fractions, and to recognise that the
      appropriate way to deal with this is to deal with the rounding at the
      display stage.
      >
      That wasn't what the OP asked. He wanted to round it without any
      display, maybe to be used in further calculation or whatever.

      And it IS possible to round correctly a double precision
      number. One of the possible solutions is:

      #include <stdio.h>
      #include <math.h>

      void RoundMyDouble (long double *value, short numberOfPrecisi ons)

      {
      long double fv=fabsl(*value );
      if (fv 1e17)
      return ;
      long long p = powl(10.0L, numberOfPrecisi ons);
      *value = (long long)(*value * p + 0.5L) / (double)p;
      }

      This is quite awful, but it works (with 64 bit long long and
      wider precision long double)
      >But instead of proposing a better solution this people limit
      >to talking nonsense without ever proposing anything else.
      >
      Ah, we're back to "nonsense" as your synonym for "correct solution that
      Jacob Navia doesn't understand", are we?
      >
      Nonse means to tell the OP that what he is asking is
      impossible!
      >Then I get angry start getting mad at heathfield and this
      >degrades.
      >
      I think is the pompous tone that makes me nervous.

      "Ex cathedra"...


      --
      jacob navia
      jacob at jacob point remcomp point fr
      logiciels/informatique

      Comment

      • jacob navia

        #33
        Re: Rounding double

        James Kuyper wrote:
        jacob navia wrote:
        >James Kuyper wrote:
        ...
        >Probably. Your solution is always the best since you did not
        >propose any
        >
        ?
        I suggesting using sprintf() and sscanf(). I left the details to be
        worked out by the reader. Was that too obscure a hint for you?
        But he was asking for a function that returns a double, not
        asking about PRINTING a double.

        Maybe he wants to WRITE printf :-)

        Or you are saying that you belive this is impossible
        in C???

        double roundto(double n,int digits);

        I do not believe so. OK. My solution looks (and is horrible,
        but it has the merit of working for a wide range:
        #include <math.h>

        double RoundMyDouble (long double *value, short numberOfPrecisi ons)

        {
        long double fv=fabsl(*value );
        if (fv 1e17 ) // That could be replaced with some standard constant
        return ;
        long long p = powl(10.0L, numberOfPrecisi ons);
        return (long long)(*value * p + 0.5L) / (long double)p;
        }

        --
        jacob navia
        jacob at jacob point remcomp point fr
        logiciels/informatique

        Comment

        • Richard Heathfield

          #34
          Re: Rounding double

          jacob navia said:
          Richard Heathfield wrote:
          >>
          >That, at least, is true. The best solution is to understand the inherent
          >limitations in representing fractions, and to recognise that the
          >appropriate way to deal with this is to deal with the rounding at the
          >display stage.
          >>
          >
          That wasn't what the OP asked. He wanted to round it without any
          display, maybe to be used in further calculation or whatever.
          And it was demonstrated that this can't be done in general, so his
          requirement cannot be met in general.
          And it IS possible to round correctly a double precision
          number.
          Show me 0.33 rounded to one decimal place.
          One of the possible solutions is:
          >
          #include <stdio.h>
          #include <math.h>
          >
          void RoundMyDouble (long double *value, short numberOfPrecisi ons)
          >
          {
          long double fv=fabsl(*value );
          if (fv 1e17)
          return ;
          long long p = powl(10.0L, numberOfPrecisi ons);
          *value = (long long)(*value * p + 0.5L) / (double)p;
          }
          >
          This is quite awful, but it works (with 64 bit long long and
          wider precision long double)
          For 0.33 rounded to one decimal place with this code of yours, I get a
          result of 0.3000000000000 00000011, which is clearly wrong (it should be
          0.3).

          --
          Richard Heathfield <http://www.cpax.org.uk >
          Email: -http://www. +rjh@
          Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
          "Usenet is a strange place" - dmr 29 July 1999

          Comment

          • James Kuyper

            #35
            Re: Rounding double

            jacob navia wrote:
            James Kuyper wrote:
            >jacob navia wrote:
            >>James Kuyper wrote:
            >...
            >>Probably. Your solution is always the best since you did not
            >>propose any
            >>
            >?
            >I suggesting using sprintf() and sscanf(). I left the details to be
            >worked out by the reader. Was that too obscure a hint for you?
            >
            But he was asking for a function that returns a double, not
            asking about PRINTING a double.
            OK - so my hint WAS too obscure. Think about it a little while before
            you respond again. I'm sure you can figure it out with a little extra
            thought. In particular, think about the implications of the fact that I
            specified sprintf() rather than printf(), and sscanf() instead of scanf().

            Incidentally, the sprintf()/sscanf() combination is unnecessarily
            inefficient. One loop writes to a buffer, and another loop reads from
            it, and both loops spends time dealing with possibilities that don't
            apply in this context. It's possible to remove the buffer by extracting
            the loops from from sprintf() and sscanf(), simplifying them, and
            connecting them directly together. However, that's a significantly more
            complicated solution, and I wouldn't recommend attempting it unless you
            do in-memory rounding to a specified number of decimal digits
            frequently. I can't remember ever needing that capability. I round to a
            specified number of decimal digits only in my outputs.
            Or you are saying that you belive this is impossible
            in C???
            I wouldn't have provided a hint how to solve the problem, if I'd thought
            that solving the problem was impossible. I'm not a sadist.

            Comment

            • jacob navia

              #36
              Re: Rounding double

              Richard Heathfield wrote:
              Show me 0.33 rounded to one decimal place.
              >
              >One of the possible solutions is:
              >>
              >#include <stdio.h>
              >#include <math.h>
              >>
              >void RoundMyDouble (long double *value, short numberOfPrecisi ons)
              >>
              >{
              > long double fv=fabsl(*value );
              > if (fv 1e17)
              > return ;
              > long long p = powl(10.0L, numberOfPrecisi ons);
              > *value = (long long)(*value * p + 0.5L) / (double)p;
              >}
              >>
              >This is quite awful, but it works (with 64 bit long long and
              >wider precision long double)
              >
              For 0.33 rounded to one decimal place with this code of yours, I get a
              result of 0.3000000000000 00000011, which is clearly wrong (it should be
              0.3).
              >
              This is perfectly OK since double has only 16 decimal digits,
              and the first ones in your result appear at 1e-21 (if I counted
              correctly). Those values can't be accurately represented with
              double precision.

              You can't go beyond 1e-16, since DBL_DIG is 15.

              Writing it in in a more sensible way:

              double roundto(long double value, unsigned digits)
              {
              long double fv=fabsl(value) ;
              if (fv powl(10.0L,DBL_ DIG) || digits DBL_DIG)
              return value; // Out of range
              long long p = powl(10.0L, digits);
              return roundl(value * p ) / (double)p;
              }


              --
              jacob navia
              jacob at jacob point remcomp point fr
              logiciels/informatique

              Comment

              • jacob navia

                #37
                Re: Rounding double

                James Kuyper wrote:
                jacob navia wrote:
                >James Kuyper wrote:
                >>jacob navia wrote:
                >>>James Kuyper wrote:
                >>...
                >>>Probably. Your solution is always the best since you did not
                >>>propose any
                >>>
                >>?
                >>I suggesting using sprintf() and sscanf(). I left the details to be
                >>worked out by the reader. Was that too obscure a hint for you?
                >>
                >But he was asking for a function that returns a double, not
                >asking about PRINTING a double.
                >
                OK - so my hint WAS too obscure. Think about it a little while before
                you respond again. I'm sure you can figure it out with a little extra
                thought. In particular, think about the implications of the fact that I
                specified sprintf() rather than printf(), and sscanf() instead of scanf().
                >
                Incidentally, the sprintf()/sscanf() combination is unnecessarily
                inefficient. One loop writes to a buffer, and another loop reads from
                it, and both loops spends time dealing with possibilities that don't
                apply in this context. It's possible to remove the buffer by extracting
                the loops from from sprintf() and sscanf(), simplifying them, and
                connecting them directly together. However, that's a significantly more
                complicated solution, and I wouldn't recommend attempting it unless you
                do in-memory rounding to a specified number of decimal digits
                frequently. I can't remember ever needing that capability. I round to a
                specified number of decimal digits only in my outputs.
                >
                >Or you are saying that you belive this is impossible
                >in C???
                >
                I wouldn't have provided a hint how to solve the problem, if I'd thought
                that solving the problem was impossible. I'm not a sadist.
                double roundto(long double value, unsigned digits)
                {
                long double fv=fabsl(value) ;
                if (fv powl(10.0L,DBL_ DIG) || digits DBL_DIG)
                return value; // Out of range
                long long p = powl(10.0L, digits);
                return roundl(value * p ) / (double)p;
                }

                Supposing long double is extended precision, why should this not
                work?

                --
                jacob navia
                jacob at jacob point remcomp point fr
                logiciels/informatique

                Comment

                • Richard Heathfield

                  #38
                  Re: Rounding double

                  jacob navia said:
                  Richard Heathfield wrote:
                  <snip>
                  >For 0.33 rounded to one decimal place with this code of yours, I get a
                  >result of 0.3000000000000 00000011, which is clearly wrong (it should be
                  >0.3).
                  >>
                  >
                  This is perfectly OK since double has only 16 decimal digits,
                  and the first ones in your result appear at 1e-21 (if I counted
                  correctly). Those values can't be accurately represented with
                  double precision.
                  Nor can 0.3.
                  >
                  You can't go beyond 1e-16, since DBL_DIG is 15.
                  >
                  Writing it in in a more sensible way:
                  >
                  double roundto(long double value, unsigned digits)
                  {
                  long double fv=fabsl(value) ;
                  if (fv powl(10.0L,DBL_ DIG) || digits DBL_DIG)
                  return value; // Out of range
                  long long p = powl(10.0L, digits);
                  return roundl(value * p ) / (double)p;
                  }
                  Could someone else please share with us the result they get when they drive
                  this function with inputs of 0.33 and 1 ? I'm getting some very, very
                  strange results here.

                  --
                  Richard Heathfield <http://www.cpax.org.uk >
                  Email: -http://www. +rjh@
                  Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
                  "Usenet is a strange place" - dmr 29 July 1999

                  Comment

                  • Marco Manfredini

                    #39
                    Re: Rounding double

                    jacob navia wrote:
                    double roundto(long double value, unsigned digits)
                    {
                    long double fv=fabsl(value) ;
                    if (fv powl(10.0L,DBL_ DIG) || digits DBL_DIG)
                    return value; // Out of range
                    long long p = powl(10.0L, digits);
                    return roundl(value * p ) / (double)p;
                    }
                    >
                    Supposing long double is extended precision, why should this not
                    work?
                    Suppose long double is 128 bit and long long 64 bit. Why should this work?

                    Comment

                    • Flash Gordon

                      #40
                      Re: Rounding double

                      jacob navia wrote, On 22/11/07 23:01:
                      Richard Heathfield wrote:
                      >Show me 0.33 rounded to one decimal place.
                      >>
                      >>One of the possible solutions is:
                      >>>
                      >>#include <stdio.h>
                      >>#include <math.h>
                      >>>
                      >>void RoundMyDouble (long double *value, short numberOfPrecisi ons)
                      >>>
                      >>{
                      >> long double fv=fabsl(*value );
                      >> if (fv 1e17)
                      >> return ;
                      >> long long p = powl(10.0L, numberOfPrecisi ons);
                      >> *value = (long long)(*value * p + 0.5L) / (double)p;
                      >>}
                      >>>
                      >>This is quite awful, but it works (with 64 bit long long and
                      >>wider precision long double)
                      >>
                      >For 0.33 rounded to one decimal place with this code of yours, I get a
                      >result of 0.3000000000000 00000011, which is clearly wrong (it should
                      >be 0.3).
                      >>
                      >
                      This is perfectly OK
                      It does not meet the OPs requirements as specified.
                      since double has only 16 decimal digits,
                      and the first ones in your result appear at 1e-21 (if I counted
                      correctly). Those values can't be accurately represented with
                      double precision.
                      <snip>

                      Which is precisely the problem. If it is wanted for display then there
                      are better ways, if it is wanted for further calculations then it is
                      very important that the OP understand why it is not possible in general.
                      --
                      Flash Gordon

                      Comment

                      • Mark McIntyre

                        #41
                        Re: Rounding double

                        jacob navia wrote:
                        Who cares?
                        That works in lcc-win.
                        Lcc-win gives you the best of C and C++
                        This is a very bad answer, and precisely what you should /not/ have said
                        if you wanted to be taken seriously.

                        Comment

                        • jacob navia

                          #42
                          Re: Rounding double

                          Richard Heathfield wrote:
                          jacob navia said:
                          >
                          >Richard Heathfield wrote:
                          >
                          <snip>
                          >
                          >>For 0.33 rounded to one decimal place with this code of yours, I get a
                          >>result of 0.3000000000000 00000011, which is clearly wrong (it should be
                          >>0.3).
                          >>>
                          >This is perfectly OK since double has only 16 decimal digits,
                          >and the first ones in your result appear at 1e-21 (if I counted
                          >correctly). Those values can't be accurately represented with
                          >double precision.
                          >
                          Nor can 0.3.
                          >
                          >You can't go beyond 1e-16, since DBL_DIG is 15.
                          >>
                          >Writing it in in a more sensible way:
                          >>
                          >double roundto(long double value, unsigned digits)
                          >{
                          > long double fv=fabsl(value) ;
                          > if (fv powl(10.0L,DBL_ DIG) || digits DBL_DIG)
                          > return value; // Out of range
                          > long long p = powl(10.0L, digits);
                          > return roundl(value * p ) / (double)p;
                          >}
                          >
                          Could someone else please share with us the result they get when they drive
                          this function with inputs of 0.33 and 1 ? I'm getting some very, very
                          strange results here.
                          >
                          d:\lcc\mc68\tes t>type tdouble3.c
                          #include <stdio.h>
                          #include <float.h>
                          #include <math.h>

                          double roundto(long double value, unsigned digits)

                          {
                          long double fv = fabs(value);
                          if (fv powl(10.0L,DBL_ DIG) || digits DBL_DIG)
                          return value;
                          long long p = powl(10.0L, digits);
                          return roundl(p*value)/p;
                          }

                          int main(int argc,char *argv[])
                          {
                          long double v = atof(argv[1]);
                          short int ndp = 0;
                          while(ndp < DBL_DIG)
                          {
                          long double newv = v;
                          newv = roundto(newv, ndp);
                          printf("%.19Lf: %hd decimals %.16Lf\n",
                          v,
                          ndp++,
                          newv);
                          }

                          return 0;
                          }



                          d:\lcc\mc68\tes t>tdouble3 0.33
                          0.3300000000000 000160: 0 decimals 0.0000000000000 000
                          0.3300000000000 000160: 1 decimals 0.3000000000000 000
                          0.3300000000000 000160: 2 decimals 0.3300000000000 000
                          0.3300000000000 000160: 3 decimals 0.3300000000000 000
                          0.3300000000000 000160: 4 decimals 0.3300000000000 000
                          0.3300000000000 000160: 5 decimals 0.3300000000000 000
                          0.3300000000000 000160: 6 decimals 0.3300000000000 000
                          0.3300000000000 000160: 7 decimals 0.3300000000000 000
                          0.3300000000000 000160: 8 decimals 0.3300000000000 000
                          0.3300000000000 000160: 9 decimals 0.3300000000000 000
                          0.3300000000000 000160: 10 decimals 0.3300000000000 000
                          0.3300000000000 000160: 11 decimals 0.3300000000000 000
                          0.3300000000000 000160: 12 decimals 0.3300000000000 000
                          0.3300000000000 000160: 13 decimals 0.3300000000000 000
                          0.3300000000000 000160: 14 decimals 0.3300000000000 000

                          d:\lcc\mc68\tes t>tdouble3 1
                          1.0000000000000 000000: 0 decimals 1.0000000000000 000
                          1.0000000000000 000000: 1 decimals 1.0000000000000 000
                          1.0000000000000 000000: 2 decimals 1.0000000000000 000
                          1.0000000000000 000000: 3 decimals 1.0000000000000 000
                          1.0000000000000 000000: 4 decimals 1.0000000000000 000
                          1.0000000000000 000000: 5 decimals 1.0000000000000 000
                          1.0000000000000 000000: 6 decimals 1.0000000000000 000
                          1.0000000000000 000000: 7 decimals 1.0000000000000 000
                          1.0000000000000 000000: 8 decimals 1.0000000000000 000
                          1.0000000000000 000000: 9 decimals 1.0000000000000 000
                          1.0000000000000 000000: 10 decimals 1.0000000000000 000
                          1.0000000000000 000000: 11 decimals 1.0000000000000 000
                          1.0000000000000 000000: 12 decimals 1.0000000000000 000
                          1.0000000000000 000000: 13 decimals 1.0000000000000 000
                          1.0000000000000 000000: 14 decimals 1.0000000000000 000

                          d:\lcc\mc68\tes t>

                          --
                          jacob navia
                          jacob at jacob point remcomp point fr
                          logiciels/informatique

                          Comment

                          • Richard Heathfield

                            #43
                            Re: Rounding double

                            jacob navia said:
                            Richard Heathfield wrote:
                            >jacob navia said:
                            >>
                            >>Richard Heathfield wrote:
                            >>
                            ><snip>
                            >>
                            >>>For 0.33 rounded to one decimal place with this code of yours, I get a
                            >>>result of 0.3000000000000 00000011, which is clearly wrong (it should
                            >>>be 0.3).
                            >>>>
                            >>This is perfectly OK since double has only 16 decimal digits,
                            >>and the first ones in your result appear at 1e-21 (if I counted
                            >>correctly). Those values can't be accurately represented with
                            >>double precision.
                            >>
                            >Nor can 0.3.
                            >>
                            >>You can't go beyond 1e-16, since DBL_DIG is 15.
                            >>>
                            >>Writing it in in a more sensible way:
                            >>>
                            >>double roundto(long double value, unsigned digits)
                            >>{
                            >> long double fv=fabsl(value) ;
                            >> if (fv powl(10.0L,DBL_ DIG) || digits DBL_DIG)
                            >> return value; // Out of range
                            >> long long p = powl(10.0L, digits);
                            >> return roundl(value * p ) / (double)p;
                            >>}
                            >>
                            >Could someone else please share with us the result they get when they
                            >drive this function with inputs of 0.33 and 1 ? I'm getting some very,
                            >very strange results here.
                            >>
                            d:\lcc\mc68\tes t>type tdouble3.c
                            No, I said "someone else". I wouldn't trust you to make a cup of coffee,
                            let alone a computer program.

                            --
                            Richard Heathfield <http://www.cpax.org.uk >
                            Email: -http://www. +rjh@
                            Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
                            "Usenet is a strange place" - dmr 29 July 1999

                            Comment

                            • Mark McIntyre

                              #44
                              Re: Rounding double

                              jacob navia wrote:
                              This is perfectly OK since double has only 16 decimal digits,
                              This is incorrect. The ISO standard requires a double to have at least
                              10 digits, but specifies no upper bound.

                              5.2.4.2.2 Characteristics of floating types
                              8. The values given in the following list shall be replaced by constant
                              expressions with implementation-defined values that are greater or equal
                              in magnitude (absolute value) to those shown, with the same sign:
                              FLT_DIG 6
                              DBL_DIG 10
                              LDBL_DIG 10

                              There are a couple of worked examples showing 15 digits, and one
                              footnote that references the ISO/IEC floating point standard, but
                              nothing else normative.

                              Comment

                              • jacob navia

                                #45
                                Re: Rounding double

                                Mark McIntyre wrote:
                                jacob navia wrote:
                                >This is perfectly OK since double has only 16 decimal digits,
                                >
                                This is incorrect. The ISO standard requires a double to have at least
                                10 digits, but specifies no upper bound.
                                >
                                5.2.4.2.2 Characteristics of floating types
                                8. The values given in the following list shall be replaced by constant
                                expressions with implementation-defined values that are greater or equal
                                in magnitude (absolute value) to those shown, with the same sign:
                                FLT_DIG 6
                                DBL_DIG 10
                                LDBL_DIG 10
                                >
                                There are a couple of worked examples showing 15 digits, and one
                                footnote that references the ISO/IEC floating point standard, but
                                nothing else normative.
                                That "footnote" is Annex F, and it IS normative. I cite (again)

                                F.2 Types
                                1 The C floating types match the IEC 60559 formats as follows:
                                — The float type matches the IEC 60559 single format.
                                — The double type matches the IEC 60559 double format

                                --
                                jacob navia
                                jacob at jacob point remcomp point fr
                                logiciels/informatique

                                Comment

                                Working...