Related
#include <stdio.h>
#include <math.h>
const int TERMS = 7;
const float PI = 3.14159265358979;
int fact(int n) {
return n<= 0 ? 1 : n * fact(n-1);
}
double sine(int x) {
double rad = x * (PI / 180);
double sin = 0;
int n;
for(n = 0; n < TERMS; n++) { // That's Taylor series!!
sin += pow(-1, n) * pow(rad, (2 * n) + 1)/ fact((2 * n) + 1);
}
return sin;
}
double cosine(int x) {
double rad = x * (PI / 180);
double cos = 0;
int n;
for(n = 0; n < TERMS; n++) { // That's also Taylor series!
cos += pow(-1, n) * pow(rad, 2 * n) / fact(2 * n);
}
return cos;
}
int main(void){
int y;
scanf("%d",&y);
printf("sine(%d)= %lf\n",y, sine(y));
printf("cosine(%d)= %lf\n",y, cosine(y));
return 0;
}
The code above was implemented to compute sine and cosine using Taylor series.
I tried testing the code and it works fine for sine(120).
I am getting wrong answers for sine(240) and sine(300).
Can anyone help me find out why those errors occur?
You should calculate the functions in the first quadrant only [0, pi/2). Exploit the properties of the functions to get the values for other angles. For instance, for values of x between [pi/2, pi), sin(x) can be calculated by sin(pi - x).
The sine of 120 degrees, which is 40 past 90 degrees, is the same as 50 degrees: 40 degrees before 90. Sine starts at 0, then rises toward 1 at 90 degrees, and then falls again in a mirror image to zero at 180.
The negative sine values from pi to 2pi are just -sin(x - pi). I'd handle everything by this recursive definition:
sin(x):
cases x of:
[0, pi/2) -> calculate (Taylor or whatever)
[pi/2, pi) -> sin(pi - x)
[pi/2, 2pi) -> -sin(x - pi)
< 0 -> sin(-x)
>= 2pi -> sin(fmod(x, 2pi)) // floating-point remainder
A similar approach for cos, using identity cases appropriate for it.
The key point is:
TERMS is too small to have proper precision. And if you increase TERMS, you have to change fact implementation as it will likely overflow when working with int.
I would use a sign to toggle the -1 power instead of pow(-1,n) overkill.
Then use double for the value of PI to avoid losing too many decimals
Then for high values, you should increase the number of terms (this is the main issue). using long long for your factorial method or you get overflow. I set 10 and get proper results:
#include <stdio.h>
#include <math.h>
const int TERMS = 10;
const double PI = 3.14159265358979;
long long fact(int n) {
return n<= 0 ? 1 : n * fact(n-1);
}
double powd(double x,int n) {
return n<= 0 ? 1 : x * powd(x,n-1);
}
double sine(int x) {
double rad = x * (PI / 180);
double sin = 0;
int n;
int sign = 1;
for(n = 0; n < TERMS; n++) { // That's Taylor series!!
sin += sign * powd(rad, (2 * n) + 1)/ fact((2 * n) + 1);
sign = -sign;
}
return sin;
}
double cosine(int x) {
double rad = x * (PI / 180);
double cos = 0;
int n;
int sign = 1;
for(n = 0; n < TERMS; n++) { // That's also Taylor series!
cos += sign * powd(rad, 2 * n) / fact(2 * n);
sign = -sign;
}
return cos;
}
int main(void){
int y;
scanf("%d",&y);
printf("sine(%d)= %lf\n",y, sine(y));
printf("cosine(%d)= %lf\n",y, cosine(y));
return 0;
}
result:
240
sine(240)= -0.866026
cosine(240)= -0.500001
Notes:
my recusive implementation of pow using successive multiplications is probably not needed, since we're dealing with floating point. It introduces accumulation error if n is big.
fact could be using floating point to allow bigger numbers and better precision. Actually I suggested long long but it would be better not to assume that the size will be enough. Better use standard type like int64_t for that.
fact and pow results could be pre-computed/hardcoded as well. This would save computation time.
const double TERMS = 14;
const double PI = 3.14159265358979;
double fact(double n) {return n <= 0.0 ? 1 : n * fact(n - 1);}
double sine(double x)
{
double rad = x * (PI / 180);
rad = fmod(rad, 2 * PI);
double sin = 0;
for (double n = 0; n < TERMS; n++)
sin += pow(-1, n) * pow(rad, (2 * n) + 1) / fact((2 * n) + 1);
return sin;
}
double cosine(double x)
{
double rad = x * (PI / 180);
rad = fmod(rad,2*PI);
double cos = 0;
for (double n = 0; n < TERMS; n++)
cos += pow(-1, n) * pow(rad, 2 * n) / fact(2 * n);
return cos;
}
int main()
{
printf("sine(240)= %lf\n", sine(240));
printf("cosine(300)= %lf\n",cosine(300));
}
I am trying my attempt at Perlin Noise (3-dimensional) as outlined in this document: http://lodev.org/cgtutor/randomnoise.html
However, this is what I'm getting.
It looks like the smoothing isn't working. You can see blocks the size of the 'size' parameter. Can someone point out what I'm doing wrong?
Here's my code:
%ffp
ctl(1):standard,"Size",range=(1,256), pos=(300,20), size=(120,*),val=64,track, action=preview
onFilterStart:
{
allocArray(9,64,64,64,4); // Array for noise depth
for(int z = 0; z < 64; z++)
for(int y = 0; y < 64; y++)
for(int x = 0; x < 64; x++) {
fputArray(9,x,y,z,(float)(rand() % 32768) / 32768.0);
}
return false;
}
forEveryTile:
{
double fractX,fractY,fractZ,xx,yy,zz;
int x1,y1,z1,x2,y2,z2,col;
double value = 0.0, value2 = 0.0, size, isize=(float)ctl(1);
// int X=screen Width, int Y=screen Height
for(int y = 0; y < Y; y++) {
for(int x = 0; x < X; x++) {
//for(int z = 0; z < 64; z++) {
value2 = 0.0;
size = isize;
while (size >=1.0) {
xx=(float)x/size;
yy=(float)y/size;
zz=(float)clock()/size;
fractX = xx - (int)(xx);
fractY = yy - (int)(yy);
fractZ = zz - (int)(zz);
x1 = ((int)(xx) + 64) % 64;
y1 = ((int)(yy) + 64) % 64;
z1 = ((int)(zz) + 64) % 64;
x2 = (x1 + 64- 1) % 64;
y2 = (y1 + 64- 1) % 64;
z2 = (z1 + 64- 1) % 64;
value=0.0;
value += fractX * fractY * fractZ * fgetArray(9,z1,y1,x1);
value += fractX * (1 - fractY) * fractZ * fgetArray(9,z1,y2,x1);
value += (1 - fractX) * fractY * fractZ * fgetArray(9,z1,y1,x2);
value += (1 - fractX) * (1 - fractY) * fractZ * fgetArray(9,z1,y2,x2);
value += fractX * fractY * (1 - fractZ) * fgetArray(9,z2,y1,x1);
value += fractX * (1 - fractY) * (1 - fractZ) * fgetArray(9,z2,y2,x1);
value += (1 - fractX) * fractY * (1 - fractZ) * fgetArray(9,z2,y1,x2);
value += (1 - fractX) * (1 - fractY) * (1 - fractZ) * fgetArray(9,z2,y2,x2);
value2 += value*size;
size /= 2.0;
}
col=(int)((float)(128.0 * value2 / isize));
col=max(min(col,255),0);
psetp(x,y,RGB(col,col,col));
//} //z
} //x
} //y
return true;
}
Your code is kind of hard to read as written.
For Perlin noise start out with a integer noise function, that behaves like a hash.
float noise(int x, int y, int z) { return hash(x+y*5+z*7); }
or
float noise(int x, int y, int z) { return array[x%w+y%h*w+z%d*w*h]; }
Those are just examples. The important part is that noise(x,y,z) = noise(x,y,z). The noise function has to return the same value for the same parameters every time.
There is a problem though: The noise function only takes integer parameters! But we would like to sample it at float values.
float noisesample (float x, float y, float z) { ... }
The easiest way to to that is using linear filtering. Any positive float value is between (int)pos and ((int)pos)+1. At sub-position pos-(int)pos. This gets us:
float Lerp(float a, float b, float f) { return a+(b-a)*f; }
Where f is the sub-position in the [0..1] range and a,b are the values to the left and right. If f is 0, Lerp returns a, if it is 1, it returns b. In between it does linear interpolation.
So use this for a simple 1D noisesample function:
float noisesample(float x) { return Lerp(noise((int)x), noise((int)x+1), fract(x) }
with
float fract(float x) { return x-(int)x; }
I am using (int)x liberally here, it is the same as floor(x) if x is positive.
To go from a single parameter noisesample to x,y is easy: Do the Lerp twice for x at y and y+1, and Lerp between those:
float noisesample(float x, float y) {
float y0 = Lerp(noise((int)x,(int)y), noise((int)x+1,(int)y), fract(x) }
float y1 = Lerp(noise((int)x,(int)y+1), noise((int)x+1,(int)y+1), fract(x) }
return Lerp ( y0, y1, fract(y) );
}
First interpolate x, twice, then interpolate between the results in y. In total we sample noise() 4 times. I leave it as an exercise how to write noisesample ( float x, float y, float z). It will sample noise() eight times and call Lerp 7 times.
All that got us is that we can sample noise (somewhat smooth - there are smoother ways!) at float coordinates. And that is what we need to make perlin noise!
float perlin(float x, float y, float z, int oc=4) {
// maybe: x = x*2^oc, y, z...
float r = 0;
float s = 1;
for ( int i=0; i<oc; i++ ) {
r += noisesample(x,y,z) * s;
s/=2.0f; // to taste
x/=2.0f;
y/=2.0f;
z/=2.0f;
}
return r;
}
The key idea is to understand sampling. It's just a combination of sampling a simple integer noise function.
I have a 2D plane in three dimensions: x+y+z=1, and I want to generate random points(x,y,z) on the plane. How can I choose these points so that they are distributed uniformly?
The Problem
As mentioned in the comments, the question was under specified. Despite that it's a interesting question. Because no distribution was given I just picked one. Here is the more precise(?)/general(?) question I will answer:
Suppose I have a plane P in R^3 defined by ax + by + cz = d.
Let c be in the point on P closest to the origin.
How can I uniformly choose a point on P within some radius r of c?
The Algorithm
Let n = (a,b,c). n is the vector normal to P.
direction
Generate any non-zero vector on the plane ax + by + cz = d, call it w. You can do this by taking the cross product of n with any non-zero vector not parallel to n.
Rotate w around n by a random angle in [0,2pi). You can do this using http://en.wikipedia.org/wiki/Rodrigues%27_rotation_formula.
so , now you got direction by normalizing it
direction = direction / direction.magnitude
origin of the ray
If d is 0, we're done. Otherwise:
Calculate c = distance of plane from Vector3(0 , 0 , 0)
according to http://en.wikipedia.org/wiki/Distance_from_a_point_to_a_plane.
Translate Origin of ray
origin of the ray = vector3.zero + c * ( n )
scale = random.range(min , max)
So the point is
origin_of_the_ray + scale * (direction_)
The Code
Here is my C implementation of the algorithm. I wrote all the vector machinery from scratch so it's a little messy. I have not tested this throughly.
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <math.h>
typedef struct {
double x, y, z;
} vec3;
vec3 vec(double x, double y, double z);
vec3 crossp(vec3 u, vec3 v);
vec3 add(vec3 u, vec3 v);
double dotp(vec3 u, vec3 v);
double norm2(vec3 u);
double norm(vec3 u);
vec3 scale(vec3 u, double s);
vec3 normalize(vec3 u);
void print_vec3(vec3 u);
// generates a random point on the plane ax + by + cz = d
vec3 random_on_plane(double r, double a, double b, double c, double d) {
// The normal vector for the plane
vec3 n = vec(a, b, c);
// create a normal vector on the plane ax + by + cz = 0
// we take any vector not parallel to n
// and find the cross product
vec3 w;
if (n.x == 0)
w = crossp(n, vec(1,0,0));
else
w = crossp(n, vec(0,0,1));
// rotate the vector around n by a random angle
// using Rodrigues' rotation formula
// http://en.wikipedia.org/wiki/Rodrigues%27_rotation_formula
double theta = ((double)rand() / RAND_MAX) * M_PI;
vec3 k = normalize(n);
w = add(scale(w, cos(theta)),
scale(crossp(k, w), sin(theta)));
// Scale the vector fill our disk.
// If the radius is zero, generate unit vectors
if (r == 0) {
w = scale(w, r/norm(w));
} else {
double rand_r = ((double)rand() / RAND_MAX) * r;
w = scale(w, rand_r/norm(w));
}
// now translate the vector from ax + by + cz = 0
// to the plane ax + by + cz = d
// http://en.wikipedia.org/wiki/Distance_from_a_point_to_a_plane
if (d != 0) {
vec3 t = scale(n, d / norm2(n));
w = add(w, t);
}
return w;
}
int main(void) {
int i;
srand(time(NULL));
for (i = 0; i < 100; i++) {
vec3 r = random_on_plane(10, 1, 1, 1, 1);
printf("random v = ");
print_vec3(r);
printf("sum = %f, norm = %f\n", r.x + r.y + r.z, norm(r));
}
}
vec3 vec(double x, double y, double z) {
vec3 u;
u.x = x;
u.y = y;
u.z = z;
return u;
}
vec3 crossp(vec3 u, vec3 v) {
vec3 w;
w.x = (u.y * v.z) - (u.z * v.y);
w.y = (u.z * v.x) - (u.x * v.z);
w.z = (u.x * v.y) - (u.y * v.x);
return w;
}
double dotp(vec3 u, vec3 v) {
return (u.x * v.x) + (u.y * v.y) + (u.z * v.z);
}
double norm2(vec3 u) {
return dotp(u, u);
}
double norm(vec3 u) {
return sqrt(norm2(u));
}
vec3 scale(vec3 u, double s) {
u.x *= s;
u.y *= s;
u.z *= s;
return u;
}
vec3 add(vec3 u, vec3 v) {
u.x += v.x;
u.y += v.y;
u.z += v.z;
return u;
}
vec3 normalize(vec3 u) {
return scale(u, 1/norm(u));
}
void print_vec3(vec3 u) {
printf("%f %f %f\n", u.x, u.y, u.z);
}
Eugene had it almost right: generate two random numbers on the interval [0,1), call them A, B. Then x = min(A,B), y = max(A,B) - x, z = 1 - (x + y). Basically, you pick two points on the line [0,1) and your three coordinates are the three intervals defined by those two points.
I'll first give you a simple algorithm
x = rand()
y = rand()
z = 1 - x - y
Now lets see an implementation of that algorithm
This code will produce any sort of numbers ( +ve or -ve )
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main()
{
srand(time(NULL));
int x= ( rand() - rand() ) ;
int y= ( rand() - rand() ) ;
int z=1-x-y;
printf("x=%d y=%d z=%d",x,y,z);
}
just use srand() to seed the random number generator, and use rand() to assign a random number.
If you need to create random numbers with a range, then use rand() % ( maxnumber + 1 ) where maxnumber is the maximum value you want.
If you want all of your numbers to be positive, then try this
int main()
{
srand(time(NULL));
int x, y , z = -1;
while ( z < 0 )
{
x = rand() ;
y = rand() ;
z = 1 - (x + y );
}
printf("x=%d y=%d z=%d",x,y,z);
}
WARNING
the above code might take some time to execute, so don't expect an instant result
int main ()
{
int n = 0;
int base = 0;
while(n < 10)
{
int x = 2;
int answer = power(x, n);
float neganswer = negpower(x, n);
printf("%d %d %f\n", base, answer, neganswer);
base++;
n++;
}
return EXIT_SUCCESS;
}
int power(int base, int power)
{
int result, i;
result = 1;
for (i=0; i < power; i++)
{
result *= base;
}
return result;
}
int negpower(int base, int power)
{
float result, i;
result = 1.0;
for (i=0; i < power; i++)
{
result = result / base;
}
return result;
}
So I'm trying to call upon this function that i've made, and I think its calculating it correctly, however it is only outputting 1.0000000 followed directly by 0.0000000. I think I've got problems with carrying the float value, can anyone chime in?
Thanks
This is because you are returning a float from negpower() which has return type of int and assigning it to a float neganswer.
Change
int negpower(int base, int power)
to
float negpower(int base, int power)
Output:
Side note:
Always add required header files.
A prototype should be declared if a function definition appears after the main().
The answer is much simpler. Your negpower function returns an int, when you actually return a float from it. Change the prototype and it should work alright.
This is optimized library if you are interested:
#ifdef DOCUMENTATION
title pow x raised to power y
index x raised to power y
usage
.s
double x, y, f, pow();
.br
f = pow(x, y);
.s
description
.s
Returns value of x raised to power y
.s
diagnostics
.s
There are three error possible error messages from this function.
.s
If the x argument is negative the message 'pow arg negative',
followed by the value of x, is written to stderr. The value
of pow for |x| is returned.
.s
If x = 0.0 and y <= 0.0 or if result overflows the message 'pow
overflow', followed by the value of y, is written to stderr.
The value of HUGE is returned.
.s
If the result underflows and if warnings are enabled (normally not),
the message 'pow underflow', followed by the value of y, is written
to stderr. The value of 0 is returned.
.s
The suggestion of Cody and Waite, that the domain be reduced to
simplify the overflow test, has been adopted, consequently overflow
is reported if the result would exceed HUGE * 2**(-1/16).
2**(-1/16) is approximately 0.9576.
.s
internal
.s
Algorithm from Cody and Waite pp. 84-124. This algorithm required
two auxiliary programs POWGA1 and POWGA2 to calculate, respectively,
the arrays a1[] and a2[] used to represent the powers of 2**(-1/16)
to more than machine precision.
The source code for these programs are in the files POWGA1.AUX and
POWGA2.AUX. The octal table on page 98 of Cody and Waite is in the
file POWOCT.DAT which is required on stdin by POWGA2.
.s
author
.s
Hamish Ross.
.s
date
.s
27-Jan-85
#endif
#include <math.h>
#define MAXEXP 2031 /* (MAX_EXP * 16) - 1 */
#define MINEXP -2047 /* (MIN_EXP * 16) - 1 */
static double a1[] = {
1.0,
0.95760328069857365,
0.91700404320467123,
0.87812608018664974,
0.84089641525371454,
0.80524516597462716,
0.77110541270397041,
0.73841307296974966,
0.70710678118654752,
0.67712777346844637,
0.64841977732550483,
0.62092890603674203,
0.59460355750136054,
0.56939431737834583,
0.54525386633262883,
0.52213689121370692,
0.50000000000000000
};
static double a2[] = {
0.24114209503420288E-17,
0.92291566937243079E-18,
-0.15241915231122319E-17,
-0.35421849765286817E-17,
-0.31286215245415074E-17,
-0.44654376565694490E-17,
0.29306999570789681E-17,
0.11260851040933474E-17
};
static double p1 = 0.833333333333332114e-1;
static double p2 = 0.125000000005037992e-1;
static double p3 = 0.223214212859242590e-2;
static double p4 = 0.434457756721631196e-3;
static double q1 = 0.693147180559945296e0;
static double q2 = 0.240226506959095371e0;
static double q3 = 0.555041086640855953e-1;
static double q4 = 0.961812905951724170e-2;
static double q5 = 0.133335413135857847e-2;
static double q6 = 0.154002904409897646e-3;
static double q7 = 0.149288526805956082e-4;
static double k = 0.442695040888963407;
double pow(x, y)
double x, y;
{
double frexp(), g, ldexp(), r, u1, u2, v, w, w1, w2, y1, y2, z;
int iw1, m, p;
if (y == 0.0)
return(1.0);
if (x <= 0.0) {
if (x == 0.0) {
if (y > 0.0)
return(x);
cmemsg(FP_POWO, &y);
return(HUGE);
}
else {
cmemsg(FP_POWN, &x);
x = -x;
}
}
g = frexp(x, &m);
p = 0;
if (g <= a1[8])
p = 8;
if (g <= a1[p + 4])
p += 4;
if (g <= a1[p + 2])
p += 2;
p++;
z = ((g - a1[p]) - a2[p / 2]) / (g + a1[p]);
z += z;
v = z * z;
r = (((p4 * v + p3) * v + p2) * v + p1) * v * z;
r += k * r;
u2 = (r + z * k) + z;
u1 = 0.0625 * (double)(16 * m - p);
y1 = 0.0625 * (double)((int)(16.0 * y));
y2 = y - y1;
w = u2 * y + u1 * y2;
w1 = 0.0625 * (double)((int)(16.0 * w));
w2 = w - w1;
w = w1 + u1 * y1;
w1 = 0.0625 * (double)((int)(16.0 * w));
w2 += (w - w1);
w = 0.0625 * (double)((int)(16.0 * w2));
iw1 = 16.0 * (w1 + w);
w2 -= w;
while (w2 > 0.0) {
iw1++;
w2 -= 0.0625;
}
if (iw1 > MAXEXP) {
cmemsg(FP_POWO, &y);
return(HUGE);
}
if (iw1 < MINEXP) {
cmemsg(FP_POWU, &y);
return(0.0);
}
m = iw1 / 16;
if (iw1 >= 0)
m++;
p = 16 * m - iw1;
z = ((((((q7*w2 + q6)*w2 + q5)*w2 + q4)*w2 + q3)*w2 + q2)*w2 + q1)*w2;
z = a1[p] + a1[p] * z;
return(ldexp(z, m));
}
You have all sorts of ints in there. When you do that, the decimal gets truncated. You should make your power functions return floats, and use a float base.
I am trying to generate an array of n points that are equidistant from each other and lie on a circle in C. Basically, I need to be able to pass a function the number of points that I would like to generate and get back an array of points.
It's been a really long time since I've done C/C++, so I've had a stab at this more to see how I got on with it, but here's some code that will calculate the points for you. (It's a VS2010 console application)
// CirclePoints.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "stdio.h"
#include "math.h"
int _tmain()
{
int points = 8;
double radius = 100;
double step = ((3.14159265 * 2) / points);
double x, y, current = 0;
for (int i = 0; i < points; i++)
{
x = sin(current) * radius;
y = cos(current) * radius;
printf("point: %d x:%lf y:%lf\n", i, x, y);
current += step;
}
return 0;
}
Try something like this:
void make_circle(float *output, size_t num, float radius)
{
size_t i;
for(i = 0; i < num; i++)
{
const float angle = 2 * M_PI * i / num;
*output++ = radius * cos(angle);
*output++ = radius * sin(angle);
}
}
This is untested, there might be an off-by-one hiding in the angle step calculation but it should be close.
This assumes I understood the question correctly, of course.
UPDATE: Redid the angle computation to not be incrementing, to reduce float precision loss due to repeated addition.
Here's a solution, somewhat optimized, untested. Error can accumulate, but using double rather than float probably more than makes up for it except with extremely large values of n.
void make_circle(double *dest, size_t n, double r)
{
double x0 = cos(2*M_PI/n), y0 = sin(2*M_PI/n), x=x0, y=y0, tmp;
for (;;) {
*dest++ = r*x;
*dest++ = r*y;
if (!--n) break;
tmp = x*x0 - y*y0;
y = x*y0 + y*x0;
x = tmp;
}
}
You have to solve this in c language:
In an x-y Cartesian coordinate system, the circle with centre coordinates (a, b) and radius r is the set of all points (x, y) such that
(x - a)^2 + (y - b)^2 = r^2
Here's a javascript implementation that also takes an optional center point.
function circlePoints (radius, numPoints, centerX, centerY) {
centerX = centerX || 0;
centerY = centerY || 0;
var
step = (Math.PI * 2) / numPoints,
current = 0,
i = 0,
results = [],
x, y;
for (; i < numPoints; i += 1) {
x = centerX + Math.sin(current) * radius;
y = centerY + Math.cos(current) * radius;
results.push([x,y]);
console.log('point %d # x:%d, y:%d', i, x, y);
current += step;
}
return results;
}