converting float to double

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

    #91
    Re: converting float to double

    On 21 Dec 2006 21:08:59 -0800, in comp.lang.c , "William Hughes"
    <wpihughes@hotm ail.comwrote:
    >
    >Assume possible precise answers are spaced at intervals of the smallest
    >currency unit.
    >
    >We convert the floating point value to a precise answer by
    >finding the closest precise answer.
    >
    >We now see that as long as the error is less that 1/2 of the smallest
    >currency spacing, the closest precise answer will also be the
    >correct answer.
    This doesn't follow, unless the currency rounding rule is to select
    the closest precise answer, and in that case its tautological.

    Several markets and currencies do not follow this rule - eg they
    always round down, or always discard pennies, or round up if the
    integer part is even, and down if its odd. Or whatever.

    If you want "correct" values, you need to implement special handling
    routines for rounding.
    --
    Mark McIntyre

    "Debugging is twice as hard as writing the code in the first place.
    Therefore, if you write the code as cleverly as possible, you are,
    by definition, not smart enough to debug it."
    --Brian Kernighan

    Comment

    • William Hughes

      #92
      Re: converting float to double


      Mark McIntyre wrote:
      On 21 Dec 2006 21:08:59 -0800, in comp.lang.c , "William Hughes"
      <wpihughes@hotm ail.comwrote:
      >

      Assume possible precise answers are spaced at intervals of the smallest
      currency unit.

      We convert the floating point value to a precise answer by
      finding the closest precise answer.

      We now see that as long as the error is less that 1/2 of the smallest
      currency spacing, the closest precise answer will also be the
      correct answer.
      >
      This doesn't follow, unless the currency rounding rule is to select
      the closest precise answer, and in that case its tautological.
      >
      You are confusing levels.

      Calculate the precise answer.
      (This may include arbitrary rules, such as
      "every second thursday of a month that doesn't
      contain r, add 1). It is at this level
      that the rounding rules you are talking about
      are relevent

      Represent the precise answer. (assumed to
      be an integral number of currency units)
      One method is to store the precise answer
      as an integer. However, any method of
      coding that can be unabiguously solved
      will work. An obvious alternative is to
      code the precise answer as any floating
      point number with the property that it is
      closer to the desired value, than any
      non desired value. The "rounding" here is
      just a decoding mechanism. It has nothing
      to do with the accounting rules of rounding.

      Several markets and currencies do not follow this rule - eg they
      always round down, or always discard pennies, or round up if the
      integer part is even, and down if its odd. Or whatever.
      >
      If you want "correct" values, you need to implement special handling
      routines for rounding.
      Duh! If you want the correct answer you have to calculate it.
      I am not saying that floating point arithmetic mirrors financial
      rules, only that financial rules can be expressed as conveniently
      in floating point as in integer.

      - William Hughes

      Comment

      • Random832

        #93
        Re: converting float to double

        2006-12-22 <JAnoyr.Au2@cwi .nl>,
        Dik T. Winter wrote:
        In article <1166749185.938 450.114020@80g2 000cwy.googlegr oups.com"christ ian.bau" <christian.bau@ cbau.wanadoo.co .ukwrites:
        Ernie Wright wrote:
        >
        If the floats you're getting are precise to one cent, you can recover
        their exact values with

        dollars = ( int ) f;
        cents = ( int )( f * 100 + 0.5 ) % 100;
        >
        Before you do this in real life, try what happens when f = 19.999.
        >
        Is that a float precise to one cent?
        Not as such. But generally when doing such a thing we would want it to
        properly translate 19.999998092651 3671875 (i.e. a single value off in
        either direction) to 20.00

        Comment

        • Dik T. Winter

          #94
          Re: converting float to double

          In article <slrneono7b.cbj .random@rlaptop .random.yi.orgrandom832@gmail .com writes:
          2006-12-22 <JAnoyr.Au2@cwi .nl>,
          Dik T. Winter wrote:
          In article <1166749185.938 450.114020@80g2 000cwy.googlegr oups.com"christ ian.bau" <christian.bau@ cbau.wanadoo.co .ukwrites:
          Ernie Wright wrote:
          If the floats you're getting are precise to one cent, you can recover
          their exact values with

          dollars = ( int ) f;
          cents = ( int )( f * 100 + 0.5 ) % 100;
          >
          Before you do this in real life, try what happens when f = 19.999.
          Is that a float precise to one cent?
          >
          Not as such. But generally when doing such a thing we would want it to
          properly translate 19.999998092651 3671875 (i.e. a single value off in
          either direction) to 20.00
          Indeed. The statement for dollars should have been:
          dollars = (int)(f * 100 + 0.5) / 100;
          --
          dik t. winter, cwi, kruislaan 413, 1098 sj amsterdam, nederland, +31205924131
          home: bovenover 215, 1025 jn amsterdam, nederland; http://www.cwi.nl/~dik/

          Comment

          • christian.bau

            #95
            Re: converting float to double

            Dik T. Winter wrote:
            In article <1166747497.876 931.68250@42g20 00cwt.googlegro ups.com"christi an.bau" <christian.bau@ cbau.wanadoo.co .ukwrites:
            Christian. I thought you knew better than this. With the multiplication
            by 1000 we get another rounding. (The multiplication is done in single
            precision.) But apparently you should avoid gcc on both Linux and
            Solaris. Try the following program with your favourite compiler:
            Yes, I got this wrong. I missed that f * 1000.0 was again assigned to a
            float. Which makes the situation more interesting. So here is my
            analysis:

            Given is a number f, which is equal to an integer x, divided by 100,
            rounded to the nearest float value - which obviously gives a rather
            large rounding error. An attempt to recover a more precise value is
            done by calculating t = (float) (f * 1000.0), then calculating d =
            (double) t / 1000.0.

            Assume 2^k <= f < 2*2^k. f is equal to the correct x/100 + eps, where
            |eps| is less than 1/2 of the least significant bit. f * 1000 is equal
            to 10x + 1000eps. t will often be in the range 2^(k+10) <= t <
            2*2^(k+10). The difference between f * 1000 and 10x is 1000eps, the
            absolute value of this is less than 500 times the least significant
            bit.

            If 10x can be exactly represented as a float, and 10x >= 2^(2k+10),
            then f * 1000 is guaranteed to be so close to 10x that it will be
            rounded to 10x, so t = 10x, and therefore d will be a much more precise
            result. However, this is not the case if 10x < 2^(2k+10) = 1024 * 2^k
            or 1000f < 1024 * 2^k or f < 1.024 * 2^k. So any dollar values between
            2^k and 1.024 * 2^k are suspicious, that is values 1.01 and 1.02, 2.01
            to 2.04, 4.01 to 4.09 and so on.

            The first number where this algorithm fails is 4.01, and it fails for
            many values slightly above 4, 8, 16, 32 and so on. It also fails when
            10x cannot be represented in a float value; since 10x is even this will
            be the case when 10x 2^25 (using 32 bit float) or when the dollar
            value is more than 1.024 * $32768.

            There is a twist if this is used for share prices: While most share
            prices are a whole number of cents, prices for low valued shares can be
            in tenths of cents or hundredths of cents. This algorithm also recovers
            most, but not all, prices that are in tenths of cents correctly (and
            will usually fail for hundredths of cents). Replacing the code with
            something that rounds to the nearest cent will make this stop working.

            Comment

            • CBFalconer

              #96
              Re: converting float to double

              "Dik T. Winter" wrote:
              >
              .... snip ...
              >
              Indeed. The statement for dollars should have been:
              dollars = (int)(f * 100 + 0.5) / 100;
              Assuming dollars is an int (or even a double or float) the usual
              rule about casts applies. They are almost always an error, or
              useless. Simply omit them unless you have a very good and clear
              reason for them. In this particular case the compiler will happily
              adapt to declaring dollars as a long, or even a long long (for
              C99). In fact, the code shown will happily discard the cents field
              when destined for a float or double. Maybe that is what you
              intended.

              Assuming that is the intention (i.e. exact float representations by
              making them integral) you can improve efficiency by:

              int incents;
              float dollars, cents, f;

              incents = f * 100 + 0.5;
              dollars = incents / 100;
              cents = incents % 100;

              avoiding the run time expense of multiple float to int conversions
              (which the optimizer might have handled) and avoiding all casts.
              The code will remain correct if the floats are changed to doubles,
              simplifying maintenance.

              --
              Chuck F (cbfalconer at maineline dot net)
              Available for consulting/temporary embedded and systems.
              <http://cbfalconer.home .att.net>


              Comment

              • Dik T. Winter

                #97
                Re: converting float to double

                In article <1166764139.463 709.72170@a3g20 00cwd.googlegro ups.com"William Hughes" <wpihughes@hotm ail.comwrites:
                Dik T. Winter wrote:
                In article <1166710344.907 715.100550@a3g2 000cwd.googlegr oups.com"Willia m Hughes" <wpihughes@hotm ail.comwrites:
                ....
                I:
                The whole point is that in most financial transactions it is
                precisely defined how fractions of something should be rounded.
                Any attempt to be slightly imprecise (using floating point)
                will fail at some point or another.
                ....
                ??. You cannot do non-trivial calculations to a precision
                greater that 1/2 of your smallest currency unit?
                Eh? I can not follow this.
                >
                The question is. Can we determine the correct answer from
                the floating point value.
                And I state: no.
                Assume possible precise answers are spaced at intervals of the smallest
                currency unit.
                >
                We convert the floating point value to a precise answer by
                finding the closest precise answer.
                >
                We now see that as long as the error is less that 1/2 of the smallest
                currency spacing, the closest precise answer will also be the
                correct answer.
                Care to explain? I find that with an initial amount of $100 and with
                an interest rate over some period of 2.5%, where the rules state that
                the interest has been truncated to the nearest cent, the following
                statements (assuming amount to be a long, damount and eamount doubles):
                amount += amount * 5 / 200;
                damount += damount * 5 / 200;
                eamount = rint(eamount * 205 / 200);
                there are already differences after the third calculation. You really
                need "floor" rather than "rint" in the eamount statement to get the
                correct results. And this is only a simple problem of compound
                interest.

                Determining whether the final result after a number of f-p
                calculations is within 1/2 of the correct result is not doable.
                As long as you use only integer representations in your floating point
                type there is no problem.
                >
                No, as long as the floating point representation remains within
                half of your smallest currency unit there is not problem.
                Depends on the kind of rounding needed for the particular problem.
                And when the calculations are only slightly difficult you get problems.
                However, be aware that each time you should
                be sure that your floating point variable represents an integer.
                >
                Why? All I need is to be sure that I can recover the correct value.
                And how can you be sure of that?
                This can be done as conveniently using floating point arithmetic
                as using fixed point arithmetic. In either case you have to
                do rounding.
                If you need rounding at each step of your floating point calculations, I
                do not see any advantage using that type over an integral type.
                >
                No, you round where required by accountancy rules or when
                needed for precision. This may be much less than every step.
                How do you keep track when you should round? In the above compound
                interest example I see already that if I do not round at every step
                that I get already a wrong result with f-p after three iterations.
                And there is a big advantage
                in being able to use the existing floating point system rather
                than having to obtain or roll you own fixed point system.
                I do not think so. 64-bit integers are becoming quite common, and
                they give better precision than double precision f-p.
                On the
                other hand, when you are using floating-point it is likely that you will
                use the exp function to calculate compound interest. That will, almost
                certainly, give the wrong result.
                >
                Why? There is no reason to turn you brain off when you use floating
                point. If the exp function does not give the accounting answer, and
                you want the accounting answer, then don't use the exp function (Duh!).
                And if floating point does not give the accounting answer, and you want
                the accounting answer, then don't use floating point.

                But try it out with the above rules and an interest rate of 0.5 % per
                period (which means that if that is a monthly period, the yearly
                interest rate is about 6.12 %). After about 2 to 4 periods there is
                a difference between integer and f-p when you do not do intermittently
                rounding. (And if the initial capital is $101 the difference shows up
                earlier...)
                --
                dik t. winter, cwi, kruislaan 413, 1098 sj amsterdam, nederland, +31205924131
                home: bovenover 215, 1025 jn amsterdam, nederland; http://www.cwi.nl/~dik/

                Comment

                • William Hughes

                  #98
                  Re: converting float to double

                  Dik T. Winter wrote:
                  In article <1166764139.463 709.72170@a3g20 00cwd.googlegro ups.com"William Hughes" <wpihughes@hotm ail.comwrites:
                  Dik T. Winter wrote:
                  In article <1166710344.907 715.100550@a3g2 000cwd.googlegr oups.com"Willia m Hughes" <wpihughes@hotm ail.comwrites:
                  ...
                  I:
                  The whole point is that in most financial transactions it is
                  precisely defined how fractions of something should be rounded.
                  Any attempt to be slightly imprecise (using floating point)
                  will fail at some point or another.
                  ...
                  ??. You cannot do non-trivial calculations to a precision
                  greater that 1/2 of your smallest currency unit?

                  Eh? I can not follow this.
                  >
                  The question is. Can we determine the correct answer from
                  the floating point value.
                  >
                  And I state: no.
                  >
                  Assume possible precise answers are spaced at intervals of the smallest
                  currency unit.
                  >
                  We convert the floating point value to a precise answer by
                  finding the closest precise answer.
                  >
                  We now see that as long as the error is less that 1/2 of the smallest
                  currency spacing, the closest precise answer will also be the
                  correct answer.
                  >
                  Care to explain? I find that with an initial amount of $100 and with
                  an interest rate over some period of 2.5%, where the rules state that
                  the interest has been truncated to the nearest cent, the following
                  statements (assuming amount to be a long, damount and eamount doubles):
                  amount += amount * 5 / 200;
                  damount += damount * 5 / 200;
                  eamount = rint(eamount * 205 / 200);
                  there are already differences after the third calculation. You really
                  need "floor" rather than "rint" in the eamount statement to get the
                  correct results. And this is only a simple problem of compound
                  interest.
                  You are confusing levels. If the rule says truncate, then
                  truncate do not round. The "rounding" required to
                  convert a double representation to an integer
                  representation has little to do with the algorithm used
                  to compute the double representation.

                  There are two questions:

                  What algorithm should be implemented?

                  What data type should be used to implement the algorithm?

                  The two questions are different, and the first dominates. When you
                  change
                  data type should not change the algorithm!

                  Consider an algorithm for compound intererest with slightly
                  modified rounding, principal
                  p, interest rate per period i, number of periods n, currency dollar.

                  For period 1 to n

                  p = round to nearest cent ( p + i p)

                  We can calculate this using a sufficiently large integer type
                  or a sufficiently large floating point type. Assume p = 100.00
                  i= .05/year, the period is 6 months and there are 10 periods.


                  An integer implementation might look like

                  long p = 10000;
                  int 1000_i = 50;
                  int number_of_perio ds n=10;
                  int 1000_i_per_n;

                  1000_i_per_n = 1000_i / 2;

                  for(i = 1;i<=n;i++){

                  p += p*1000_i_per_n/1000

                  if( 2*( p%1000_i_per_n) >= 1000_i_per_n ){
                  p++;
                  }

                  }

                  At the end we convert to dollars and cents, dollars = p/100,
                  cents = p%100.

                  A floating point implemenation might look like

                  double p = 10000;
                  double i = .05;
                  double i_per_n;
                  int number_of_perio ds n = 10;

                  i_per_n = i/2.0;


                  for(i = 1;i<=10;i++){

                  p += p*i_per_n;

                  if( fmod(100*p,1.0) 0.495) {
                  p += .01;
                  }


                  }

                  At the end you determine dollars = floor(p), cents = floor(100*p + 0.5)

                  I see no clear winner here. Both give exaclty the
                  same answer (even for unrealistically large values
                  of n) The rounding rule is a bit clearer
                  in the integer form (and if we specify truncation it can be
                  ommited altogether in the integer form, not so in the floating
                  point form) but the interest rate calculation is a bit more
                  natural in the floating point form. The integer form only works with
                  interest rate
                  per period in multiples of .001. This may need to be made
                  more precise. If accounting rules so specifiy, the interest rate
                  per period of the floating point form might have to be made less
                  precise.
                  Determining whether the final result after a number of f-p
                  calculations is within 1/2 of the correct result is not doable.
                  >
                  As long as you use only integer representations in your floating point
                  type there is no problem.
                  >
                  No, as long as the floating point representation remains within
                  half of your smallest currency unit there is not problem.
                  >
                  Depends on the kind of rounding needed for the particular problem.
                  No. The rounding needed for the particluar problem
                  is performed. The "rounding" needed to convert from the floating
                  point representation to an integer representation is something
                  different.
                  And when the calculations are only slightly difficult you get problems.
                  >
                  Not different than the problems associated with integer
                  calculations (you have the advantage that a truncation is
                  a nop with integer math. Given that you need to implement
                  general rounding rules in any case, I do not see this as
                  a big advantage)
                  However, be aware that each time you should
                  be sure that your floating point variable represents an integer.
                  >
                  Why? All I need is to be sure that I can recover the correct value.
                  >
                  And how can you be sure of that?
                  >
                  This can be done as conveniently using floating point arithmetic
                  as using fixed point arithmetic. In either case you have to
                  do rounding.

                  If you need rounding at each step of your floating point calculations, I
                  do not see any advantage using that type over an integral type.
                  >
                  No, you round where required by accountancy rules or when
                  needed for precision. This may be much less than every step.
                  >
                  How do you keep track when you should round? In the above compound
                  interest example I see already that if I do not round at every step
                  that I get already a wrong result with f-p after three iterations.
                  >
                  If you do not implement the correct algorithm you get
                  the wrong answer (Duh!).

                  You have to round after every step with integer arithmetic.
                  The fact that if the rounding rule is truncation you can
                  ommit this step is not true in general.
                  And there is a big advantage
                  in being able to use the existing floating point system rather
                  than having to obtain or roll you own fixed point system.
                  >
                  I do not think so. 64-bit integers are becoming quite common, and
                  they give better precision than double precision f-p.
                  >
                  And both are too small for some real world problems.
                  The class of problems for which double is insufficient, but
                  64 bit integer is sufficient, is not very large.

                  You still need to deal with fractions. Whether
                  you do so by using a fixed point system or
                  approximate rational arithmetic, native
                  support for 64 bits will only take you so far.
                  On the
                  other hand, when you are using floating-point it is likely that you will
                  use the exp function to calculate compound interest. That will, almost
                  certainly, give the wrong result.
                  >
                  Why? There is no reason to turn you brain off when you use floating
                  point. If the exp function does not give the accounting answer, and
                  you want the accounting answer, then don't use the exp function (Duh!).
                  >
                  And if floating point does not give the accounting answer, and you want
                  the accounting answer, then don't use floating point.
                  >
                  A sufficiently precise floating point can be used to implement
                  any accounting algorithm. The question is whether
                  this is less convenient that using (sufficiently large)
                  integer arithmetic.

                  - William Hughes

                  Comment

                  • William Hughes

                    #99
                    Re: converting float to double


                    William Hughes wrote:
                    Dik T. Winter wrote:
                    >>
                    A floating point implemenation might look like
                    >
                    double p = 10000;
                    double i = .05;
                    double i_per_n;
                    int number_of_perio ds n = 10;
                    >
                    i_per_n = i/2.0;
                    >
                    >
                    for(i = 1;i<=10;i++){
                    >
                    p += p*i_per_n;
                    >
                    Correction
                    if( fmod(100*p,1.0) 0.495) {
                    p += .01;
                    }
                    >
                    Should be

                    if( fmod(100*p,1.0) 0.495) {
                    p += .01 - fmod(p,0.01);

                    }
                    else {
                    p -= fmod(p,0.01);
                    }

                    - William Hughes

                    Comment

                    • Dik T. Winter

                      Re: converting float to double

                      In article <1166861246.723 939.80850@80g20 00cwy.googlegro ups.com"William Hughes" <wpihughes@hotm ail.comwrites:
                      Dik T. Winter wrote:
                      ....
                      Consider an algorithm for compound intererest with slightly
                      modified rounding, principal
                      p, interest rate per period i, number of periods n, currency dollar.
                      >
                      For period 1 to n
                      p = round to nearest cent ( p + i p)
                      We can calculate this using a sufficiently large integer type
                      or a sufficiently large floating point type. Assume p = 100.00
                      i= .05/year, the period is 6 months and there are 10 periods.
                      If the period is 1/2 year, the interest per period is not one half of
                      the year interest. Try to do it over a five year period. A yearly
                      interest rate of .05 gives after five years $ 127.63 and an half-yearly
                      interest rate of .025 gives after five years $ 128.01. A difference
                      that some accountants worry about. There are specific rules how to
                      do interest about a period smaller than the base period (although the
                      rules depend on the situation).

                      But let me assume that the interest is 0.025 / 6 months.
                      An integer implementation might look like
                      long p = 10000;
                      int 1000_i = 50;
                      int number_of_perio ds n=10;
                      int 1000_i_per_n;
                      >
                      1000_i_per_n = 1000_i / 2;
                      for(i = 1;i<=n;i++){
                      p += p*1000_i_per_n/1000
                      if( 2*( p%1000_i_per_n) >= 1000_i_per_n ){
                      p++;
                      }
                      }
                      I would do it as:
                      long amount = 20000; /* 2 times the amount in cents */
                      ...
                      for(i = 1; i <= n; i++) {
                      amount += amount * 1000_i_per_n / 1000;
                      amount += (amount & 1);
                      }
                      amount /= 2; /* the real amount in cents after the calculations */
                      Your formulation is wrong. When the amount is 10769 cents (3-rd
                      iteration), the interest calculations give an interest of 269.225 cents,
                      that is rounded 269 cents. The next result is 11038 cents. Your formula
                      gives 11039.
                      What is wrong is that your formulation uses cents as units for p and
                      you try to find out what has been rounded off from that value. But your
                      formulation is about twice as slow as mine. (For 1,000,000 iterations
                      52 vs. 32 seconds.) Improving the condition when a cent should be added
                      would increase the calculation time.
                      A floating point implemenation might look like
                      double p = 10000;
                      double i = .05;
                      double i_per_n;
                      int number_of_perio ds n = 10;
                      >
                      i_per_n = i/2.0;
                      for(i = 1;i<=10;i++){
                      p += p*i_per_n;
                      if( fmod(100*p,1.0) 0.495) {
                      p += .01 - fmod(p, 0.01);
                      } else {
                      p -= fmod(p, 0.01);
                      }
                      }
                      I incorporated your later improvement. But the result still is wrong.
                      You get already a difference after the 18-th iteration with the
                      formulation I did give. And when I introduce a "p = floor(p + 0.5);"
                      in each iteration it goes wrong at the 63-rd step (strange enough
                      the first case where the error is in favour of the bank). And without
                      the ftrunc the calculation (with 1,000,000 iterations) takes 0.73
                      seconds, with it it takes 0.90 seconds. You would be better off if
                      you had eliminated the complete conditional statement and replaced it
                      by a simple "p = floor(p + 0.5)". In that case the formulation would
                      be correct (and it would win in terms of speed on the machine I did
                      try it on: 0,22 seconds for 1,000,000 iterations). But now you simply
                      do an emulated version of integer arithmetic with floating point.
                      That can or can not be faster than a true integer formulation, depending
                      on machine architecture.
                      I see no clear winner here. Both give exaclty the
                      same answer (even for unrealistically large values
                      of n)
                      I have indicated above where your calculations give wrong results.
                      The rounding rule is a bit clearer
                      in the integer form (and if we specify truncation it can be
                      ommited altogether in the integer form, not so in the floating
                      point form) but the interest rate calculation is a bit more
                      natural in the floating point form.
                      But interest calculations for part periods are *far* from natural.
                      In my opinion, my formulation is clear, concise, and fast. *And*
                      you need proper scaling.
                      And when the calculations are only slightly difficult you get problems.
                      >
                      Not different than the problems associated with integer
                      calculations (you have the advantage that a truncation is
                      a nop with integer math. Given that you need to implement
                      general rounding rules in any case, I do not see this as
                      a big advantage)
                      See above.
                      How do you keep track when you should round? In the above compound
                      interest example I see already that if I do not round at every step
                      that I get already a wrong result with f-p after three iterations.
                      >
                      If you do not implement the correct algorithm you get
                      the wrong answer (Duh!).
                      Well, you did not do that either.
                      You have to round after every step with integer arithmetic.
                      The fact that if the rounding rule is truncation you can
                      ommit this step is not true in general.
                      You also have to round after every step with f-p arithmetic. And it
                      does not matter whether the rounding rule is round to nearest, truncate
                      or the bankers rule. You have to do it. And I admit that bankers rule
                      is not easy in integer arithmetic, but it is also not easy in f-p
                      arithmetic. Let me make an attempt. a is the amount in cents, interest
                      is the interest per 1000 per period.
                      i = a * interest / 500;
                      if(i & 1) { /* if the interest truncates to half a cent */
                      if(i * 500 a * interest) { /* if less than 0.5 is truncated */
                      i++; /* round up */
                      } else if(i & 2) { /* amount in cents is odd */
                      i++; /* round up */
                      }
                      }
                      a += (i >1);
                      This, indeed, can be done better in IEEE f-p:
                      i = rint(a * interest / 1000);
                      a += i;

                      But you are still emulating integer arithmetic in f-p.
                      --
                      dik t. winter, cwi, kruislaan 413, 1098 sj amsterdam, nederland, +31205924131
                      home: bovenover 215, 1025 jn amsterdam, nederland; http://www.cwi.nl/~dik/

                      Comment

                      • Ernie Wright

                        Re: converting float to double

                        Random832 wrote:
                        >>Ernie Wright wrote:
                        >>>
                        >>>If the floats you're getting are precise to one cent, you can
                        >>>recover their exact values with
                        >>>>
                        >>> dollars = ( int ) f;
                        >>> cents = ( int )( f * 100 + 0.5 ) % 100;
                        >
                        [...] But generally when doing such a thing we would want it to
                        properly translate 19.999998092651 3671875 (i.e. a single value off in
                        either direction) to 20.00
                        I agree, for real code, and should have said so earlier.

                        - Ernie http://home.comcast.net/~erniew

                        Comment

                        • Ernie Wright

                          Re: converting float to double

                          christian.bau wrote:
                          Yes, I got this wrong. I missed that f * 1000.0 was again assigned to
                          a float. Which makes the situation more interesting. So here is my
                          analysis:
                          [excellent analysis snipped]
                          So any dollar values between 2^k and 1.024 * 2^k are suspicious, that
                          is values 1.01 and 1.02, 2.01 to 2.04, 4.01 to 4.09 and so on.
                          >
                          The first number where this algorithm fails is 4.01, and it fails for
                          many values slightly above 4, 8, 16, 32 and so on.
                          Very illuminating, I wish I'd done this.

                          Note to the unwary: I initially tested this with something like the
                          following,

                          float f;
                          double d, d0;
                          int i;

                          for ( i = 1; i <= 10000; i++ ) { /* $0.01 to $100.00 */
                          d0 = i / 100.0; /* best possible precision */

                          f = i / 100.0f; /* funky rounding method */
                          f *= 1000.0; /* questioned by the OP */
                          d = f / 1000.0;

                          if ( d != d0 ) { /* are they the same? */
                          printf( "%8.2f", d );
                          }

                          in Microsoft C on an x86 machine, and found that d != d0 was never true.
                          As it turns out, MS C never actually uses the 32-bit value of f when it
                          appears on the right side of the assignments. It uses the 80-bit value
                          still sitting at the top of the FP stack after the previous calculation,
                          and as both Christian and Dik point out, the rounding of f in

                          f *= 1000.0

                          is crucial to the behavior.

                          I found that inserting expressions involving address-of f,

                          f = i / 100.0f;
                          testf( &f ); /* here */
                          f *= 1000.0;
                          testf( &f ); /* and here */
                          d = f / 1000.0;

                          forced the compiler to reload the contents of f after each line, and
                          this produced the expected result: the funky *1000/1000 rounding fails
                          for 4.01, 4.03, 4.05, 4.07, 4.09, 8.02, 8.03, 8.06, and so on.

                          The moral being that writing test code often isn't enough.

                          - Ernie http://home.comcast.net/~erniew

                          Comment

                          • William Hughes

                            Re: converting float to double


                            Dik T. Winter wrote:
                            In article <1166861246.723 939.80850@80g20 00cwy.googlegro ups.com"William Hughes" <wpihughes@hotm ail.comwrites:
                            Dik T. Winter wrote:
                            ...
                            Consider an algorithm for compound intererest with slightly
                            modified rounding, principal
                            p, interest rate per period i, number of periods n, currency dollar.
                            >
                            For period 1 to n
                            p = round to nearest cent ( p + i p)
                            We can calculate this using a sufficiently large integer type
                            or a sufficiently large floating point type. Assume p = 100.00
                            i= .05/year, the period is 6 months and there are 10 periods.
                            >
                            If the period is 1/2 year, the interest per period is not one half of
                            the year interest.
                            Try to do it over a five year period. A yearly
                            interest rate of .05 gives after five years $ 127.63 and an half-yearly
                            interest rate of .025 gives after five years $ 128.01. A difference
                            that some accountants worry about. There are specific rules how to
                            do interest about a period smaller than the base period (although the
                            rules depend on the situation).
                            >
                            But let me assume that the interest is 0.025 / 6 months.
                            >
                            An integer implementation might look like
                            long p = 10000;
                            int 1000_i = 50;
                            int number_of_perio ds n=10;
                            int 1000_i_per_n;
                            >
                            1000_i_per_n = 1000_i / 2;
                            for(i = 1;i<=n;i++){
                            p += p*1000_i_per_n/1000
                            if( 2*( p%1000_i_per_n) >= 1000_i_per_n ){
                            p++;
                            }
                            }
                            >
                            I would do it as:
                            long amount = 20000; /* 2 times the amount in cents */
                            ...
                            for(i = 1; i <= n; i++) {
                            amount += amount * 1000_i_per_n / 1000;
                            amount += (amount & 1);
                            }
                            amount /= 2; /* the real amount in cents after the calculations */
                            Your formulation is wrong. When the amount is 10769 cents (3-rd
                            iteration), the interest calculations give an interest of 269.225 cents,
                            that is rounded 269 cents. The next result is 11038 cents. Your formula
                            gives 11039.
                            Teach me to try to program at 4 am. Both attempts were
                            had errors. Here is a (hopefully) correct version.

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


                            long p = 10000;
                            long delta_p;
                            int i_1000 = 50;
                            int i_1000_per_n;

                            double dp = 100.0;
                            double i = .05;
                            double i_per_n;


                            int n = 200; /*number of periods*/
                            int j;

                            int i_dollars, i_cents, d_dollars, d_cents;

                            i_1000_per_n = i_1000 / 2;
                            i_per_n = i/2.0;

                            for(j = 1;j<=n;j++){


                            delta_p = p*i_1000_per_n/1000;



                            if( (p*i_1000_per_n %1000) >= 500 ){

                            delta_p++;
                            }


                            p += delta_p;





                            dp += dp*i_per_n;

                            if( fmod(dp,0.01) 0.00495) {
                            dp += .01 - fmod(dp, 0.01);
                            } else {
                            dp -= fmod(dp, 0.01);
                            }

                            if( j%10 == 0 ) {

                            i_dollars = p/100;
                            i_cents = p % 100;

                            d_dollars = floor(dp);
                            d_cents = floor(100*dp+.0 5) - 100*d_dollars;


                            printf("%d %d %d %d
                            %d\n",j,i_dolla rs,i_cents,d_do llars,d_cents);
                            }



                            }
                            }


                            I see no clear advantage to using integer or floating
                            point. Yes, both can be optimized, but as calculation
                            speed is unlikely to be the bottleneck, optimization is
                            unlikely to be needed.

                            (I do not find the doubling trick to be very natural, and
                            it does not generalize to other forms of rounding)


                            - William Hughes

                            Comment

                            • Dik T. Winter

                              Re: converting float to double

                              In article <1167280845.058 848.99960@f1g20 00cwa.googlegro ups.com"William Hughes" <wpihughes@hotm ail.comwrites:
                              Dik T. Winter wrote:
                              ....
                              Note this part of my article:
                              If the period is 1/2 year, the interest per period is not one half of
                              the year interest.
                              Try to do it over a five year period. A yearly
                              interest rate of .05 gives after five years $ 127.63 and an half-yearly
                              interest rate of .025 gives after five years $ 128.01. A difference
                              that some accountants worry about. There are specific rules how to
                              do interest about a period smaller than the base period (although the
                              rules depend on the situation).
                              Teach me to try to program at 4 am.
                              Yes, that is approximately the time that I normally write my articles.
                              I am a bit early now.
                              i_1000_per_n = i_1000 / 2;
                              i_per_n = i/2.0;
                              And see what I wrote above about this. But otherwise your results are
                              now correct. Although I can not see a guarantee from your floating
                              point formulation that it always will be correct, although off-hand
                              I can not find wrong examples. Ah, I found one. 31 cent initial
                              capital, interest per period 1.6%. The correct method gives zero
                              interest after one period, your double method gives one cent interest.
                              After 200 periods your double precision method gives 849 cents, while
                              with the correct method there has been no accumulation at all. Now
                              that I have this case it is easy to create other cases as well.
                              And I may note that interest percentages are frequently stated in
                              decimals. My account gives an interest of 3.6% if I remember right.
                              I see no clear advantage to using integer or floating
                              point. Yes, both can be optimized, but as calculation
                              speed is unlikely to be the bottleneck, optimization is
                              unlikely to be needed.
                              In the financial world calculation speed frequently *is* the bottleneck.
                              And as for speed, for 1000000 iterations, mine goes in 0.32 seconds,
                              your integer variant in 0.61 seconds and your floating point variant
                              in 0.096 seconds. And the advantage of integer over floating point
                              is that with the first you have a guarantee that the result is correct,
                              while with the second you cannot give that guarantee at all (and I am
                              stating this as a numerical mathematician, which I have been some time).
                              (I do not find the doubling trick to be very natural, and
                              it does not generalize to other forms of rounding)
                              It is not natural. But that is the way you would code when doing
                              fixed point arithmetic. It does generalise to some other forms of
                              rounding (round up, round down), it does not generalise to, e.g.,
                              bankers rounding. But there are other methods that can handle that.
                              --
                              dik t. winter, cwi, kruislaan 413, 1098 sj amsterdam, nederland, +31205924131
                              home: bovenover 215, 1025 jn amsterdam, nederland; http://www.cwi.nl/~dik/

                              Comment

                              • William Hughes

                                Re: converting float to double


                                Dik T. Winter wrote:
                                In article <1167280845.058 848.99960@f1g20 00cwa.googlegro ups.com"William Hughes" <wpihughes@hotm ail.comwrites:
                                Dik T. Winter wrote:
                                ...
                                Note this part of my article:
                                >
                                If the period is 1/2 year, the interest per period is not one half of
                                the year interest.
                                Try to do it over a five year period. A yearly
                                interest rate of .05 gives after five years $ 127.63 and an half-yearly
                                interest rate of .025 gives after five years $ 128.01. A difference
                                that some accountants worry about. There are specific rules how to
                                do interest about a period smaller than the base period (although the
                                rules depend on the situation).
                                >
                                This is irrelevent, unless the rules specified can only be implemented
                                in integer arithmetic.
                                Teach me to try to program at 4 am.
                                >
                                Yes, that is approximately the time that I normally write my articles.
                                I am a bit early now.
                                >
                                i_1000_per_n = i_1000 / 2;
                                i_per_n = i/2.0;
                                >
                                And see what I wrote above about this. But otherwise your results are
                                now correct. Although I can not see a guarantee from your floating
                                point formulation that it always will be correct, although off-hand
                                I can not find wrong examples. Ah, I found one. 31 cent initial
                                capital, interest per period 1.6%. The correct method gives zero
                                interest after one period, your double method gives one cent interest.
                                After 200 periods your double precision method gives 849 cents, while
                                with the correct method there has been no accumulation at all. Now
                                that I have this case it is easy to create other cases as well.
                                And I may note that interest percentages are frequently stated in
                                decimals. My account gives an interest of 3.6% if I remember right.
                                The problem here is that 0.00495 was used instead of the
                                needed 0.004995. I miscounted intitially and did not update this.

                                The floating point calculations are almost
                                exact, the only possible problem occurs at the equality condition.
                                Given principal in hundreths, and interest in thousandths, the
                                minimum spacing is 10 ^-5. Thus, though we could get a true
                                value of 0.00499, we cannot get a true value of 0.004996.
                                Thus if our floating point answer is greater than 0.004995, we know
                                that the true answer was 0.00500 or greater and we need to round
                                up. If the true answers are generated by integer arithmetic, then
                                there must be discrete spacing at some scaling, so we can use
                                sufficiently accurate floating point arithmetic to give "exact"
                                answers.

                                - William Hughes

                                Comment

                                Working...