Related
I'm a beginner in CS50 trying to do the Credit problem from Problem Set 1. We are using C. The problem asks us to validate credit card numbers using Luhn's algorithm. I was going to use an array, but code using one wasn't easy to understand for me.
I'm trying to type out the full Luhn formula to calculate. I don't know where I'm messing up. Every time I run a card number that's supposed to be valid, it's never card_total % 10 = 0 like it should be.
Example Card Number: 4003600000000014 => checksum total (int card_total) = 33
Below is just code that asks for the credit card number, runs it through the algorithm, and prints out the total checksum just for me to see if it's working properly. I know this is really long, but this is just for my understanding of all the pieces. I've written much shorter and nicer code before. I swear!
EDIT: I run my code in the cs50 VS virtual codespace, which uses Linux I think. I will take the advice of changing the other ints to longs and see if this fixes my problem. My formulas are consistent, so this is a formatting issue. Once this is fixed, the rest of the problem is easy to solve.
Someone mentioned my complicated calculations. Sorry. I know this could be more brief, but I just wanted to follow the algorithm so I can see what's going on. The lecture for this week didn't touch on going through arrays or manipulating strings, so I'm just doing what I know so far in C. This would be a lot easier in python.
EDIT 2: All that needed to change was int to long. The code now works perfectly and incorporates properly with the rest of my code checking for Amex, Visa, etc. THANK YOU SO MUCH!
#include <cs50.h>
#include <stdio.h>
int get_number(void);
int main(void)
{
long n = get_number();
//calculating card number with modulo
long a = ((n % 10000000000000000) / 1000000000000000);
long b = ((n % 1000000000000000) / 100000000000000);
long c = ((n % 100000000000000) / 10000000000000);
long d = ((n % 10000000000000) / 1000000000000);
long e = ((n % 1000000000000) / 100000000000);
long f = ((n % 100000000000) / 10000000000);
long g = ((n % 10000000000) / 1000000000);
long h = ((n % 1000000000) / 100000000);
long i = ((n % 100000000) / 10000000);
long j = ((n % 10000000) / 1000000);
long k = ((n % 1000000) / 100000);
long l = ((n % 100000) / 10000);
long m = ((n % 10000) / 1000);
long ene = ((n % 1000) / 100);
long o = ((n % 100) / 10);
long p = ((n % 10) / 1); //The "/ 1" is just for visualization
// multiply odd numbers by 2 //Also for visualization
long q = a * 2;
long r = c * 2;
long s = e * 2;
long t = g * 2;
long u = i * 2;
long v = k * 2;
long w = m * 2;
long x = o * 2;
//process odd products //Luhn's has exceptions for double digit numbers
long qq;
if (q < 10)
{
qq = ((q % 10) + ((q % 100)/10));
}
else if (q > 10)
{
qq = (q % 10) + 1;
}
else if (q == 10)
{
qq = 1;
}
else
{
qq = q;
}
long rr;
if (r < 10)
{
rr = ((r % 10) + ((r % 100) / 10));
}
else if (r > 10)
{
rr = (r % 10) + 1;
}
else if (r == 10)
{
rr = 1;
}
else
{
rr = r;
}
long ss;
if (s < 10)
{
ss = ((s % 10) + ((s % 100) / 10));
}
else if (s > 10)
{
ss = (s % 10) + 1;
}
else if (s == 10)
{
ss = 1;
}
else
{
ss = s;
}
long tt;
if (t < 10)
{
tt = ((t % 10) + ((t % 100) / 10));
}
else if (t > 10)
{
tt = (t % 10) + 1;
}
else if (t == 10)
{
tt = 1;
}
else
{
tt = t;
}
long uu;
if (u < 10)
{
uu = ((u % 10) + ((u % 100) / 10));
}
else if (u > 10)
{
uu = (u % 10) + 1;
}
else if (u == 10)
{
uu = 1;
}
else
{
uu = u;
}
long vv;
if (v < 10)
{
vv = ((v % 10) + ((v % 100) / 10));
}
else if (v > 10)
{
vv = (v % 10) + 1;
}
else if (v == 10)
{
vv = 1;
}
else
{
vv = v;
}
long ww;
if (w < 10)
{
ww = ((w % 10) + ((w % 100) / 10));
}
else if (w > 10)
{
ww = (w % 10) + 1;
}
else if (w == 10)
{
ww = 1;
}
else
{
ww = w;
}
long xx;
if (x < 10)
{
xx = ((x % 10) + ((x % 100) / 10));;
}
else if (x > 10)
{
xx = (x % 10) + 1;
}
else if (x == 10)
{
xx = 1;
}
else
{
xx = x;
}
//Sum processed odd products
long total_odd = qq + rr + ss + tt + uu + vv + ww + xx;
//sum total odd products and even card numbers
long bb = ((b % 10) + ((b % 100) / 10));
long dd = ((d % 10) + ((d % 100) / 10));
long ff = ((f % 10) + ((f % 100) / 10));
long hh = ((h % 10) + ((h % 100) / 10));
long jj = ((j % 10) + ((j % 100) / 10));
long ll = ((l % 10) + ((l % 100) / 10));
long eneene = ((ene % 10) + ((ene % 100) / 10));
long pp = ((p %10) + ((p % 100) / 10));
long total_even = bb + dd + ff + hh+ jj + ll + eneene + pp;
//sum odd & even
long card_total = total_odd + total_even;
printf(" %li\n", card_total);
}
int get_number(void) //Works perfectly
{
long n;
do
{
n = get_long("Number: "); // Records credit card number
}
while (n < 1000000000000 || n > 5599999999999999); // CC at least 13 digits but < 17 digits
return n;
}
Trying out your code and debugging it, the issue I found right away is that the return size element for your "get_number" function is too small.
int get_number(void);
When I debugged the returned value to the main function, the value was a negative number since the integer return value is too small for your long integer.
Changing the function definition to "long get_number(void)" in the prototype and the function, allowed for the entered value to flow back to the main function and get tested properly. Following was the test output on my terminal (FYI, I added a couple of printf statements to illustrate that the entered value was flowing through properly).
#Vera:~/C_Programs/Console/CC_Luhn/bin/Release$ ./CC_Luhn
Number: 4003600000000014
Value stored is: 4003600000000014
Returned number: 4003600000000014
20
Just as a double-check, I ran a Luhn calculator program I had built some time back to answer a similar problem. Following is the output again using your credit card example as input.
#Vera:~/C_Programs/Console/Luhn/bin/Release$ ./Luhn
Enter a number: 4003600000000014
Length of number is: 16
Digit is: 4 Value is: 8 Sum is 8
Digit is: 0 Value is: 0 Sum is 8
Digit is: 0 Value is: 0 Sum is 8
Digit is: 3 Value is: 3 Sum is 11
Digit is: 6 Value is: 3 Sum is 14
Digit is: 0 Value is: 0 Sum is 14
Digit is: 0 Value is: 0 Sum is 14
Digit is: 0 Value is: 0 Sum is 14
Digit is: 0 Value is: 0 Sum is 14
Digit is: 0 Value is: 0 Sum is 14
Digit is: 0 Value is: 0 Sum is 14
Digit is: 0 Value is: 0 Sum is 14
Digit is: 0 Value is: 0 Sum is 14
Digit is: 0 Value is: 0 Sum is 14
Digit is: 1 Value is: 2 Sum is 16
Digit is: 4 Value is: 4 Sum is 20
Valid
The result of the final calculation was the value of "20" which is a number that ends in zero, which indicates a valid number.
This might have been a bit verbose, but the bottom line is be careful mixing your integer sizes in functions and formulas.
Give that a try to see if it meets the spirit of your project.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I'm looking to implement an FFT algorithm on microcontrollers so I want to simulate the codes before actually using it
I got 2 examples which I converted to matlab codes but the result just isn't what I'm expected
Here are the codes:
function [ H ] = fft_2( g )
%FFT2 Summary of this function goes here
% Detailed explanation goes here
NUMDATA = length(g);
NUMPOINTS = NUMDATA/2;
N = NUMPOINTS;
% for(k=0; k<N; k++)
% {
% IA[k].imag = -(short)(16383.0*(-cos(2*pi/(double)(2*N)*(double)k)));
% IA[k].real = (short)(16383.0*(1.0 - sin(2*pi/(double)(2*N)*(double)k)));
% IB[k].imag = -(short)(16383.0*(cos(2*pi/(double)(2*N)*(double)k)));
% IB[k].real = (short)(16383.0*(1.0 + sin(2*pi/(double)(2*N)*(double)k)));
% }
for k=0:(N-1)
IA(k+1,2) = -floor(16383.0*(-cos(2*pi/(2*N)*k)));
IA(k+1,1) = floor(16383.0*(1.0 - sin(2*pi/(2*N)*k)));
IB(k+1,2) = -floor(16383.0*(cos(2*pi/(2*N)*k)));
IB(k+1,1) = floor(16383.0*(1.0 + sin(2*pi/(2*N)*k)));
end
% Note, IA(k) is the complex conjugate of A(k) and IB(k) is the complex conjugate of
% B(k).
% *********************************************************************************/
% #include <math.h>
% #include ”params1.h”
% #include ”params.h”
% extern short g[];
% void dft(int, COMPLEX *);
% void split(int, COMPLEX *, COMPLEX *, COMPLEX *, COMPLEX *);
% main()
% {
% int n, k;
% COMPLEX x[NUMPOINTS+1]; /* array of complex DFT data */
% COMPLEX A[NUMPOINTS]; /* array of complex A coefficients */
% COMPLEX B[NUMPOINTS]; /* array of complex B coefficients */
% COMPLEX IA[NUMPOINTS]; /* array of complex A* coefficients */
% COMPLEX IB[NUMPOINTS]; /* array of complex B* coefficients */
% COMPLEX G[2*NUMPOINTS]; /* array of complex DFT result */
% for(k=0; k<NUMPOINTS; k++)
for k=0:(NUMPOINTS-1)
% {
% A[k].imag = (short)(16383.0*(-cos(2*pi/(double)(2*NUMPOINTS)*(double)k)));
% A[k].real = (short)(16383.0*(1.0 - sin(2*pi/(double)(2*NUMPOINTS)*(double)k)));
% B[k].imag = (short)(16383.0*(cos(2*pi/(double)(2*NUMPOINTS)*(double)k)));
% B[k].real = (short)(16383.0*(1.0 + sin(2*pi/(double)(2*NUMPOINTS)*(double)k)));
% IA[k].imag = -A[k].imag;
% IA[k].real = A[k].real;
% IB[k].imag = -B[k].imag;
% IB[k].real = B[k].real;
% }
A(k+1, 2) = floor(16383.0*(-cos(2*pi/(2*NUMPOINTS)*k)));
A(k+1, 1) = floor(16383.0*(1.0 - sin(2*pi/(2*NUMPOINTS)*k)));
B(k+1, 2) = floor(16383.0*(cos(2*pi/(2*NUMPOINTS)*k)));
B(k+1, 1) = floor(16383.0*(1.0 + sin(2*pi/(2*NUMPOINTS)*k)));
IA(k+1, 2) = -A(k+1, 2);
IA(k+1, 1) = A(k+1, 1);
IB(k+1, 2) = -B(k+1, 2);
IB(k+1, 1) = B(k+1, 1);
end
% /* Forward DFT */
% /* From the 2N point real sequence, g(n), for the N-point complex sequence, x(n) */
% for (n=0; n<NUMPOINTS; n++)
% {
for n=0:(NUMPOINTS-1)
% x[n].imag = g[2*n + 1]; /* x2(n) = g(2n + 1) */
% x[n].real = g[2*n]; /* x1(n) = g(2n) */
% }
x(n+1,2)=g(2*n + 1+1);
x(n+1,1)=g(2*n +1);
end
% /* Compute the DFT of x(n) to get X(k) -> X(k) = DFT{x(n)} */
% dft(NUMPOINTS, x);
% void dft(int N, COMPLEX *X)
% {
% int n, k;
% double arg;
% int Xr[1024];
% int Xi[1024];
% short Wr, Wi;
% for(k=0; k<N; k++)
% {
N=NUMPOINTS;
for k=0:(N-1)
% Xr[k] = 0;
% Xi[k] = 0;
Xr(k+1)=0;
Xi(k+1)=0;
% for(n=0; n<N; n++)
% {
for n=0:(N-1)
% arg =(2*PI*k*n)/N;
% Wr = (short)((double)32767.0 * cos(arg));
% Wi = (short)((double)32767.0 * sin(arg));
% Xr[k] = Xr[k] + X[n].real * Wr + X[n].imag * Wi;
% Xi[k] = Xi[k] + X[n].imag * Wr – X[n].real * Wi;
arg = (2*pi*k*n)/N;
Wr = floor(32767*cos(arg));
Wi = floor(32767*sin(arg));
Xr(k+1) = Xr(k+1)+x(n+1,1)*Wr+x(n+1,2)*Wi;
Xi(k+1) = Xr(k+1)+x(n+1,2)*Wr-x(n+1,1)*Wi;
% }
% }
end
end
% for (k=0;k<N;k++)
% {
for k=0:(N-1)
% X[k].real = (short)(Xr[k]>>15);
% X[k].imag = (short)(Xi[k]>>15);
x(k+1,1)=floor(Xr(k+1)/pow2(15));
x(k+1,2)=floor(Xi(k+1)/pow2(15));
% }
% }
end
% /* Because of the periodicity property of the DFT, we know that X(N+k)=X(k). */
% x[NUMPOINTS].real = x[0].real;
% x[NUMPOINTS].imag = x[0].imag;
x(NUMPOINTS+1,1)=x(1,1);
x(NUMPOINTS+1,2)=x(1,2);
% /* The split function performs the additional computations required to get
% G(k) from X(k). */
% split(NUMPOINTS, x, A, B, G);
% void split(int N, COMPLEX *X, COMPLEX *A, COMPLEX *B, COMPLEX *G)
% {
% int k;
% int Tr, Ti;
% for (k=0; k<N; k++)
% {
for k=0:(NUMPOINTS-1)
% Tr = (int)X[k].real * (int)A[k].real – (int)X[k].imag * (int)A[k].imag +
% (int)X[N–k].real * (int)B[k].real + (int)X[N–k].imag * (int)B[k].imag;
Tr = x(k+1,1)*A(k+1,1)-x(k+1,2)*A(k+1,2)+x(NUMPOINTS-k+1,1)*B(k+1,1)+x(NUMPOINTS-k+1,2)*B(k+1,2);
% G[k].real = (short)(Tr>>15);
G(k+1,1)=floor(Tr/pow2(15));
% Ti = (int)X[k].imag * (int)A[k].real + (int)X[k].real * (int)A[k].imag +
% (int)X[N–k].real * (int)B[k].imag – (int)X[N–k].imag * (int)B[k].real;
Ti = x(k+1,2)*A(k+1,1)+x(k+1,1)*A(k+1,2)+x(NUMPOINTS-k+1,1)*B(k+1,2)-x(NUMPOINTS-k+1,2)*B(k+1,1);
% G[k].imag = (short)(Ti>>15);
G(k+1,2)=floor(Ti/pow2(15));
% }
end
% }
% /* Use complex conjugate symmetry properties to get the rest of G(k) */
% G[NUMPOINTS].real = x[0].real - x[0].imag;
% G[NUMPOINTS].imag = 0;
% for (k=1; k<NUMPOINTS; k++)
% {
% G[2*NUMPOINTS-k].real = G[k].real;
% G[2*NUMPOINTS-k].imag = -G[k].imag;
% }
G(NUMPOINTS+1,1) = x(1,1) - x(1,2);
G(NUMPOINTS+1,2) = 0;
for k=1:(NUMPOINTS-1)
G(2*NUMPOINTS-k+1,1) = G(k+1,1);
G(2*NUMPOINTS-k+1,2) = -G(k+1,2);
end
for k=1:(NUMDATA)
H(k)=sqrt(G(k,1)*G(k,1)+G(k,2)*G(k,2));
end
end
Another one:
function [ fr, fi ] = fix_fft( fr, fi )
%UNTITLED Summary of this function goes here
% Detailed explanation goes here
N_WAVE = 1024; % full length of Sinewave[]
LOG2_N_WAVE = 10; % log2(N_WAVE)
m = nextpow2(length(fr));
% void fix_fft(short fr[], short fi[], short m)
% {
% long int mr = 0, nn, i, j, l, k, istep, n, shift;
mr=0;
% short qr, qi, tr, ti, wr, wi;
%
% n = 1 << m;
n = pow2(m);
% nn = n - 1;
nn = n-1;
%
% /* max FFT size = N_WAVE */
% //if (n > N_WAVE) return -1;
%
% /* decimation in time - re-order data */
% for (m=1; m<=nn; ++m)
for m=1:nn
% {
% l = n;
l=n;
% do
% {
% l >>= 1;
% } while (mr+l > nn);
not_done = true;
while(mr+l>nn || not_done)
l=floor(l/2);
not_done=false;
end
%
% mr = (mr & (l-1)) + l;
mr = (mr & (l-1)) + l;
% if (mr <= m) continue;
if (mr <= m)
continue
end
%
% tr = fr[m];
% fr[m] = fr[mr];
% fr[mr] = tr;
% ti = fi[m];
% fi[m] = fi[mr];
% fi[mr] = ti;
tr = fr(m+1);
fr(m+1) = fr(mr+1);
fr(mr+1) = tr;
ti = fi(m+1);
fi(m+1) = fi(mr+1);
fi(mr+1) = ti;
% }
end
%
% l = 1;
% k = LOG2_N_WAVE-1;
l=1;
k = LOG2_N_WAVE-1;
%
% while (l < n)
% {
while (l < n)
% /*
% fixed scaling, for proper normalization --
% there will be log2(n) passes, so this results
% in an overall factor of 1/n, distributed to
% maximize arithmetic accuracy.
%
% It may not be obvious, but the shift will be
% performed on each data point exactly once,
% during this pass.
% */
%
% // Variables for multiplication code
% long int c;
% short b;
%
% istep = l << 1;
istep = l*2;
% for (m=0; m<l; ++m)
% {
for m=0:(l-1)
% j = m << k;
% /* 0 <= j < N_WAVE/2 */
% wr = Sinewave[j+N_WAVE/4];
% wi = -Sinewave[j];
j = m*(pow2( k));
wr = sin((j+N_WAVE/4)*2*pi/N_WAVE)*32768;
wi = -sin(j*2*pi/1024)*32768;
%
% wr >>= 1;
% wi >>= 1;
wr = floor(wr/2);
wi = floor(wi/2);
%
% for (i=m; i<n; i+=istep)
% {
i=m;
while(i<n)
% j = i + l;
j = i+l;
%
% // Here I unrolled the multiplications to prevent overhead
% // for procedural calls (we don't need to be clever about
% // the actual multiplications since the pic has an onboard
% // 8x8 multiplier in the ALU):
%
% // tr = FIX_MPY(wr,fr[j]) - FIX_MPY(wi,fi[j]);
% c = ((long int)wr * (long int)fr[j]);
% c = c >> 14;
% b = c & 0x01;
% tr = (c >> 1) + b;
c = wr * fr(j+1);
c = floor(c / pow2(14));
b = c & 1;
tr = floor(c /2) + b;
%
% c = ((long int)wi * (long int)fi[j]);
% c = c >> 14;
% b = c & 0x01;
% tr = tr - ((c >> 1) + b);
c = wi * fi(j+1);
c = floor(c / pow2(14));
b = c & 1;
tr = tr - (floor((c/2)) + b);
%
% // ti = FIX_MPY(wr,fi[j]) + FIX_MPY(wi,fr[j]);
% c = ((long int)wr * (long int)fi[j]);
% c = c >> 14;
% b = c & 0x01;
% ti = (c >> 1) + b;
c = wr*fi(j+1);
c = floor(c / pow2(14));
b = c & 1;
ti = floor((c /2)) + b;
%
% c = ((long int)wi * (long int)fr[j]);
% c = c >> 14;
% b = c & 0x01;
% ti = ti + ((c >> 1) + b);
c = wi * fr(j+1);
c = floor(c / pow2(14));
b = c & 1;
ti = ti + (floor((c/2)) + b);
%
% qr = fr[i];
% qi = fi[i];
% qr >>= 1;
% qi >>= 1;
%
% fr[j] = qr - tr;
% fi[j] = qi - ti;
% fr[i] = qr + tr;
% fi[i] = qi + ti;
qr = fr(i+1);
qi = fi(i+1);
qr = floor(qr/2);
qi = floor(qi/2);
fr(j+1) = qr - tr;
fi(j+1) = qi - ti;
fr(i+1) = qr + tr;
fi(i+1) = qi + ti;
% }
i = i+istep;
end
% }
end
%
% --k;
% l = istep;
% }
k=k-1;
l=istep;
end
% }
end
Those in comments are the original, those aren't are the translated code
Then I simulated with this
function [ r ] = mfft( f )
%MFFT Summary of this function goes here
% Detailed explanation goes here
Fs = 2048;
T = 1/Fs;
L = 2048;
t = (0:L-1)*T;
NFFT = 2^nextpow2(L);
l = length(f);
y = 0;
for k=1:l
y = y + sin(2*pi*f(k)*t);
end
%sound(y, Fs);
Y = fft(y,NFFT)/L;
YY = fft_2(y)/L;
[Y1 Y2] = fix_fft(y, zeros(1, L));
YYY = Y1+j()*Y2;
f = Fs/2*linspace(0,1,NFFT/2+1);
plot(f, 2*abs(Y(1:NFFT/2+1)), ':+b');
hold on
plot(f, 2*abs(YY(1:NFFT/2+1)), '-or');
plot(f, abs(YYY(1:NFFT/2+1)), '--*g');
hold off
r=0;
end
Basically create a simple sine wave with a specific frequency (say 400Hz)
The expected output of the FFT should be a spike at 400 only, which the builtin FFT function agrees but the other codes didn't
Here's the output graph
The blue line is from builtin function and is what expected
The red line is the above code which, well, looks pretty good except there is a spike elsewhere with higher amplitude
The green line is absolute mess
I tried checking the program several times but to no avail
Did I ported them wrong or somehow I can fix them?
There are several ways to approach this problem, and a programmer should try all of them. First, an FFT is an optimization of a Fourier Transform, so as a first step code a Fourier Transform. That is, don't do an FFT, just do a FT directly.
These days an FT is not as slow as you might think. Unless the project needs to transform something like 10,000 data points in less than a few milliseconds. Also, an FT, compared to an FFT, is simple and easy to debug.
Doing this for a problem provides a baseline, that is, the correct answer. This is important because when you work on the FFT how do you know if the problem is in the code for the FFT or that the data is correct and just giving you an unexpected, but correct, answer.
Next, use a pre-written package to do an FFT. Scan the web, I know there are packages written in C that do FFTs.
Third, if you just have to write your own FFT then do so. But only if tasks (1) or (2) don't meet your requirements. It will be difficult to out-do any pre-written FFT packages.
You will learn much along this path.
I've a problem, i'm stuck with some underflow problem for my algorithm.
I'm basically dseisgning a path from a Bezier curve and to deal with this I had to work with some vector multiplication (cross and dot product) in order to have the angle between two vectors and the clock-counterclock direction from one to another one.
The problem is that when the path is a straight line one of the control variable has problem of underflow, basically blocking the execution and causing errors.
Here is the code:
void BezierInterp() {
NumOfSetpoints = 10;
float seqTH[11];
float orient[10];
float divider;
math.MatrixMult((float*) BCoeff, (float*) waypointX, 11, 4, 1,
(float*) setpoint0);
math.MatrixMult((float*) BCoeff, (float*) waypointY, 11, 4, 1,
(float*) setpoint1);
float dx1, dy1, dx2, dy2, dxy1, dxy2, dir;
dx1 = cos(state[2]);
dy1 = sin(state[2]);
dx2 = setpoint0[1] - setpoint0[0];
dy2 = setpoint1[1] - setpoint1[0];
dxy2 = sqrt(sq(dx2) + sq(dy2));
dir = dx1 * dy2 - dx2 * dy1;
if (dxy2<0.0001 && dxy2>-0.0001) {
seqTH[0] = 0.0;
}
else{
if (dir >= 0) {
seqTH[0] = acos((dx1 * dx2 + dy1 * dy2) / (dxy2));
} else {
seqTH[0] = -acos((dx1 * dx2 + dy1 * dy2) / (dxy2));
}}
for (uint8_t i = 1; i <= 9; i = i + 1) {
dx2 = setpoint0[i + 1] - setpoint0[i];
dy2 = setpoint1[i + 1] - setpoint1[i];
dxy2 = sqrt(sq(dx2) + sq(dy2));
dx1 = setpoint0[i] - setpoint0[i - 1];
dy1 = setpoint1[i] - setpoint1[i - 1];
dxy1 = sqrt(sq(dx1) + sq(dy1));
dir = dx1 * dy2 - dx2 * dy1;
divider= dxy1 * dxy2;
if (divider<0.0001 && divider>-0.0001) {
seqTH[0] = 0.0;
}
else {
if (dir >= 0) {
seqTH[i] = acos((dx1 * dx2 + dy1 * dy2) / (divider));
} else {
seqTH[i] = -acos((dx1 * dx2 + dy1 * dy2) / (divider));
}}
}
print_array("seqTh", seqTH, 11, 6);
orient[0] = state[2] + seqTH[0];
if (orient[0]<0.0001 && orient[0]>-0.0001){orient[0]=0.0001;}
for (uint8_t i = 1; i <= 9; i = i + 1) {
orient[i] = orient[i - 1] + seqTH[i];
if (orient[i]<0.0001 && orient[i]>-0.0001){orient[i]=0.0001;}
}
print_array("orient", orient, 10, 6);
for (uint8_t i = 1; i <= 9; i = i + 1) {
setpoint2[i] = orient[i - 1];
setpoint3[i] = Vref * cos(orient[i - 1]);
setpoint4[i] = Vref * sin(orient[i - 1]);
}
setpoint2[10] = orient[9];
setpoint3[10] = 0;
setpoint4[10] = 0;
setpoint5[10] = 0;
}
}
As you see in the attempt to avoid error I put several if conditions, but was not enough.
Actually the problem come probably from dir=dx1 * dy2 - dx2 * dy1;. that's when moving along x or y axis is too small to be a float.
A friend suggested to use a boolean value but I'm not sure how.
Maybe defining boolean dir; and then if the value is too small will be a 0 otherwise will be considered a 1 and in that case I could use the same procedure i'm using now for the detection of the direction.
Do you have any suggestion or maybe a different solution?
Thanks in advance
Ned
I'm not familiar with the method you're using, but when I've done this in the past I've detected the degenerate case of the Bezier (where the two end points and two control points fall on a straight line) as a special case.
This is also much faster to draw of course.
I use the following code to rotate a bitmask (a packed 2d array). To be honest I do not have a firm grip of the algorithm used, I copied and modified the rotation code from the pygame library (where it was used to rotate surfaces). Due to the implementation of bitmask I can speed this rotation up a lot by reversing the inner loop. With that I mean, instead of doing foreach y { foreach x { ... } } I need to do foreach x { foreach y { ... } }. I have trouble reversing the loop because the trigonometry has to be adapted in a way I don't currently see at this moment.
Here's the code:
typedef struct bitmask {
int w,h;
BITMASK_W bits[1];
} bitmask_t;
bitmask_t* bitmask_rotate(const bitmask_t *mask, float angle) {
bitmask_t *newmask = NULL;
double radangle, sangle, cangle;
int isin, icos;
double cx, cy, sx, sy;
int x, y, ax, ay, xd, yd, dx, dy;
int nxmax, nymax, xmaxval, ymaxval;
radangle = angle * DEG_TO_RAD;
sangle = sin(radangle);
cangle = cos(radangle);
isin = (int)(sangle * 65536);
icos = (int)(cangle * 65536);
x = mask->w;
y = mask->h;
cx = cangle*x;
cy = cangle*y;
sx = sangle*x;
sy = sangle*y;
nxmax = (int) (MAX (MAX (MAX (fabs (cx + sy), fabs (cx - sy)), fabs (-cx + sy)), fabs (-cx - sy)));
nymax = (int) (MAX (MAX (MAX (fabs (sx + cy), fabs (sx - cy)), fabs (-sx + cy)), fabs (-sx - cy)));
newmask = bitmask_create(nxmax, nymax, 0);
if (!newmask) return NULL;
cy = newmask->h / 2;
xd = ((mask->w - newmask->w) << 15);
yd = ((mask->h - newmask->h) << 15);
ax = ((newmask->w) << 15) - (int)(cangle * ((newmask->w - 1) << 15));
ay = ((newmask->h) << 15) - (int)(sangle * ((newmask->w - 1) << 15));
xmaxval = ((mask->w) << 16) - 1;
ymaxval = ((mask->h) << 16) - 1;
for (y = 0; y < newmask->h; y++) {
dx = (ax + (isin * (cy - y))) + xd;
dy = (ay - (icos * (cy - y))) + yd;
for (x = 0; x < newmask->w; x++) {
if (!(dx < 0 || dy < 0 || dx > xmaxval || dy > ymaxval)) {
if (bitmask_getbit(mask, dx >> 16, dy >> 16)) {
bitmask_setbit(newmask, x, y);
}
}
dx += icos;
dy += isin;
}
}
return newmask;
}
Before people are going to ask "what have you tried?", I looped up rotating matrices on Wikipedia, and I could see what is going on there and how they implemented it in this algorithm (precalculate a starting dx and dy and then increment with icos and isin), but the bitshifts and parameters I don't understand (ax for example) make it hard for me to follow.
for (x = 0; x < newmask->w; x++) {
dx = (ax + (isin * cy + icos * x)) + xd;
dy = (ay - (icos * cy - isin * x)) + yd;
for (y = 0; y < newmask->h; y++) {
if (!(dx < 0 || dy < 0 || dx > xmaxval || dy > ymaxval)) {
if (bitmask_getbit(mask, dx >> 16, dy >> 16)) {
bitmask_setbit(newmask, x, y);
}
}
dx -= isin;
dy += icos;
}
}
I'm working on a problem that the professor assigned, and I'm having a problem looking for a way to detect if the angle between 3 points is more than 180 degrees, e.g:
I want to detect if alpha is more than 180 degrees. Anyways, my professor has a code that solves the problem, but he has a function called zcross, but I don't exactly know how it works. Could anyone tell me? His code is here:
#include <fstream.h>
#include <math.h>
#include <stdlib.h>
struct point {
double x;
double y;
double angle;
};
struct vector {
double i;
double j;
};
point P[10000];
int hull[10000];
int
zcross (vector * u, vector * v)
{
double p = u->i * v->j - v->i * u->j;
if (p > 0)
return 1;
if (p < 0)
return -1;
return 0;
}
int
cmpP (const void *a, const void *b)
{
if (((point *) a)->angle < ((point *) b)->angle)
return -1;
if (((point *) a)->angle > ((point *) b)->angle)
return 1;
return 0;
}
void
main ()
{
int N, i, hullstart, hullend, a, b;
double midx, midy, length;
vector v1, v2;
ifstream fin ("fc.in");
fin >> N;
midx = 0, midy = 0;
for (i = 0; i < N; i++) {
fin >> P[i].x >> P[i].y;
midx += P[i].x;
midy += P[i].y;
}
fin.close ();
midx = (double) midx / N;
midy = (double) midy / N;
for (i = 0; i < N; i++)
P[i].angle = atan2 (P[i].y - midy, P[i].x - midx);
qsort (P, N, sizeof (P[0]), cmpP);
hull[0] = 0;
hull[1] = 1;
hullend = 2;
for (i = 2; i < N - 1; i++) {
while (hullend > 1) {
v1.i = P[hull[hullend - 2]].x - P[hull[hullend - 1]].x;
v1.j = P[hull[hullend - 2]].y - P[hull[hullend - 1]].y;
v2.i = P[i].x - P[hull[hullend - 1]].x;
v2.j = P[i].y - P[hull[hullend - 1]].y;
if (zcross (&v1, &v2) < 0)
break;
hullend--;
}
hull[hullend] = i;
hullend++;
}
while (hullend > 1) {
v1.i = P[hull[hullend - 2]].x - P[hull[hullend - 1]].x;
v1.j = P[hull[hullend - 2]].y - P[hull[hullend - 1]].y;
v2.i = P[i].x - P[hull[hullend - 1]].x;
v2.j = P[i].y - P[hull[hullend - 1]].y;
if (zcross (&v1, &v2) < 0)
break;
hullend--;
}
hull[hullend] = i;
hullstart = 0;
while (true) {
v1.i = P[hull[hullend - 1]].x - P[hull[hullend]].x;
v1.j = P[hull[hullend - 1]].y - P[hull[hullend]].y;
v2.i = P[hull[hullstart]].x - P[hull[hullend]].x;
v2.j = P[hull[hullstart]].y - P[hull[hullend]].y;
if (hullend - hullstart > 1 && zcross (&v1, &v2) >= 0) {
hullend--;
continue;
}
v1.i = P[hull[hullend]].x - P[hull[hullstart]].x;
v1.j = P[hull[hullend]].y - P[hull[hullstart]].y;
v2.i = P[hull[hullstart + 1]].x - P[hull[hullstart]].x;
v2.j = P[hull[hullstart + 1]].y - P[hull[hullstart]].y;
if (hullend - hullstart > 1 && zcross (&v1, &v2) >= 0) {
hullstart++;
continue;
}
break;
}
length = 0;
for (i = hullstart; i <= hullend; i++) {
a = hull[i];
if (i == hullend)
b = hull[hullstart];
else
b = hull[i + 1];
length += sqrt ((P[a].x - P[b].x) * (P[a].x - P[b].x) + (P[a].y - P[b].y) * (P[a].y - P[b].y));
}
ofstream fout ("fc.out");
fout.setf (ios: :fixed);
fout.precision (2);
fout << length << '\n';
fout.close ();
}
First, we know that if sin(a) is negative, then the angle is more than 180 degrees.
How do we find the sign of sin(a)? Here is where cross product comes into play.
First, let's define two vectors:
v1 = p1-p2
v2 = p3-p2
This means that the two vectors start at p2 and one points to p1 and the other points to p3.
Cross product is defined as:
(x1, y1, z1) x (x2, y2, z2) = (y1z2-y2z1, z1x2-z2x1, x1y2-x2y1)
Since your vectors are in 2d, then z1 and z2 are 0 and hence:
(x1, y1, 0) x (x2, y2, 0) = (0, 0, x1y2-x2y1)
That is why they call it zcross because only the z element of the product has a value other than 0.
Now, on the other hand, we know that:
||v1 x v2|| = ||v1|| * ||v2|| * abs(sin(a))
where ||v|| is the norm (size) of vector v. Also, we know that if the angle a is less than 180, then v1 x v2 will point upwards (right hand rule), while if it is larger than 180 it will point down. So in your special case:
(v1 x v2).z = ||v1|| * ||v2|| * sin(a)
Simply put, if the z value of v1 x v2 is positive, then a is smaller than 180. If it is negative, then it's bigger (The z value was x1y2-x2y1). If the cross product is 0, then the two vectors are parallel and the angle is either 0 or 180, depending on whether the two vectors have respectively same or opposite direction.
zcross is using the sign of the vector cross product (plus or minus in the z direction) to determine if the angle is more or less than 180 degrees, as you've put it.
In 3D, find the cross product of the vectors, find the minimum length for the cross product which is basically just finding the smallest number of x, y and z.
If the smallest value is smaller than 0, the angle of the vectors is negative.
So in code:
float Vector3::Angle(const Vector3 &v) const
{
float a = SquareLength();
float b = v.SquareLength();
if (a > 0.0f && b > 0.0f)
{
float sign = (CrossProduct(v)).MinLength();
if (sign < 0.0f)
return -acos(DotProduct(v) / sqrtf(a * b));
else
return acos(DotProduct(v) / sqrtf(a * b));
}
return 0.0f;
}
Another way to do it would be as follows:
calculate vector v1=p2-p1, v2 = p2 -p3.
Then, use the cross-product formula : u.v = ||u|| ||v|| cos(theta)