I want to get a periodic value that moves between 0 and a specified height (in my case that's 40) from the sine curve.
But I am messing something up, because my value goes all the way to 79 instead of the expected 40. What am I doing wrong?
This is my attempt:
#include <math.h>
#define degToRad(angleInDegrees) ((angleInDegrees)*M_PI / 180.0)
int main()
{
int height = 40;
int i = 0;
while (1) {
int value = height + sin(degToRad(i / 2 + 1)) * height;
printf("val = %i\n", value);
i++;
}
return 0;
}
A direct resolution is to divide the wave magnitude by 2 #Eric Postpischil
// int value = height + sin(degToRad(i / 2 + 1)) * height;
int value = height + sin(degToRad(i / 2 + 1)) * height)/2;
and use floating point math in the i/2 division. #bruno
I expect a more acceptable result using rounding rather than truncation (what OP's code does) going from floating point to int.
int value = height + lround(sin(degToRad(i / 2 + 1)) * height)/2);
The amplitude of the curve would then be height / 2 and not height; simply replace
int value = height + sin(degToRad(i / 2 + 1)) * height;
with
int value = height / 2 + sin(degToRad(i / 2 + 1)) * height / 2;
A good way to remember that is that sin x is always in the range [-1, 1].
Related
I'm looking for solution to find the sum of numbers. Input will be given has n in integer and problem is to find Sum of the values of sum(1)+ sum(1+2) + sum(1+2+3) + ... + sum(1+2+..+n). I need a very optimised solution using dynamic programming or any math calculation.
int main()
{
int sum = 0;
int i = 0, n = 6;
for( i = 1; i < n; i++ )
sum = sum + findSumN( i );
printf( "%d",sum );
}
You can often find a formula for series like this by calculating the first few terms and using the results to search the On-Line Encyclopedia of Integer Sequences.
1 = 1
1 + (1+2) = 4
4 + (1+2+3) = 10
10 + (1+2+3+4) = 20
20 + (1+2+3+4+5) = 35
35 + (1+2+3+4+5+6) = 56
The sequence you're trying to calculate (1, 4, 10, 20, 35, 56, ...) is A000292, which has the following formula:
a(n) = n × (n + 1) × (n + 2) / 6
If you play with the number you can find some patterns. Starts with
sum(1 + 2 + 3 ... + N) = ((1 + N) * N) /2
Then there is a relationship between the max number and the value above, that is from 1 the difference step 1/3 everytime the max number increase by 1. So get:
(1 + ((1.0 / 3.0) * (max - 1)))
I am not good enough at math to explain why this pattern occurs. Perhaps someone can explain it in a math way.
The following is my solution, no iteration needed.
int main()
{
int min = 1;
int max = 11254;
double sum = ((min + max) * max / 2) * (1 + ((1.0 / 3.0) * (max - 1)));
printf("%.f", sum);
}
Look at the closed form of sum(n)=1+2+…+n and look up the Pascal's triangle identities. This gives immediately a very fast computation method.
As
binom(k,2) + binom(k,3) = binom(k+1,3)
binom(k,2) = binom(k+1,3) - binom(k,3)
the summation of binom(k+1,2) from k=M to N results in the sum value
binom(N+2,3)-binom(M+1,3)=(N+2)*(N+1)*N/6-(M+1)*M*(M-1)/6
= (N+1-M) * ((N+1)²+(N+1)M+M²-1)/6
Having some trouble optimizing a function that returns the number of neighbors of a cell in a Conway's Game of Life implementation. I'm trying to learn C and just get better at coding. I'm not very good at recognizing potential optimizations, and I've spent a lot of time online reading various methods but it's not really clicking for me yet.
Specifically I'm trying to figure out how to unroll this nested for loop in the most efficient way, but each time I try I just make the runtime longer.
I'm including the function, I don't think any other context is needed. Thanks for any advice you can give!
Here is the code for the countNeighbors() function:
static int countNeighbors(board b, int x, int y)
{
int n = 0;
int x_left = max(0, x-1);
int x_right = min(HEIGHT, x+2);
int y_left = max(0, y-1);
int y_right = min(WIDTH, y+2);
int xx, yy;
for (xx = x_left; xx < x_right; ++xx) {
for (yy = y_left; yy < y_right; ++yy) {
n += b[xx][yy];
}
}
return n - b[x][y];
}
Instead of declaring board as b[WIDTH][HEIGHT] declare it as b[WIDTH + 2][HEIGHT + 2]. This gives an extra margin which will have zeros, but it prevents from index out of bounds. So, instead of:
x x
x x
We will have:
0 0 0 0
0 x x 0
0 x x 0
0 0 0 0
x denotes used cells, 0 will be unused.
Typical trade off: a bit of memory for speed.
Thanks to that we don't have to call min and max functions (which have bad for performance if statements).
Finally, I would write your function like that:
int countNeighborsFast(board b, int x, int y)
{
int n = 0;
n += b[x-1][y-1];
n += b[x][y-1];
n += b[x+1][y-1];
n += b[x-1][y];
n += b[x+1][y];
n += b[x-1][y+1];
n += b[x][y+1];
n += b[x+1][y+1];
return n;
}
Benchmark (updated)
Full, working source code.
Thanks to Jongware comment I added linearization (reducing array's dimensions from 2 to 1) and changing int to char.
I also made the main loop linear and calculate the returned sum directly, without an intermediate n variable.
2D array was 10002 x 10002, 1D had 100040004 elements.
The CPU I have is Pentium Dual-Core T4500 at 2.30 GHz, further details here (output of cat /prof/cpuinfo).
Results on default optimization level O0:
Original: 15.50s
Mine: 10.13s
Linear: 2.51s
LinearAndChars: 2.48s
LinearAndCharsAndLinearLoop: 2.32s
LinearAndCharsAndLinearLoopAndSum: 1.53s
That's about 10x faster compared to the original version.
Results on O2:
Original: 6.42s
Mine: 4.17s
Linear: 0.55s
LinearAndChars: 0.53s
LinearAndCharsAndLinearLoop: 0.42s
LinearAndCharsAndLinearLoopAndSum: 0.44s
About 15x faster.
On O3:
Original: 10.44s
Mine: 1.47s
Linear: 0.26s
LinearAndChars: 0.26s
LinearAndCharsAndLinearLoop: 0.25s
LinearAndCharsAndLinearLoopAndSum: 0.24s
About 44x faster.
The last version, LinearAndCharsAndLinearLoopAndSum is:
typedef char board3[(HEIGHT + 2) * (WIDTH + 2)];
int i;
for (i = WIDTH + 3; i <= (WIDTH + 2) * (HEIGHT + 1) - 2; i++)
countNeighborsLinearAndCharsAndLinearLoopAndSum(b3, i);
int countNeighborsLinearAndCharsAndLinearLoopAndSum(board3 b, int pos)
{
return
b[pos - 1 - (WIDTH + 2)] +
b[pos - (WIDTH + 2)] +
b[pos + 1 - (WIDTH + 2)] +
b[pos - 1] +
b[pos + 1] +
b[pos - 1 + (WIDTH + 2)] +
b[pos + (WIDTH + 2)] +
b[pos + 1 + (WIDTH + 2)];
}
Changing 1 + (WIDTH + 2) to WIDTH + 3 won't help, because compiler takes care of it anyway (even on O0 optimization level).
I've built a good function for rotating bitmaps in degrees.
The problem that occurred after some optimizations is that the output image is getting slightly re-positioned during the rotation.
I've recorded a 360o rotating video for you to see what do I mean.
And the code as follows:
#define OFFSET_OF_ID (0x0)
#define OFFSET_OF_SIZE (0x2)
#define OFFSET_OF_PIXELS (0xA)
#define OFFSET_OF_NDIB (0xE)
#define OFFSET_OF_WIDTH (0x12)
#define OFFSET_OF_HEIGHT (0x16)
#define OFFSET_OF_BPP (0x1C)
#define OFFSET_OF_NRAW (0x22)
typedef unsigned char byte, pixel[3];
typedef unsigned short word;
typedef unsigned long dword;
typedef unsigned long long ddword;
byte*
bmp_rotate
(byte *buffer, float angle)
{
const dword src_width = *( (dword*)&buffer[OFFSET_OF_WIDTH]);
const dword src_height = *( (dword*)&buffer[OFFSET_OF_HEIGHT]);
const dword src_nraw = *( (dword*)&buffer[OFFSET_OF_NRAW]);
const dword src_pixels = *( (dword*)&buffer[OFFSET_OF_PIXELS]);
const dword src_bpp = *( (dword*)&buffer[OFFSET_OF_BPP]);
const dword single = src_bpp / 8;
const dword row = src_width * single;
dword rowsize = (row % 4) ? (row + 4 - row % 4) : (row);
byte *dest = calloc( src_pixels + src_nraw, sizeof(byte) );
double midX, midY;
int i, j;
double sin_angle = sin(angle);
double cos_angle = cos(angle);
midX = src_width / 2.0f;
midY = src_height / 2.0f;
memcpy(dest, buffer, src_pixels);
for(j = 0; j < src_height; j++)
{
dword dest_offset = src_pixels + j * rowsize;
double deltaY = j - midY;
double deltaX = 0 - midX;
double x_computation, y_computation;
x_computation = midX + deltaX * cos_angle + deltaY * sin_angle + 0.5f;
y_computation = midY - deltaX * sin_angle + deltaY * cos_angle + 0.5f;
for(i = 0; i < src_width; i++)
{
ddword rotX = x_computation;
ddword rotY = y_computation;
if(rotX >= 0 && rotX < src_width && rotY >= 0 && rotY < src_height)
{
ddword src_offset = src_pixels + rotY * rowsize + rotX * single;
memcpy(&dest[dest_offset], &buffer[src_offset], sizeof(pixel));
}
x_computation += cos_angle;
y_computation -= sin_angle;
dest_offset += single;
}
}
return dest;
}
What causes this indecent behavior?
I can't really see your problem in the video, but I assume that the full 360° rotation is achieved in various partial rotations.
If we look at a 180° rotation, the offset becomes clear: The sine is 0 and the cosine is −1. The rotated coordinates of the top left corner (0,0) is then:
x' = xm + (x - xm) * cosa + (y - ym) * sina = xm + xm = w
y' = ym - (x - xm) * sina + (y - ym) * cosa = ym + ym = h
The coordinates (w, h) are the exclusive right and bottom borders.
Your working coordinates are real numbers. The integer values describe the left and top coordinates. Converting the (positive) real coords to integers will truncate the fractional part and yield the zero-based pixel indices.
You add 0.5 to your working coordinates in the target space once to enforce proper index calculation. Instead, you should treat the real coordinates of all pixels as the middle of that pixel:
x(i) = i + 0.5
y(j) = j + 0.5
All your calculations remain correct, except:
double deltaY = j + 0.5 - midY;
double deltaX = 0 + 0.5 - midX;
x_computation = midX + deltaX * cos_angle + deltaY * sin_angle;
y_computation = midY - deltaX * sin_angle + deltaY * cos_angle;
The idea is to treat pixel coordinates as pixel centres in both source and target space. The correct representation in target space is achieved automatically by rounding towards zero when convering to integer.
It may be a rounding-related problem. I have also faced this kind of problem in my projects in the past. Please check the lines where "integer to other types" or "other types to integer" conversions occur.
I need a function to animate a sine wave infinitely over time. The sine wave moves to the left.
My sine wave is built using the following equation:
A * sin(B * x + C) + D
Now to animate the sine wave as if it is moving to the left, I simply increase C by 1 everytime I refresh the screen. Now this is all fine and dandy for a few minutes but I need to have that animation run for hours. I can't just have an integer build up 60 times a second forever. How does someone deal with this? Do I just try to find a point where the sine wave crosses 0 and then restart the animation from 0?
I just need to have the logic of something like this explained.
EDIT #1
I forgot to mention that there's a randomized component to my sine. The sine is not continuously the same. A and D are sinusoidal functions tied to that integer at the moment. The sine needs to look random with varying periods and amplitudes.
EDIT #2
Edited see Edit 3
EDIT #3
#Potatoswatter I tried implementing your technique but I don't think I'm getting it. Here's what I got:
static double i = 0;
i = i + (MPI / 2);
if ( i >= 800 * (MPI / 2) ) i -= 800 * (MPI / 2);
for (k = 0; k < 800; ++k)
{
double A1 = 145 * sin((rand1 * (k - 400) + i) / 300) + rand3; // Amplitude
double A2 = 100 * sin((rand2 * (k - 400) + i) / 300) + rand2; // Amplitude
double A3 = 168 * sin((rand3 * (k - 400) + i) / 300) + rand1; // Amplitude
double B1 = 3 + rand1 + (sin((rand3 * k) * i) / (500 * rand1)); // Period
double B2 = 3 + rand2 + (sin((rand2 * k) * i) / 500); // Period
double B3 = 3 + rand3 + (sin((rand1 * k) * i) / (500 * rand3)); // Period
double x = k; // Current x
double C1 = 10 * i; // X axis move
double C2 = 11 * i; // X axis move
double C3 = 12 * i; // X axis move
double D1 = rand1 + sin(rand1 * x / 600) * 4; // Y axis move
double D2 = rand2 + sin(rand2 * x / 500) * 4; // Y axis move
double D3 = rand3 + cos(rand3 * x / 400) * 4; // Y axis move
sine1[k] = (double)A1 * sin((B1 * x + C1) / 400) + D1;
sine2[k] = (double)A2 * sin((B2 * x + C2) / 300) + D2 + 100;
sine3[k] = (double)A3 * cos((B3 * x + C3) / 500) + D3 + 50;
}
How do I modify this to make it work?
Halp!
Sine has a period of 2 pi, meaning that sin(x) = sin(x + 2 * M_PI), for any x.
So, you could just increase C by, say, pi/n where n is any integer, as you refresh the screen, and after 2n refreshes, reset C (to 0, or whatever).
Edit for clarity: the integer n is not meant to change over time.
Instead, pick some n, for example, let's say n = 10. Now, every frame, increase x by pi / 10. After 20 frames, you have increased x by a total of 20 * pi / 10 = 2 * pi. Since sin(x + 2 * pi) = sin(x), you may as well just reset your sin(...) input to just x, and start the process over.
sin is periodic, with a period of 2π. Therefore, if the argument is greater than 2π, you can subtract 2 * M_PI from it and get the same answer.
Instead of using a single variable k to compute all waves of various speeds, use three variables double k1, k2, k3, and keep them bound in the range from 0 to 2π.
if ( k2 >= 2 * M_PI ) k2 -= 2 * M_PI;
They may be individually updated by adding some value each frame. If the increment may be more than 2π then subtracting a single 2π won't bring them back into range, but you can use fmod() instead.
I decided to change my course of action. I just drive i with the system's monotonic clock like so:
struct timespec spec;
int ms;
time_t s;
static unsigned long long etime = 0;
clock_gettime(CLOCK_MONOTONIC, &spec);
s = spec.tv_sec;
ms = spec.tv_nsec / 10000000;
etime = concatenate((long)s, ms);
Then I simply changed i to etime in my sine equations. Here's the concatenating function I used for this purpose:
unsigned concatenate(unsigned x, unsigned y) {
x = x * 100;
return x + y;
}
I would like to evaluate Pi approximately by running the following code which fits a regular polygon of n sides inside a circle with unit diameter and calculates its perimeter using the function in the code. However the output after the 34th term is 0 when long double variable type is used or it increases without bounds when double variable type is used. How can I remedy this situation? Any suggestion or help is appreciated and welcome.
Thanks
P.S: Operating system: Ubuntu 12.04 LTS 32-bit, Compiler: GCC 4.6.3
#include <stdio.h>
#include <math.h>
#include <limits.h>
#include <stdlib.h>
#define increment 0.25
int main()
{
int i = 0, k = 0, n[6] = {3, 6, 12, 24, 48, 96};
double per[61] = {0}, per2[6] = {0};
// Since the above algorithm is recursive we need to specify the perimeter for n = 3;
per[3] = 0.5 * 3 * sqrtl(3);
for(i = 3; i <= 60; i++)
{
per[i + 1] = powl(2, i) * sqrtl(2 * (1.0 - sqrtl(1.0 - (per[i] / powl(2, i)) * (per[i] / powl(2, i)))));
printf("%d %f \n", i, per[i]);
}
return 0;
for(k = 0; k < 6; k++)
{
//p[k] = k
}
}
Some ideas:
Use y = (1.0 - x)*( 1.0 + x) instead of y = 1.0 - x*x. This helps with 1 stage of "subtraction of nearly equal values", but I am still stuck on the next 1.0 - sqrtl(y) as y approaches 1.0.
// per[i + 1] = powl(2, i) * sqrtl(2 * (1.0 - sqrtl(1.0 - (per[i] / powl(2, i)) * (per[i] / powl(2, i)))));
long double p = powl(2, i);
// per[i + 1] = p * sqrtl(2 * (1.0 - sqrtl(1.0 - (per[i] / p) * (per[i] / p))));
long double x = per[i] / p;
// per[i + 1] = p * sqrtl(2 * (1.0 - sqrtl(1.0 - x * x)));
// per[i + 1] = p * sqrtl(2 * (1.0 - sqrtl((1.0 - x)*(1.0 + x)) ));
long double y = (1.0 - x)*( 1.0 + x);
per[i + 1] = p * sqrtl(2 * (1.0 - sqrtl(y) ));
Change array size or for()
double per[61+1] = { 0 }; // Add 1 here
...
for (i = 3; i <= 60; i++) {
...
per[i + 1] =
Following is a similar method for pi
unsigned n = 6;
double sine = 0.5;
double cosine = sqrt(0.75);
double pi = n*sine;
static const double mpi = 3.1415926535897932384626433832795;
do {
sine = sqrt((1 - cosine)/2);
cosine = sqrt((1 + cosine)/2);
n *= 2;
pi = n*sine;
printf("%6u s:%.17e c:%.17e pi:%.17e %%:%.6e\n", n, sine, cosine, pi, (pi-mpi)/mpi);
} while (n <500000);
Subtracting 1.0 from a nearly-1.0 number is leading to "catastrophic cancellation", where the relative error in a FP calculation skyrockets due to the loss of significant digits. Try evaluating pow(2, i) - (pow(2, i) - 1.0) for each i between 0 and 60 and you'll see what I mean.
The only real solution to this issue is reorganizing your equations to avoid subtracting nearly-equal nonzero quantities. For more details, see Acton, Real Computing Made Real, or Higham, Accuracy and Stability of Numerical Algorithms.