I am working on an implementation of a Moog VCF filter that creates a fourth order filter by placing four first order filters in series. These first order filters all share the same values for their coefficients. One way of approaching this was to use aggregation and create a filter class whose member variables were reference types:
class FirstOrderFilter {
public:
FirstOrderFilter(float& a1, float& b0, float& b1, float& g) : a1(a1), b0(b0), b1(b1), g(g) {}
float process(float in);
private:
// Coefficients
float& a1;
float& b0;
float& b1;
float& g;
// x[n-1]
float previousInput;
// y[n-1]
float previousOutput;
};
The idea was that I could create an array or vector of filters at the start of the program and any change to the coefficients would cause the member variables for each class to be updated without the need to call a setter function.
This does work but I ran into a few issues. The only two options for initialising the containers that work are:
std::vector<FirstOrderFilter> filters (4, FirstOrderFilter{gA1, gB0, gB1, gCutoff});
std::array<FirstOrderFilter, 4> = {
FirstOrderFilter{gA1, gB0, gB1, gCutoff},
FirstOrderFilter{gA1, gB0, gB1, gCutoff},
FirstOrderFilter{gA1, gB0, gB1, gCutoff},
FirstOrderFilter{gA1, gB0, gB1, gCutoff}
};
If I do the following:
std::vector<FirstOrderFilter> filters;
for (int i = 0; i < 4; i++)
filters.push_back({gA1, gB0, gB1, gCutoff});
The program crashes because the output becomes incredibly large (although there is no runtime error produced). If I use emplace_back the program still runs but the filter does not display the correct behaviour.
I looked into using std::reference_wrapper but I am not sure of the correct way to use it. For example, the following does not improve matters:
// Coefficients
std::reference_wrapper<float> a1;
std::reference_wrapper<float> b0;
std::reference_wrapper<float> b1;
std::reference_wrapper<float> g;
I understand this is caused by the fact that references cannot be copied or assigned, however, I thought emplace_back might help get round this. If I was to use an array instead of a vector, is there another way of initialising the array instead of the cumbersome method above?
Can anyone explain what is happening here?
Here is a minimal reproducible example:
#include <iostream>
#include <vector>
float gA1 = 0.0f, gB0 = 0.0f, gB1 = 0.0f;
float gCutoff = 0.0f;
void calculate_coefficients()
{
gA1 = 1.0f; gB0 = 1.0f / 1.3f; gB1 = 0.3f / 1.3f;
gCutoff = 1.0f;
}
class Filter {
public:
Filter(float& a1, float& b0, float& b1, float& g) : a1(a1), b0(b0), b1(b1), g(g) {}
float process(float in);
private:
// Coefficients
float& a1;
float& b0;
float& b1;
float& g;
// x[n-1]
float previousInput = 0.0f;
// y[n-1]
float previousOutput = 0.0f;
};
float Filter::process(float in)
{
float out = ((b0*in + b1*previousInput - a1*previousOutput) * g) + a1*previousOutput;
previousInput = in;
previousOutput = out;
return out;
}
std::vector<Filter> filters;
// This produces the expected result
// std::vector<Filter> filters (4, Filter(gA1, gB0, gB1, gCutoff));
int main() {
// Comment out this loop if using fill constructor
for (unsigned int i = 0; i < 4; i++)
filters.push_back(Filter(gA1, gB0, gB1, gCutoff));
calculate_coefficients();
float out = 1.0f;
for (unsigned int i = 0; i < filters.size(); i++)
out = filters[i].process(out);
std::cout << std::to_string(out) << std::endl;
}
The output produced by running the above code is a negative long double. Something like -66466164548257686390571008.000000, for example.
Update: This error was caused by declaring the reference types on the same line and not initialising previousInput and previousOutput correctly.
Related
so, I am writing a couple of functions so to run GLSL fragment shaders on CPU. I implemented all the basic mathematical functions to do so. However I can't even get the simplest stuff to execute correctly. I was able to trace it down to either of these functions:
template<unsigned vsize>
_SHADERH_INLINE
vec<float, vsize> normalize(const vec<float, vsize>& vs) {
vec<float, vsize> fres;
float mod = 0.0f;
for (unsigned i = 0; i < vsize; ++i) {
mod += vs[i] * vs[i];
}
float mag = glsl::sqrt(mod);
if (mag == 0) {
std::logic_error("In normalize the input vector is a zero vector");
}
for (unsigned i = 0; i < vsize; ++i) {
fres[i] = vs[i] / mag;
}
return fres;
}
template<unsigned vsize>
_SHADERH_INLINE
vec<float, vsize> length(const vec<float, vsize>& vs) {
float fres = 0;
for (unsigned it = 0; it != vsize; it++) {
fres += vs[it] * vs[it];
}
return glsl::sqrt(fres);
}
template<unsigned vsize>
_SHADERH_INLINE
vec<float, vsize> dot(const vec<float, vsize>& vs1, const vec<float, vsize>& vs2) {
return std::inner_product(vs1.begin(), vs1.end(), vs2.begin(), 0);
}
But it could still be something in my vec implementation (pretty certain it's not).
So, does anyone see anything wrong with the code above or something that does not align with glsl behavior? If nobody is able to find anything wrong there, I will make a follow-up question with my vec implementation.
There are few things that may be the origin of the problems.
Failing dot function
After a bit of testing, it turned out that your dot function fails, because you are providing an integer value 0 as initial value in your call to inner_product, which results in wrong calculations. See this post for the reason: Zero inner product when using std::inner_product
Simply write 0.0f to ensure a float as initial value for the accumulator :
vec<float, vsize> dot(const vec<float, vsize>& vs1, const vec<float, vsize>& vs2) {
return std::inner_product(vs1.begin(), vs1.end(), vs2.begin(), 0.0f);
}
More generally, I recommend you to always write any hardcoded value with clear indication of its type.
You can also manually write your dot product as well, as you did in normalize and length :
vec<float, vsize> dot(const vec<float, vsize>& vs1, const vec<float, vsize>& vs2) {
float f = 0.0f;
for (unsigned i = 0; i < vsize; ++i) {
f += vs1[i] * vs2[i];
}
return f;
}
No exception thrown when normalizing a null vector
In the normalize function, you are not actually throwing any error when mag == 0. When passing a null vector to normalize, it returns (-nan, -nan, -nan) instead of throwing the error you want. std::logic_error does not throw any error, it creates an object to be thrown (see : https://en.cppreference.com/w/cpp/error/logic_error).
Thus instead of writing :
if (mag == 0) {
// Doesn't do anything...
std::logic_error("In normalize the input vector is a zero vector");
}
You must write :
if (mag == 0.0f) {
// Actually throws a `logic_error` exception
throw std::logic_error("In normalize the input vector is a zero vector");
}
Handling of floats as vec types
This depends on your implementation of vec. length and dot return scalar values (float) and not vectors. Since (to my understanding) you didn't mention compilation errors, I assume your vec type can handle floats as 1-component vectors. Be sure that this is indeed working.
Here is the code I used to test your functions. I quickly implemented a simple vec class and adapted your functions to this type :
#include <iostream>
#include <vector>
#include <math.h>
#include <numeric>
#include <stdexcept>
class vec {
public:
int vsize;
std::vector<float> vals;
vec(int s) : vsize(s){
vals = std::vector<float>(vsize, 0.0f);
}
};
void print_vec(vec& v){
for(unsigned i = 0; i < v.vsize; i++){
std::cout << v.vals[i] << " ";
}
std::cout << std::endl;
}
vec normalize(const vec& vs) {
vec fres(vs.vsize);
float mod = 0.0f;
for (unsigned i = 0; i < vs.vsize; ++i) {
mod += vs.vals[i] * vs.vals[i];
}
float mag = sqrt(mod);
if (mag == 0.0f) {
throw std::logic_error("In normalize the input vector is a zero vector");
}
for (unsigned i = 0; i < vs.vsize; ++i) {
fres.vals[i] = vs.vals[i] / mag;
}
return fres;
}
float length(const vec& vs) {
float fres = 0;
for (unsigned it = 0; it != vs.vsize; it++) {
fres += vs.vals[it] * vs.vals[it];
}
return sqrt(fres);
}
float dot(const vec& vs1, const vec& vs2) {
return std::inner_product(vs1.vals.begin(), vs1.vals.end(), vs2.vals.begin(), 0.0f);
}
In main I simply tested some hardcoded vectors and printed the results of normalize, length and dot. I ran the code on https://www.onlinegdb.com/online_c++_compiler
the statement below the function calling is not executed. i am at a loss, why this is so? could someone please clarify. Please consider the code below :
#include<iostream>
#include<cmath>
using namespace std;
class Matrix
{
private:
int row,col;
double *values;
public:
Matrix();
Matrix(int r, int c, double* x);
void setdim(int m, int n){row=m;col=n;}
int getrowdim() const {return row;}
int getcoldim() const {return col;}
void set_values(int i, double x);
double get_value(int i) const;
friend Matrix operator+(const Matrix &A, const Matrix &B);
};
Matrix::Matrix()
{
this->row = 0;
this->col = 0;
this->values = NULL;
}
Matrix::Matrix(int r, int c, double* x)
{
this->row = r;
this->col = c;
this->values = new double[r*c];
for (int i =0;i<r*c;i++)
{
cout<<"Enter value ["<<i<<"] ";
cin>>this->values[i];
}
}
void Matrix::set_values(int k, double x)
{
this->values[k] = x;
}
Matrix operator+(const Matrix &A, const Matrix &B)
{
int rowa = A.getrowdim();
int cola = A.getcoldim();
int rowb = B.getrowdim();
int colb = B.getcoldim();
if(rowa == rowb && cola == colb)
{
Matrix C;
C.setdim(rowa, colb);
for(int i =0; i< rowa*cola ; i++)
{
cout<<"i = "<<i<<", A.get_value = "<<A.get_value(i)<<", B.get_value = "<<B.get_value(i)<<endl;
double m = A.get_value(i) + B.get_value(i);
cout<<m<<endl;
C.set_values(i, m );
cout<<"Returned from C.set_values()"<<endl;
// THIS STATEMENT DOES NOT GET PRINTED. PLEASE TELL THE REASON // WHY. I SUSPECT THE ERROR IS HERE
}
return C;
}
else
{
cout<<"Invalid Operation";
return A;
}
}
double Matrix::get_value(int i) const
{
return this->values[i];
}
int main()
{
Matrix A(2,2,NULL);
Matrix B(2,2,NULL);
Matrix C;
C = A+B;
return 0;
}
The statement - Returned from C.set_values() does not get printed at all .
Could someone help clarify why this is the case? Thanks a lot for the help!
Here:
Matrix C; // (1)
C.setdim(rowa, colb); // (2)
for(int i =0; i< rowa*cola ; i++)
{
cout<<"i = "<<i<<", A.get_value = "<<A.get_value(i)<<", B.get_value = "<<B.get_value(i)<<endl;
double m = A.get_value(i) + B.get_value(i);
cout<<m<<endl;
C.set_values(i, m ); // (3)
You default construct a Matrix (1). The default constructor just sets the member values to NULL. Then you adjust the size members in (2), but values is still NULL. Then, in (3) you call set_values which tries to access array elements, but there is no array.
The problem is that your Matrix has a raw owning pointer as member. When a class manages a resource you must follow the rule of 3/5. If you don't, the class is broken. Managing a resource is not trivial, and following the rule of 3/5 is just the bare minimum.
The simpler alternative that you should strive for is the rule of 0. For a class that does not manage a resource, the compiler generated special members are just right. If you replace the raw pointer member with a std::vector<double> then you do not need to worry about copying, assignment or destruction, because the compiler will generate the required methods for you.
I kinda trying to make a class method here that is able to assign a rvalue with "operator =" to an array, which requires also the input of the indexes. For now the code looks like this:
#include <iostream>
using namespace std;
class Matrix
{
public:
int nz,nx;
float *elements;
int size() {return nz * nx;} // Return size of the matrix
float idx(int,int);
void idxAssign(int,int) operator = (float);
void allocate() {elements = new float[size()];}
};
void Matrix::idxAssign (int i,int j) operator = (float &rvalue)
{
elements[j * nz + i] = rvalue;
}
float Matrix::idx (int i, int j)
{
// Return a element of the matrix from the index
return elements[j * nz + i];
}
void dotprodMatrix(Matrix A, Matrix B)
{
if(A.size() == B.size()){
for(int i=0; i<A.size; i++){
A.idxAssign(i,j) = A.idx(i,j) + B.idx(i,j);
}
}
}
int main()
{
Matrix A;
A.nz = 32;
A.nx = 32;
Matrix B;
B.nz = 32;
B.nx = 32;
// Method to allocate both matrices in the cpu
A.allocate();
B.allocate();
// Fill up
for(int i=0; i<B.size(); i++)
{
A.elements[i] = 2.0;
B.elements[i] = 5.0;
}
dotprodMatrix(A, B);
// Print results
for(int i=0; i<A.nz; i++)
{
for(int j=0; j<A.nx; j++)
{
cout<<A.idx(i,j)<<" ";
}
cout<<endl;
}
delete A.elements;
delete B.elements;
return 0;
}
While executing, the compiler says that at declares that it expected a ";" right after void idxAssign(int,int). I am not very knowledgeable about c++ classes, operators and what not, so please forgive the quality of my code. I spent a lot of hours trying to look for a solution until I finally decided to ask for help here. So thanks if you can help me a little bit!
Thx in advance!
void idxAssign(int,int) operator = (float) is not valid C++. void idxAssign(int,int) is one function declaration and operator = (float) is another ill-formed function (operator overload) declaration.
Possibly what your looking for is something like float& idxAssign(int, int).
float& Matrix::idxAssign (int i,int j)
{
return elements[j * nz + i];
}
Now you can assign values using this syntax,
Matrix mat;
...
mat.idxAssign(0, 0) = 10;
What you have here is a non-const getter. And since we aren't actually assigning anything, we can rename it,
float& Matrix::get(int i, int j)
{
return elements[j * nz + i];
}
Now the API is much more clear for someone whos reading this. Usually assignments using functions are done using some syntax like: void Matrix::Assign(int i, int j, float value); but using getters to return a reference and then assigning it is pretty common.
I am aware there exists a C++ function template (std::inner_product), but I want to try writing my own. Here's some code I found but it runs in the main function:
#include <iostream>
using namespace std;
int main(){
float vectorA[3], vectorB[3], scalar=0.0;
int i;
// Get input vectors from user.
cout << "Enter elements of first vector: " << endl;
for(i=0;i<3;i++)
{
cin >> vectorA[i];
}
cout << "Enter elements of second vector: " << endl;
for(i=0;i<3;i++)
{
cin >> vectorB[i];
}
// Calculate scalar product.
for(i=0;i<3;i++)
{
scalar = scalar + (vectorA[i] * vectorB[i]);
}
// Output result.
cout << "The scalar product is " << scalar << endl;
return 0;
}
Next, I want to write this into a separate reusable function that I can call from my main loop. This is the best I could come up with.
float scalarProduct(float a1, float a2, float a3, float b1, float b2, float b3) {
float vectorA[3], vectorB[3], scalar;
vectorA[0]=a1;
vectorA[1]=a2;
vectorA[2]=a3;
vectorB[0]=b1;
vectorB[1]=b2;
vectorB[2]=b3;
for(int i=0;i<3;i++) // Calculate scalar product.
{
scalar = scalar + (vectorA[i] * vectorB[i]);
}
return scalar;
}
int main() {
cout << scalarProduct(1,2,3,4,5,6);
}
So my questions are:
How can I pass an array into this function? There must be a better way than having six parameters but I can't figure out how.
When I run the program in Xcode, I get the warning 'Variable scalar may be uninitialised when used here' at the line
scalar = scalar + (vectorA[i] * vectorB[i]);
The program still runs and computes the correct answer but how can I make this warning go away?
Question
How can I pass an array into this function? There must be a better way than having six parameters but I can't figure out how.
Change the function to accept two arrays as argument. For the sake of safety, also pass the number of elements in the array.
float scalarProduct(float a[], float b[], size_t num);
Change the function to accept two std:vectors as argument.
float scalarProduct(std::vector<float> const& a, std::vector<float> const& b);
Change the function to accept two std:arrays as argument.
float scalarProduct(std::array<float, 3> const& a, std::array<float, 3> const& b);
In all of these cases, you can access the elements of the collection using the array syntax.
float scalarProduct(std::array<float, 3> const& a, std::array<float, 3> const& b)
{
// Initialize scalar to 0
float scalar = 0.0f;
for(int i=0;i<3;i++) // Calculate scalar product.
{
scalar = scalar + (a[i] * b[i]);
}
return scalar;
}
The implementations will be a little different if you use the other signatures but not too different.
Question
When I run the program in Xcode, I get the warning 'Variable scalar may be uninitialised when used here' at the line
I have already added the line to initialize scalar. Without that, the initial value of scalar is not predictable. Also, accessing the value of an uninitialized variable is cause of undefined behavior.
How can I pass an array into this function? There must be a better way than having six parameters but I can't figure out how.quote
To pass an array into your function, simply do:
float scalarProduct(float arr[6])
In your main(), it will look like:
float array[6] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0};
cout << scalarProduct(array);
From there you can use your array like:
vectorA[0]=arr[0];
vectorA[1]=arr[1];
vectorA[2]=arr[2];
vectorB[0]=arr[3];
vectorB[1]=arr[4];
vectorB[2]=arr[5];
When I run the program in Xcode, I get the warning 'Variable scalar may be uninitialised when used here' at the line
Maybe try and initialize scalar with an initial value:
float scalar = 0.0;
Just have your function take in a reference to a vector (or array as stated by Hayden). A vector is better as you don't have to hard-code the size of the vector.
Also, it is useful to have a template function for this case.
#include <iostream>
#include <vector>
using namespace std;
template <typename T>
T scalarProduct(const vector<T>& a, const vector<T>& b)
{
// Check that the size of a and b match here.
// If not, do what you deem is necessary.
T product = 0; // Not initializing variable is cause of your warning.
for (int i = 0; i < a.size(); i++)
product += a[i] * b[i];
return product;
}
int main(void)
{
// Compile for c++ 11
// vector<float> a = {1.0, 2.0, 3.0};
// vector<float> b = {1, 1, 1};
// Else
vector<float> a;
vector<float> b;
a.push_back(1);
a.push_back(2);
a.push_back(3);
b.push_back(1);
b.push_back(1);
b.push_back(1);
cout << scalarProduct<float>(a, b) << endl;
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
int width = 100;
int height = 100;
float cam[] = {-1.1,-1.0,1.2};
float D[] = {0.2,0.2,-0.2};
float U[] = {0.0,1.0,0.0};
float* cross(float* v1,float* v2)
{
float el1[] = {(v1[1]*v2[2]-v1[2]*v2[1]),(v1[2]*v2[0]-v1[0]*v2[2]),(v1[0]*v2[1]-v1[1]*v2[0])};
return el1;
}
float* neg3(float* v)
{
float arr[3];
for(int i=0;i<3;i++)
arr[i] = 0.0-(v[i]);
return arr;
}
/*
float* cam_space(float* p)
{
float* e1 = cross(D,U);
float* e2 = cross(D,cross(U,D));
float* e3_n = D;
float ar[4];
ar[0] = e1[0]*p[0]+e1[1]*p[1]+e1[2]*p[2];
ar[1] = e2[0]*p[0]+e2[1]*p[1]+e2[2]*p[2];
ar[2] = -(e3_n[0]*p[0]+e3_n[1]*p[1]+e3_n[2]*p[2]);
ar[3] = p[3];
return ar;
}
*/
float* translate(float* p,float* v)
{
float arr1[3];
for(int i=0;i<=2;i++)
arr1[i] = p[i] + v[i];
return arr1;
}
int main()
{
float* poi;
poi = cam; //undo later
float* nc;
nc = neg3(cam);
cout<<" "<<nc[0]<<" "<<nc[1]<<" "<<nc[2]<<endl;
float arbit[3] = {0.1,0.1,0.1};
float* temp1;
temp1 = translate(poi,arbit);
//float* temp2;
//temp2 = cam_space(temp);
cout<<" "<<nc[0]<<" "<<nc[1]<<" "<<nc[2]<<endl;
cout<<" "<<poi[0]<<" "<<poi[1]<<" "<<poi[2]<<endl;
cout<<" "<<temp1[0]<<" "<<temp1[1]<<" "<<temp1[2]<<endl;
return 0;
}
As you can see, I am outputting nc twice. But both the values differ. The second time nc is displayed, it actually shows the temp1 value, and temp1 actually shows garbage values.
Any help?
float* translate(float* p,float* v)
{
float arr1[3];
for(int i=0;i<=2;i++)
arr1[i] = p[i] + v[i];
return arr1;
}// arr1 ceases to exist from this point.
You are returning the reference of a local variable, arr1. It resides on stack and gets de-allocated on the return of function call. But you are holding a reference to it which is yielding you garbage values. Instead new new[] arr1 and return it. Remember to delete[] it when you are done.
You are returning pointers to local variables left right and centre. Those variables go out of scope at the end of the function body, and the result is undefined behaviour.
A nice way of handling array-modifying functions is to pass the array as a parameter:
void modify_me(float arr[]) // or `modify_me(float * arr)`, same thing
{
arr[0] = 0.5;
arr[1] = -2.25;
}
int main()
{
float myarray[2];
modify_me(myarray); // now myarray[0] == 0.5, etc.
// ...
}
Since you're in C++, you could even use template magic:
template <unsigned int N>
void modify_me(float (&arr)[N])
{
static_assert(N == 3, "You're doing it wrong!"); // C++11 feature
arr[0] = /* ... */
}
Now you get a compile-time error if you try to call this with anything that's not an automatic array of size 3.
Instead of returning pointers to local variables you should return values.
Consider this:
struct V3 { float data[3]; }
V3 neg3(V3 v)
{
for(int i=0;i<3;i++)
v.data[i] = -v.data[i];
return v;
}
translate() returns a local pointer (converted from array type). So what temp1 is referring to, doesn't exist after the function translate() returns.
Same is the case with neg3() also.
If you're using C++, then std::vector<float> will solve all such problem.
You could write this:
std::vector<float> translate(const std::vector<float> & p, const std::vector<float> & v)
{
std::vector<float> vf(3);
for(int i=0;i <3;i++)
vf[i] = p[i] + v[i];
return vf; //semantically, it returns a copy of the local object.
}
Similarly, use std::vector whereever you're using float[3]. And don't use global variables.