float algorithm is slow

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

    float algorithm is slow

    float percentage;

    for (j = 0; j < 10000000; j++)
    {
    percentage = sinf(frequency * j * 2 * 3.14159 / sampleFreq );
    buffer[totalBytes] =ceilf(volume * percentage) + volume;
    totalBytes++;
    }

    Because the float variable, the above loop take 2 seconds in c or c++
    on Linux machine. Does anybody has a solution to reduce the time?

    Thanks,

    Wenfei

  • E. Robert Tisdale

    #2
    Re: float algorithm is slow

    Wenfei wrote:
    [color=blue]
    > float percentage;
    >
    > for (j = 0; j < 10000000; j++) {
    > percentage = sinf(frequency * j * 2 * 3.14159 / sampleFreq );
    > buffer[totalBytes] =ceilf(volume * percentage) + volume;
    > totalBytes++;
    > }
    >
    > Because the float variable, the above loop take 2 seconds in c or c++
    > on Linux machine. Does anybody has a solution to reduce the time?[/color]
    [color=blue]
    > cat main.c[/color]
    #include <stdlib.h>
    #include <math.h>

    int main(int argc, char* argv[]) {

    const
    size_t n = 10000000;
    float buffer[n];
    size_t totalBytes = 0;
    const
    float_t frequency = 1.0;
    const
    float_t sampleFreq = 1.0;
    const
    float_t pi = 3.1415926535897 9323846;
    const
    float_t volume = 1.0;

    for (size_t j = 0; j < n; ++j) {
    float_t percentage = sinf(frequency* j*2*pi/sampleFreq);
    buffer[totalBytes] =ceilf(volume*p ercentage) + volume;
    totalBytes++;
    }

    return 0;
    }
    [color=blue]
    > gcc -Wall -std=c99 -pedantic -O2 -o main main.c -lm
    > time ./main[/color]
    3.694u 0.258s 0:03.92 100.5% 0+0k 0+0io 0pf+0w

    Comment

    • Eric Sosman

      #3
      Re: float algorithm is slow

      Wenfei wrote:[color=blue]
      > float percentage;
      >
      > for (j = 0; j < 10000000; j++)
      > {
      > percentage = sinf(frequency * j * 2 * 3.14159 / sampleFreq );
      > buffer[totalBytes] =ceilf(volume * percentage) + volume;
      > totalBytes++;
      > }
      >
      > Because the float variable, the above loop take 2 seconds in c or c++
      > on Linux machine. Does anybody has a solution to reduce the time?[/color]

      Yes: Change the iteration count from 10000000 to 0, and
      the code will almost certainly run faster.

      In other words, micro-benchmarks of this sort are not
      very informative. What are you really trying to do?

      --
      Eric Sosman
      esosman@acm-dot-org.invalid

      Comment

      • Gordon Burditt

        #4
        Re: float algorithm is slow

        >float percentage;[color=blue]
        >
        >for (j = 0; j < 10000000; j++)
        >{
        > percentage = sinf(frequency * j * 2 * 3.14159 / sampleFreq );
        > buffer[totalBytes] =ceilf(volume * percentage) + volume;
        > totalBytes++;
        >}
        >
        >Because the float variable,[/color]

        My guess is that if you GOT RID OF the float variable, it would
        take about the same time:
        [color=blue]
        >for (j = 0; j < 10000000; j++)[/color]
        {
        buffer[totalBytes] =ceilf(volume * sinf(frequency * j * 2 * 3.14159 / sampleFreq )) + volume;
        totalBytes++;
        }
        [color=blue]
        >the above loop take 2 seconds in c or c++
        >on Linux machine. Does anybody has a solution to reduce the time?[/color]

        You haven't demonstrated why taking two seconds is a problem yet.
        Cut down the number of iterations? Get a faster machine?
        Doing the calculation in double might make it faster (although on
        Intel *86 it probably won't).

        Gordon L. Burditt

        Comment

        • Anonymous 7843

          #5
          Re: float algorithm is slow

          In article <1120589218.015 773.173960@g14g 2000cwa.googleg roups.com>,
          Wenfei <ye_wenfei@hotm ail.com> wrote:[color=blue]
          >
          >
          > float percentage;
          >
          > for (j = 0; j < 10000000; j++)
          > {
          > percentage = sinf(frequency * j * 2 * 3.14159 / sampleFreq );
          > buffer[totalBytes] =ceilf(volume * percentage) + volume;
          > totalBytes++;
          > }
          >
          > Because the float variable, the above loop take 2 seconds in c or c++
          > on Linux machine. Does anybody has a solution to reduce the time?[/color]

          * Use a small table of sine values instead of sinf() function.
          It appears that you're downsampling to the width of a char
          anyway, so table of somewhat more than 256 sine values probably
          won't make things much worse.

          * Or just map out one complete waveform and just repeatedly copy that
          throughout the rest of the buffer.

          * Or Just make one copy of the waveform and index into that as
          appropriate when you need the results.
          --
          7842++

          Comment

          • Robert Gamble

            #6
            Re: float algorithm is slow

            Wenfei wrote:[color=blue]
            > float percentage;
            >
            > for (j = 0; j < 10000000; j++)
            > {
            > percentage = sinf(frequency * j * 2 * 3.14159 / sampleFreq );
            > buffer[totalBytes] =ceilf(volume * percentage) + volume;
            > totalBytes++;
            > }
            >
            > Because the float variable, the above loop take 2 seconds in c or c++
            > on Linux machine. Does anybody has a solution to reduce the time?[/color]

            <OT>
            It is unlikely that using double will be any faster.

            On my system, 66% of the time is spent in the first statement inside
            the loop, 27% on the second. The sinf and ceilf function calls are by
            far the most intensive parts of these statements. If your system is
            similiar, you might try replacing the sinf call with a lookup table of
            precalculated values with a tradeoff of accuracy and memory usage. You
            could also use a macro of inline function in place of ceilf.

            You didn't specify how much faster you need it, what tradeoffs are
            feasible, what you have tried already, or even what exactly you are
            trying to accomplish. Perhaps the algorithm itself could be improved
            but it is difficult to attempt to do so without knowing what the
            specifications are.
            </OT>

            Robert Gamble

            Comment

            • Erik de Castro Lopo

              #7
              Re: float algorithm is slow

              Wenfei wrote:[color=blue]
              >
              > float percentage;
              >
              > for (j = 0; j < 10000000; j++)
              > {
              > percentage = sinf(frequency * j * 2 * 3.14159 / sampleFreq );
              > buffer[totalBytes] =ceilf(volume * percentage) + volume;
              > totalBytes++;
              > }
              >
              > Because the float variable, the above loop take 2 seconds in c or c++
              > on Linux machine. Does anybody has a solution to reduce the time?[/color]

              I assume your linux machine has an x86 based processor. If thats the
              case then you problem is probably the ceilf() function. The implementation
              of that function requires that the FPU's control word to be modified at
              the start of ceilf() and restored afterwards. Every time the FPU control
              word is modified, it causes a stall in the FPU pipeline.

              You might try replacing ceilf() with the C99 function lrintf().
              Unfortunately lrintf() is a round function, not a ceil function so you
              might need to replace

              ceilf (x)

              with

              lrintf (x + 0.5).


              Also have a look at this paper:



              Erik
              --
              +-----------------------------------------------------------+
              Erik de Castro Lopo nospam@mega-nerd.com (Yes it's valid)
              +-----------------------------------------------------------+
              "It has been discovered that C++ provides a remarkable facility
              for concealing the trival details of a program -- such as where
              its bugs are." -- David Keppel

              Comment

              • Anonymous 7843

                #8
                Re: float algorithm is slow

                In article <1120589218.015 773.173960@g14g 2000cwa.googleg roups.com>,
                Wenfei <ye_wenfei@hotm ail.com> wrote:[color=blue]
                >
                > buffer[totalBytes] =ceilf(volume * percentage) + volume;[/color]

                Sorry for posting twice to the same thread, but ceilf() may not be
                strictly really necessary. If buffer is an array of some kind of
                integer type then the assignment is going to do a conversion from float
                to int anyway. Unless you have some mathematically rigorous standard
                to uphold, you might get a "close enough" result by rounding up. E.g.

                buffer[totalBytes] = (volume * percentage + 0.5) + volume;
                --
                7842++

                Comment

                • Christian Bau

                  #9
                  Re: float algorithm is slow

                  In article <1120589218.015 773.173960@g14g 2000cwa.googleg roups.com>,
                  "Wenfei" <ye_wenfei@hotm ail.com> wrote:
                  [color=blue]
                  > float percentage;
                  >
                  > for (j = 0; j < 10000000; j++)
                  > {
                  > percentage = sinf(frequency * j * 2 * 3.14159 / sampleFreq );
                  > buffer[totalBytes] =ceilf(volume * percentage) + volume;
                  > totalBytes++;
                  > }
                  >
                  > Because the float variable, the above loop take 2 seconds in c or c++
                  > on Linux machine. Does anybody has a solution to reduce the time?[/color]

                  I wouldn't worry about the speed, because your results are garbage
                  anyway.

                  When j has the maximum value 1e7 - 1, what is the difference between j *
                  2 * 3.14159 and j * 2 * pi?

                  Once you've fixed this, just a hint (mathematics is fun): Consecutive
                  terms of any function of the form

                  f (n) = a * sin (x * n + b) + c * cos (x * n + d)

                  can be calculated using one single multiplication and one single
                  addition.

                  Comment

                  • Lawrence Kirby

                    #10
                    Re: float algorithm is slow

                    On Tue, 05 Jul 2005 22:57:23 +0100, Christian Bau wrote:

                    ....
                    [color=blue]
                    > Once you've fixed this, just a hint (mathematics is fun): Consecutive
                    > terms of any function of the form
                    >
                    > f (n) = a * sin (x * n + b) + c * cos (x * n + d)
                    >
                    > can be calculated using one single multiplication and one single
                    > addition.[/color]

                    But you need to be careful about accumulation of errors.

                    Lawrence



                    Comment

                    • Lawrence Kirby

                      #11
                      Re: float algorithm is slow

                      On Tue, 05 Jul 2005 21:15:21 +0000, Anonymous 7843 wrote:
                      [color=blue]
                      > In article <1120589218.015 773.173960@g14g 2000cwa.googleg roups.com>,
                      > Wenfei <ye_wenfei@hotm ail.com> wrote:[color=green]
                      >>
                      >>
                      >> float percentage;
                      >>
                      >> for (j = 0; j < 10000000; j++)
                      >> {
                      >> percentage = sinf(frequency * j * 2 * 3.14159 / sampleFreq );[/color][/color]

                      You may gain a little by precalculating the loop invariant
                      frequency * 2 * 3.14159 / sampleFreq outside the loop.
                      [color=blue][color=green]
                      >> buffer[totalBytes] =ceilf(volume * percentage) + volume;
                      >> totalBytes++;
                      >> }
                      >>
                      >> Because the float variable, the above loop take 2 seconds in c or c++
                      >> on Linux machine. Does anybody has a solution to reduce the time?[/color]
                      >
                      > * Use a small table of sine values instead of sinf() function.
                      > It appears that you're downsampling to the width of a char
                      > anyway, so table of somewhat more than 256 sine values probably
                      > won't make things much worse.[/color]

                      On of the problems is that the type of buffer is not specified
                      [color=blue]
                      > * Or just map out one complete waveform and just repeatedly copy that
                      > throughout the rest of the buffer.
                      >
                      > * Or Just make one copy of the waveform and index into that as
                      > appropriate when you need the results.[/color]

                      These only work if the cycle length corresponds to an integral number of
                      positions in buffer. There's nothing to suggest that this is the case.

                      Lawrence


                      Comment

                      • Anonymous 7843

                        #12
                        Re: float algorithm is slow

                        In article <pan.2005.07.06 .11.32.32.98500 0@netactive.co. uk>,
                        Lawrence Kirby <lknews@netacti ve.co.uk> wrote:[color=blue]
                        >
                        > On Tue, 05 Jul 2005 21:15:21 +0000, Anonymous 7843 wrote:
                        >[color=green]
                        > > In article <1120589218.015 773.173960@g14g 2000cwa.googleg roups.com>,
                        > > Wenfei <ye_wenfei@hotm ail.com> wrote:[color=darkred]
                        > >>
                        > >> percentage = sinf(frequency * j * 2 * 3.14159 / sampleFreq );[/color][/color]
                        >[color=green]
                        > > * Or Just make one copy of the waveform and index into that as
                        > > appropriate when you need the results.[/color]
                        >
                        > These only work if the cycle length corresponds to an integral number of
                        > positions in buffer. There's nothing to suggest that this is the case.[/color]

                        Given the choice to use float, round pi off at the 6th digit and the
                        (likely) stuffing of results into a char it didn't seem like fidelity
                        was foremost.

                        One hopes that this project was just the first exercise in a DSP course
                        and that our intrepid correspondent Wenfei soon outlearns us.
                        --
                        7842++

                        Comment

                        • Wenfei

                          #13
                          Re: float algorithm is slow

                          I am converting Notes format to PCM format to play sounds on the ceil
                          phone. It is Linux os and it is not FPU, so it is slow.

                          But finally, I used a sinf lookup table, and the sound can be played
                          instantly.

                          Thanks for all your guys idea.

                          Wenfei

                          Comment

                          • websnarf@gmail.com

                            #14
                            Re: float algorithm is slow

                            Wenfei wrote:[color=blue]
                            > float percentage;
                            > for (j = 0; j < 10000000; j++) {
                            > percentage = sinf(frequency * j * 2 * 3.14159 / sampleFreq );
                            > buffer[totalBytes] =ceilf(volume * percentage) + volume;
                            > totalBytes++;
                            > }[/color]

                            sinf() appears to be a Microsoft VC++ extension that computes sin() but
                            uses only 32-bit floats. Interesting that the zealots in this
                            newsgroup didn't call you on that.

                            Ok, anyhow remembering our trigonometry:

                            sin(a + b) = sin(a)*cos(b) + sin(b)cos(a)
                            cos(a + b) = cos(a)*cos(b) - sin(b)sin(a)

                            Now we can strength reduce the argument to sinf:

                            arg += (freqency*2*3.1 4159/sampleFreq);

                            But that value is a constant:

                            arg += deltaAngle; /* deltaAngle is precomputed as:
                            freqency*2*3.14 159/sampleFreq */

                            So we can simplify this to:

                            s1 = percentage*cos( deltaAngle) + c*sin(deltaAngl e);
                            c = c*cos(deltaAngl e) + percentage*sin( deltaAngle);
                            percentage = s1;

                            And of course we can replace the cos(deltaAngle) and sin(deltaAngle)
                            with some precomputed values, and we initialize c to 1, and percentage
                            to 0.

                            This removes all the trigonometric functions altogether.

                            The problem is that it will have "accumulati ng accuracy" problems.
                            These problems are not trivial, because you will lose the sin^2+cos^2=1
                            property, which will start scaling your results (either upward or
                            downward) globally, which could get bad.

                            A simple way to mitigate this is to split the loop into groups of, say,
                            100 or 1000 at a time, and reset the parameters with their true
                            mathematical value with the raw sin/cos functions:

                            percentage = sinf (frequency * j * 2 * 3.14159 / sampleFreq);
                            c = cosf (frequency * j * 2 * 3.14159 / sampleFreq);
                            [color=blue]
                            > Because the float variable, the above loop take 2 seconds in c or c++
                            > on Linux machine. Does anybody has a solution to reduce the time?[/color]

                            This takes time because you are calling sinf(), not because its
                            floating point.

                            --
                            Paul Hsieh
                            Pobox has been discontinued as a separate service, and all existing customers moved to the Fastmail platform.



                            Comment

                            • CBFalconer

                              #15
                              Re: float algorithm is slow

                              websnarf@gmail. com wrote:[color=blue]
                              > Wenfei wrote:
                              >[color=green]
                              >> float percentage;
                              >> for (j = 0; j < 10000000; j++) {
                              >> percentage = sinf(frequency * j * 2 * 3.14159 / sampleFreq );
                              >> buffer[totalBytes] =ceilf(volume * percentage) + volume;
                              >> totalBytes++;
                              >> }[/color]
                              >
                              > sinf() appears to be a Microsoft VC++ extension that computes
                              > sin() but uses only 32-bit floats. Interesting that the zealots
                              > in this newsgroup didn't call you on that.[/color]

                              The usage is proper. The foolish comment is not. From N869:

                              7.12.4.6 The sin functions

                              Synopsis

                              [#1]
                              #include <math.h>
                              double sin(double x);
                              float sinf(float x);
                              long double sinl(long double x);

                              Description

                              [#2] The sin functions compute the sine of x (measured in
                              radians).

                              Returns

                              [#3] The sin functions return the sine value.

                              --
                              "If you want to post a followup via groups.google.c om, don't use
                              the broken "Reply" link at the bottom of the article. Click on
                              "show options" at the top of the article, then click on the
                              "Reply" at the bottom of the article headers." - Keith Thompson


                              Comment

                              Working...