Loss of trig precision [closed] - c++

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
For a gravity simulation, I need to find the angle between two objects so I can apply the force. However, I am losing precision and I don't know where. Here is the minimal code that can reproduce the issue.
#include<iostream>
using namespace std;
struct Vector2f
{
float x, y;
};
Vector2f operator-(Vector2f& left, Vector2f& right)
{
return Vector2f{ left.x - right.x, left.y - right.y };
}
double pi = 3.141592653589793238463;
double angle(Vector2f& one, Vector2f& two)
{
Vector2f normal(one - two);
if (!normal.x && !normal.y)
{
return 0.0f;
}
float theta = -(atan((double)(normal.y / normal.x)) - pi / 2);
if (normal.x < 0)
{
return (theta - pi / 2);
}
else
{
return (theta + pi / 2);
}
}
int main()
{
Vector2f one{ 0,0 };
for (int i = -100; i <= 100; i += 100)
{
for (int j = -100; j <= 100; j += 100)
{
Vector2f two{ i,j };
cout << i << ", " << j << endl;
cout << "sin:\t" << sin(angle(one, two)) * 180.0f / pi << endl;
cout << "cos:\t" << cos(angle(one, two)) * 180.0f / pi << endl;
cout << endl;
}
}
return 0;
}
For instance, where I should be getting 45 (comparing (0,0) with (100, -100) due to the grid), I am getting answers like 40.5142 and 57.2958. I understand if the precision lost were less than a degree, but this is ridiculous. I want all the output from this code to be multiples of 45, basically for those without trig knowledge. Changing the datatype of Vector2f to double does not affect the end result. Could you help me find the issue?
I am using VS 2015, but it happens similarly on VS 2013.

sin(angle(one, two)) * 180.0f / pi doesn't make sense.
it should be
sin(angle(one, two))
And you may print your angle
std::cout << angle(one, two)) * 180.0f / pi << " degree\n";
std::cout << angle(one, two)) << " radian\n";

Related

On line 138 of my code I keep getting an "expected a ';'" error (code E0065). I'm using Visual Studio 2019 Community Edition [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 1 year ago.
Improve this question
I've included all the code I've written so far, because I wasn't sure if anyone wanted to try to replicate the error. It might be too much, but I didn't want to leave anything out in case that's what was causing the error.
#include
using namespace std;
#include "olcNoiseMaker.h"
The line above shows what library I'm using, here's a link to the Github page where I got it from: https://github.com/OneLoneCoder/synth
//Converts frequency (Hz) to angular velocity
double w(double dHertz)
{
return dHertz * 2.0 * PI;
}
atomic<double> dFrequencyOutput = 0.0;
double dOctaveBaseFrequency = 220.0; //A3
double d12thRootOf2 = pow(2.0, 1.0 / 12.0);
sEnvelopeADSR envelope;
double osc(double dHertz, double dTime, int nType)
{
switch (nType)
{
case 0: // Sine Wave
return sin(w(dHertz) * dTime);
case 1: // Square Wave
return sin(w(dHertz) * dTime) > 0 ? 1.0 : -1.0;
case 2: // Triangle Wave
return asin(sin(w(dHertz) * dTime)) * 2.0 / PI;
case 3: // Saw Wave (analogue / warm / slow)
{
double dOutput = 0.0;
for (double n = 1.0; n < 100.0; n++)
dOutput += (sin(n * w(dHertz) * dTime)) / n;
return dOutput * (2.0 / PI);
}
case 4: // Saw Wave (optimised / harsh / fast)
return (2.0 / PI) * (dHertz * PI * fmod(dTime, 1.0 / dHertz) - (PI / 2.0));
case 5: // Psuedo Random Noise
return 2.0 * ((double)rand() / (double)RAND_MAX) - 1.0;
default:
return 0.0;
}
}
struct sEnvelopeADSR
{
double dAttackTime;
double dDecayTime;
double dReleaseTime;
double dSustainAmplitude;
double dStartAmplitude;
double dTriggerOnTime;
double dTriggerOffTime;
bool bNoteOn;
sEnvelopeADSR()
{
dAttackTime = 0.01;
dDecayTime = 0.01;
dStartAmplitude = 1.0;
dSustainAmplitude = 0.8;
dReleaseTime = 0.02;
dTriggerOnTime = 0.0;
dTriggerOffTime = 0.0;
bNoteOn = false;
}
// Call when key is pressed
void NoteOn(double dTimeOn)
{
dTriggerOnTime = dTimeOn;
bNoteOn = true;
}
// Call when key is released
void NoteOff(double dTimeOff)
{
dTriggerOffTime = dTimeOff;
bNoteOn = false;
}
// Get the correct Amplitude at the requested point in time
double GetAmplitude(double dTime)
{
double dAmplitude = 0.0;
double dLifeTime = dTime - dTriggerOnTime;
if (bNoteOn)
{
// ADS
// Attack
if (dLifeTime <= dAttackTime) {
dAmplitude = (dLifeTime / dAttackTime) * dStartAmplitude;
}
// Decay
if (dLifeTime > dAttackTime && dLifeTime <= (dAttackTime + dDecayTime)) {
dAmplitude = ((dLifeTime - dAttackTime) / dDecayTime) * (dSustainAmplitude - dStartAmplitude) + dStartAmplitude;
}
// Sustain
if (dLifeTime > (dAttackTime + dDecayTime))
{
dAmplitude = dSustainAmplitude;
}
else
{
// Release
dAmplitude = ((dTime - dTriggerOffTime) / dReleaseTime) * (0.0 - dSustainAmplitude) + dSustainAmplitude;
}
if (dAmplitude <= 0.0001)
{
dAmplitude = 0;
}
return dAmplitude;
}
}
}
// Function used by olcNoiseMaker to generate sound
// Returns amplitude(-1.0 to + 1.0) as a function of time
double MakeNoise(double dTime)
The line above is where I'm having the problem. In Visual Studio 2019 Community Edition, I get an error saying that a semicolon is needed somewhere before it. I don't understand the issue
{
}
int main()
{
wcout << "onelonecoder.com - Synthesizer Part 1" << endl;
// Get all sound behaviors
vector<wstring> devices = olcNoiseMaker<short>::Enumerate();
//Display findings
for (auto d : devices) wcout << "Found Output Device:" << d << endl;
// Create sound machine!!
olcNoiseMaker<short> sound(devices[0], 44100, 1, 8, 512);
// Link noise function with sound machine
sound.SetUserFunction(MakeNoise);
while (1)
{
//Add a keyboard like a piano
bool bKeyPressed = false;
for (int k = 0; k < 15; k++)
{
if (GetAsyncKeyState((unsigned char)("ZSXCFVGBNJMK\xbcL\xbe\xbf"[k])) & 0x8000)
{
dFrequencyOutput = dOctaveBaseFrequency * pow(d12thRootOf2, k);
envelope.bNoteOn(sound.GetTime());
bKeyPressed = true;
}
}
if (!bKeyPressed)
{
envelope.bNoteOff(sound.GetTime());
}
return 0;
}
}
The end of a struct or class definition needs a ; after it, even though it ends with a }. This is one of those mistakes you usually only make once.
The reason for this is so that you can simultaneously declare the struct/class and create a variable of that type, by putting the variable name before the ;. This was used more often in C, you don't see it so much in C++.
You are missing the semi-colon after that final } of your struct osc definition.

Why doesn't my Gradient descent algorithm converge? (For Logistic Regression)

I have an assignment which says to implement logistic regression in c++ using gradient descent. Part of the assignment is to make the gradient descent stop when the magnitude of the gradient is below 10e-07.
I have to minimize: //chart.googleapis.com/chart?cht=tx&chl=L(w)%20%3D%20%5Cfrac%7B1%7D%7BN%7D%5Csum%20log(1%20%2B%20exp(-y_%7Bi%7Dw%5E%7BT%7Dx_%7Bi%7D))
However my gradient descent keeps stopping due to max iterations surpassed. I have tried with various max iteration thresholds, and they all max out. I think there is something wrong with my code, since logistic regression is supposedly an easy task for gradient descent due to the concave nature of its cost function, the gradient descent should easily find the minium.
I am using the armadillo library for matrices and vectors.
#include "armadillo.hpp"
using namespace arma;
double Log_Likelihood(Mat<double>& x, Mat<int>& y, Mat<double>& w)
{
Mat<double> L;
double L_sum = 0;
for (int i = 0; i < x.n_rows; i++)
{
L = log(1 + exp(-y[i] * w * x.row(i).t() ));
L_sum += as_scalar(L);
}
return L_sum / x.n_rows;
}
Mat<double> Gradient(Mat<double>& x, Mat<int>& y, Mat<double>& w)
{
Mat<double> grad(1, x.n_cols);
for (int i = 0; i < x.n_rows; i++)
{
grad = grad + (y[i] * (1 / (1 + exp(y[i] * w * x.row(i).t()))) * x.row(i));
}
return -grad / x.n_rows;
}
void fit(Mat<double>& x, Mat<int>& y, double alpha = 0.05, double threshold = pow(10, -7), int maxiter = 10000)
{
w.set_size(1, x.n_cols);
w = x.row(0);
int iter = 0;
double log_like = 0;
while (true)
{
log_like = Log_Likelihood(x, y, w);
if (iter % 1000 == 0)
{
std::cout << "Iter: " << iter << " -Log likelihood = " << log_like << " ||dL/dw|| = " << norm( Gradient(x, y, w), 2) << std::endl;
}
iter++;
if ( norm( Gradient(x, y, w), 2) < threshold)
{
std::cout << "Magnitude of gradient below threshold." << std::endl;
break;
}
if (iter == maxiter)
{
std::cout << "Max iterations surpassed." << std::endl;
break;
}
w = w - (alpha * Gradient(x, y, w));
}
}
I want the gradient descent to stop because the magnitude of the gradient falls below 10e-07.
My labels are {1, -1}.
Verify that your loglikelihood is increasing towards convergence by recording or plotting the values at every iteration, and also check that the norm of the gradient is going towards 0. You should be doing gradient ascent, so add the gradient instead of subtracting it. If the norm of the gradient consistently increases it means you are not going in a direction towards the optimum. If on the other hand, the norm of the gradient "jumps around" but doesn't go to 0, then you should reduce your stepsize/learning rate alpha and try again.
Plotting and analyzing these values will be helpful to debug and analyze your algorithm.

C++ nan keeps coming up with integration [closed]

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 7 years ago.
Improve this question
I am trying to get a integration program running but I keep getting the nan when computing. i have no idea whats wrong with my code.
#include <iostream>
#include <cmath>
using namespace std;
int main(){
cout << "For integration up \n";
for (int z=0; z<=5; z++){
int i=1;
float nathan [6] = {pow(10,2), pow(10,3), pow(10,4), pow(10,5),pow(10,6), pow(10,7)};
int h= nathan[z];
int n=0;
double x= (h-i)/h;
double y= (h-i)/h;
double t= 0;
while(n <= h){
if(n == 0){
t += (x/3)*(1/y);
}else if(n==h){
t+= (x/3)*(1/y);
}else if(n%2 ==1){
t+= (4*x/3)*(1/y);
}else{t+= (2*x/3)*(1/y);
}
y= x+y;
n = n+1;
}
cout << "The integration of 1/x for N = "<< nathan[z] <<" is equal to " << t << endl;
}
}
can someone please help me out with this...
With
int i = 1;
int h = nathan[z];
The term
(h - i) / h
invokes integer division, and since both h - i and h are positive and h - i is smaller than h, this results in an integer zero.
After
double x= (h-i)/h;
double y= (h-i)/h;
then, both x and y are zero, and from there all terms in
if(n == 0){
t += (x / 3) * (1 / y);
} else if(n == h) {
t += (x / 3) * (1 / y);
} else if(n%2 == 1) {
t += (4 * x / 3) * (1 / y);
} else {
t += (2 * x / 3) * (1 / y);
}
result in zero times infinity, which is not a number (i.e., nan). Once you're down that sinkhole, you're never coming back.
Make h a double to avoid this.
Side note: Please, please, please learn to properly indent your code. Your eventual coworkers are going to skin you alive if you don't, and they'll be right.
it s because x and y are always 0 in your code because h is int. When you do (h-i)/h, the compiler assumes that (h-i) is int and h is also int so it also assumes that the result of the ratio is int. This ratio is between 0 and 1 so when you only represent it with an int, it is just 0. And only after that the compiler cast this value to a double, which then remains 0.
Try with :
double x= (h-i)/(double)h;
double y= (h-i)/(double)h;

C++ changing instance variables [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I am trying to write a program to calculate an n-body problem. I have run into a problem trying to change my code so it would be easily adaptable for any number of bodies. There seems to be a problem with the function corr(), the changes made to some variables of the instances of the class particle in this function seem to get lost after the function corr() has been used. How do i solve this problem?
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <fstream>
#define h 1000.0
#define G 6.67384*pow(10.0,-11)
using namespace std;
class particle{
public:
double kx1,kx2,kx3,kx4, kv1, kv2, kv3, kv4;
double ky1, ky2, ky3, ky4, kvy1, kvy2, kvy3, kvy4;
double x,y,vx,vy,m;
double dist(particle aap){
double dx = x - aap.x;
double dy = y - aap.y;
return sqrt(pow(dx,2.0)+pow(dy,2.0));
}
double g(double x1, double y1,particle aap){
return G*aap.m*(aap.x-x1)/pow(dist(aap),3.0);
}
double p(double x1, double y1, particle aap){
return G*aap.m*(aap.y-y1)/pow(dist(aap),3.0);
}
void update(){ //zet het object 1 stap vooruit
x = x + (1/6.0)*(kx1+2*kx2+2*kx3+kx4);
vx = vx + (1/6.0)*(kv1+2*kv2+2*kv3+kv4);
y = y + (1/6.0)*(ky1+2*ky2+2*ky3+ky4);
vy = vy + (1/6.0)*(kvy1+2*kvy2+2*kvy3+kvy4);
}
void create(double x1, double y1, double vx1, double vy1, double m1){
x = x1;
y = y1;
vx = vx1;
vy = vy1;
m =m1;
}
bool operator ==(particle &other){
if(x == other.x && y == other.y && vx == other.vx && vy == other.vy){
return true;
}
}
};
particle zon, maan, aarde;
void set(){
zon.create(1, 1, -2, 1, 2*pow(10.0,30));
aarde.create(1.5*pow(10.0,11), 0, 2, 29780, 6*pow(10.0,24));
maan.create(aarde.x + 1, aarde .y + 3.844399*pow(10.0,8), aarde.vx + -1022.0, aarde.vy + 1, 7.3347*pow(10.0,22));
}
double xforce(double x1, double y1, particle aap){ //kracht in de x-richting
particle bodies[] = {zon, aarde, maan};
double fx;
for (int i = 0; i < 3; i++){
if (bodies[i].x == aap.x && bodies[i].y == aap.y && bodies[i].vx == aap.vx && bodies[i].vy == aap.vy ){;}
else{
fx += aap.g(x1,y1,bodies[i]);
}
}
return fx;
}
double yforce(double x1, double y1, particle aap){ //kracht in de y-richting
particle bodies[] = {zon, aarde, maan};
double fy;
for (int i = 0; i <= 3; i++){
if (bodies[i].x == aap.x && bodies[i].y == aap.y && bodies[i].vx == aap.vx && bodies[i].vy == aap.vy) {;}
else{
fy += aap.p(x1,y1,bodies[i]);
}
}
return fy;
}
void corr(particle body){
body.kx1 = h*body.vx;
body.kv1 = h*xforce(body.x, body.y, body);
body.ky1 = h*body.vy;
body.kvy1 =h*yforce(body.x, body.y, body);
body.kx2 = h*(body.vx + 0.5*body.kv1);
body.kv2 = h*xforce(body.x + 0.5*body.kx1, body.y + 0.5*body.ky1, body);
body.ky2 = h*(body.vy + 0.5*body.kvy1);
body.kvy2 = h*yforce(body.x + 0.5*body.kx1, body.y + 0.5*body.ky1, body);
body.kx3 = h*(body.vx+ 0.5*body.kv2);
body.kv3 = h*xforce(body.x + 0.5*body.kx2, body.y + 0.5*body.ky2, body);
body.ky3 = h*(body.vy+ 0.5*body.kvy2);
body.kvy3 = h*yforce(body.x + 0.5*body.kx2, body.y + 0.5*body.ky2,body);
body.kx4 = h*(body.vx+body.kv3);
body.kv4 = h*xforce(body.x+ body.kx3, body.y + body.ky3, body);
body.ky4 = h*(body.vy + body.kvy3);
body.kvy4 = h*yforce(body.x + body.kx3, body.y + body.ky3, body);
}
void bereken(){
set();
ofstream file;
file.open("3body.txt");
for(int i =0; i <=30000; i++){
corr(maan);
corr(zon);
corr(aarde);
zon.update();
aarde.update();
maan.update();
file << i*h <<" "<< zon.x << " "<< zon.y << " "<< zon.vx<< " "<< zon.vy <<" "<< aarde.x << " " << aarde.y <<" "<< aarde.vx <<" " << aarde.vy <<" "<< maan.x<<" "<<maan.y<<"\n";
}
file.close();
}
int main()
{
set();
bereken();
system("pause");
return 0;
}
Just use references:
void corr(particle& body)
The same fix has to be applied in other places. What you currently have is a code that COPIES your object, does some calculations on it and then just deletes this temporary object... By using reference (&) you effectively "share" the object between the caller and callee.
In your class methods you should also use references for passing this object, but this time for efficiency reasons - it's simple to pass reference (usually the same as pointer), but copying this huge object takes time.
The suggestion made by Freddie Chopin worked and fixed the function corr(). Now however i came across the fact that the functions xforce() and yforce() don't work properly. They are supposed to return the total force on a certain particle, which they do in the first step, but after that they seem to be returning wrong values. Anyone has an idea why that happens?

Need floating point precision, GUI gui uses int

I have a flow layout. Inside it I have about 900 tables. Each table is stacked one on top of the other. I have a slider which resizes them and thus causes the flow layout to resize too.
The problem is, the tables should be linearly resizing. Their base size is 200x200. So when scale = 1.0, the w and h of the tables is 200.
I resize by a fixed amount each time making them 4% bigger each time. This means I would expect them to grow by 8 pixels each time. What happens is, every few resizes, the tables grow by 9 pixels. I use doubles everywhere. I have tried rounding, floor and ceil but the problem persists. What could I do so that they always grow by the correct amount?
void LobbyTableManager::changeTableScale( double scale )
{
setTableScale(scale);
}
void LobbyTableManager::setTableScale( double scale )
{
scale += 0.3;
scale *= 2.0;
std::cout << scale << std::endl;
agui::Gui* gotGui = getGui();
float scrollRel = m_vScroll->getRelativeValue();
setScale(scale);
rescaleTables();
resizeFlow();
...
double LobbyTableManager::getTableScale() const
{
return (getInnerWidth() / 700.0) * getScale();
}
void LobbyFilterManager::valueChanged( agui::Slider* source,int val )
{
if(source == m_magnifySlider)
{
DISPATCH_LOBBY_EVENT
{
(*it)->changeTableScale((double)val / source->getRange());
}
}
}
void LobbyTableManager::renderBG( GraphicsContext* g, agui::Rectangle& absRect, agui::Rectangle& childRect )
{
int cx, cy, cw, ch;
g->getClippingRect(cx,cy,cw,ch);
g->setClippingRect(absRect.getX(),absRect.getY(),absRect.getWidth(),absRect.getHeight());
float scale = 0.35f;
int w = m_bgSprite->getWidth() * getTableScale() * scale;
int h = m_bgSprite->getHeight() * getTableScale() * scale;
int numX = ceil(absRect.getWidth() / (float)w) + 2;
int numY = ceil(absRect.getHeight() / (float)h) + 2;
float offsetX = m_activeTables[0]->getLocation().getX() - w;
float offsetY = m_activeTables[0]->getLocation().getY() - h;
int startY = childRect.getY() + 1;
if(moo)
{
std::cout << "TS: " << getTableScale() << " Scr: " << m_vScroll->getValue() << " LOC: " << childRect.getY() << " H: " << h << std::endl;
}
if(moo)
{
std::cout << "S=" << startY << ",";
}
int numAttempts = 0;
while(startY + h < absRect.getY() && numAttempts < 1000)
{
startY += h;
if(moo)
{
std::cout << startY << ",";
}
numAttempts++;
}
if(moo)
{
std::cout << "\n";
moo = false;
}
g->holdDrawing();
for(int i = 0; i < numX; ++i)
{
for(int j = 0; j < numY; ++j)
{
g->drawScaledSprite(m_bgSprite,0,0,m_bgSprite->getWidth(),m_bgSprite->getHeight(),
absRect.getX() + (i * w) + (offsetX),absRect.getY() + (j * h) + startY,w,h,0);
}
}
g->unholdDrawing();
g->setClippingRect(cx,cy,cw,ch);
}
void LobbyTable::rescale( double scale )
{
setScale(scale);
float os = getObjectScale();
double x = m_baseHeight * os;
if((int)(x + 0.5) > (int)x)
{
x++;
}
int oldH = getHeight();
setSize(m_baseWidth * os, floor(x));
...
I added the related code. The slider sends a value changed which is multiplied to get a 4 percent increase (or 8 percent if slider moves 2 values etc...) then the tables are rescaled with this.
The first 3 are when the table size increased by 9, the 4th time it increased by 8px. But the scale factor increases by 0.04 each time.
Why is the 4th time inconsistant?
the pattern seems like 8,8,8,9,9,9,8,8,8,9,9,9...
It increases by 1 pixel more for a few and then decreases by 1 ten increases by 1 etc, thats my issue...
I still don't see the "add 4%" code there (in a form I can understand, anyway), but from your description I think I see the problem: adding 4% twice is not adding 8%. It is adding 8.16% (1.04 * 1.04 == 1.0816). Do that a few more times and you'll start getting 9 pixel jumps. Do it a lot more times and your jumps will get much bigger (they will be 16 pixel jumps when the size gets up to 400x400). Which, IMHO is how I like my scaling to happen.