Migration from Win to Linux

A

Alex Neumann

Hi,

I have written a C++ program, very small, under Windows.
Normally I work under Linux, but I had to use a Windows machine over the
weekend.
The program does not use anything special, only

#include <iostream>
#include <stdlib.h>
#include "math.h"

I have copied the .cpp files from my Windows machine to my Linux machine
now.
Compiling with g++ 3.3.2-r5 under Gentoo works fine, but when I execute, the
results I get are just wrong, totally wrong. So this is nothing due to
rounding or so, there is no slight difference, it is just totally wrong.

I am not a C++ guru since I usually code in other languages.

What can be the reason for that ?

Since it is few lines of code only (< 200 lines) I can also post it if that
helps...

Thanks !
 
H

Howard

Since it is few lines of code only (< 200 lines) I can also post it if that
helps...

You'll have to post *something*, at least! Are we supposed to guess what
the problem is? We don't even know what the correct or incorrect results
are. (To be just a "wee" bit facetious: does it fly around the room singing
"Mammy", instead of sorting your fruits into apples and oranges? :))

More seriously, if you could at least post the relevant parts of your code,
along with an explanation about what is expected and what it actually seen,
that would help us (and you).

-Howard
 
A

Alex Neumann

Howard said:
You'll have to post *something*, at least! Are we supposed to guess what
the problem is? We don't even know what the correct or incorrect results
are. (To be just a "wee" bit facetious: does it fly around the room
singing "Mammy", instead of sorting your fruits into apples and oranges?
:))

More seriously, if you could at least post the relevant parts of your
code, along with an explanation about what is expected and what it
actually seen, that would help us (and you).

-Howard

Ok... here the code first:

---
FILE 1: porcupine.cpp
---
#include <iostream>
#include <stdlib.h>
#include "math.h"
#include "point2D.h"

using namespace std;


// Helper to calculate the normal vector
Point2D norm_vector(Point2D point)
{
return Point2D(-point.y, point.x);
}


// Helper to calculate the norm
float norm(Point2D point)
{
return sqrt( pow(point.x, 2) + pow(point.y, 2) );
}


// Helper to calculate the vectorproduct
float vectorproduct(Point2D point_a, Point2D point_b)
{
return point_a.x * point_b.y - point_a.y * point_b.x;
}


// Helper to calculate the faculty
int faculty(int n)
{
int faculty = 1;

for(n; n>0; n--)
{
faculty = faculty * n;
}

return faculty;
}


// Helper to calculate the binomial
float binomial(int n, int i)
{
return faculty(n) / (faculty(i) * faculty(n-i));
}


// Helper to calculate Bernstein
float bernstein(float t, int n, int i)
{
return binomial(n,i) * pow(t,i) * pow( (1.0-t), (n-i) );
}


// Helper to calculate Bezier
Point2D bezier(float t, int n, Point2D points[])
{
Point2D result;
int i = 0;

for(i; i<=n; i++)
{
result.x += bernstein(t,n,i) * points.x;
result.y += bernstein(t,n,i) * points.y;
}

return result;
}


// Helper to calculate the 1st derivative of a Bezier curve
Point2D bezier_first_derivative(float t, int n, Point2D points[])
{
Point2D result;
int intervallborder_s = 0;
int intervallborder_t = 1;
int i = 0;

for(i; i<=n-1; i++)
{
result.x += bernstein(t,n-1,i) * (points[i+1].x - points.x);
result.y += bernstein(t,n-1,i) * (points[i+1].y - points.y);
}

result.x = result.x * (n / (intervallborder_t - intervallborder_s));
result.y = result.y * (n / (intervallborder_t - intervallborder_s));

return result;
}


// Helper to calculate the 1st derivative of a Bezier curve
Point2D bezier_second_derivative(float t, int n, Point2D points[])
{
Point2D result;
int intervallborder_s = 0;
int intervallborder_t = 1;
int i = 0;

for(i; i<=n-2; i++)
{
result.x += bernstein(t,n-2,i) * (points[i+2].x - 2*points[i+1].x +
points.x);
result.y += bernstein(t,n-2,i) * (points[i+2].y - 2*points[i+1].y +
points.y);
}

result.x = result.x * ( n*(n-1.0) / pow( (double)(intervallborder_t -
intervallborder_s), 2) );
result.y = result.y * ( n*(n-1.0) / pow( (double)(intervallborder_t -
intervallborder_s), 2) );

return result;
}


// Calculate curvature
float curvature(float t, int n, Point2D points[])
{
Point2D bsd = bezier_second_derivative(t,n,points);
Point2D bfd = bezier_first_derivative(t,n,points);

float vp = vectorproduct(bsd, bfd);
float n_bfd = norm(bfd);

return vp / pow(n_bfd, 3);
}


// Calculate curvature vector
Point2D curvature_vector(float t, int n, Point2D points[])
{
Point2D bfd = bezier_first_derivative(t,n,points);

// Calculate normal vector
Point2D norm_bfd = norm_vector(bfd);

// Multiply with curvature
float c = curvature(t,n,points);

Point2D result = Point2D(norm_bfd.x * c, norm_bfd.y * c);

return result;
}

// Main
int main(int argc, char *argv[])
{
// Read the value specifying the degree
int n = atoi(argv[1]);

// Read the corresponding Bezier points
Point2D points[n];
int j = 0;

for (int i=2; i<(2*(n+1))+2; i+=2)
{
points[j] = Point2D(atof(argv), atof(argv[i+1]));
j += 1;
}

// Set a start value for t
float t = 0.0;

// Iterate and print the p_i's and the corresponding curvature values
for (int k=0; k<=20; k++)
{
Point2D pi = bezier(t, n, points);
//Point2D pi = curvature_vector(t, n, points);
//cout << curvature(t,n,points) << endl;
cout << pi.x << "\t\t" << pi.y << endl;
t = t + 0.05;
}

return 0;
}



---
File 2: point2d.h
---
class Point2D
{
public:
float x;
float y;

Point2D();
Point2D(float x, float y);
};

Point2D::point2D()
{
this->x=0;
this->y=0;
}

Point2D::point2D(float x, float y)
{
this->x=x;
this->y=y;
}



This is what I get:

bash-2.05b# ./porcupine 2 0 0 1 1 2 1
13073.4 9.21956e-41
11798.7 8.32063e-41
10589.4 7.4678e-41
9445.51 6.66107e-41
8366.96 5.90059e-41
7353.77 5.18607e-41
6405.95 4.51765e-41
5523.5 3.89533e-41
4706.41 3.31898e-41
3954.7 2.78886e-41
3268.34 2.30486e-41
2647.36 1.86695e-41
2091.74 1.47515e-41
1601.49 1.12945e-41
1176.6 8.29709e-42
817.085 5.76354e-42
522.934 3.68962e-42
294.15 2.07532e-42
130.733 9.23456e-43
32.6832 2.31214e-43
1.85784e-10 1.4013e-45


And this is what is expected (and what I get under windows):

(-0.353553, 0.353553)
(-0.362023, 0.381077)
(-0.369594, 0.41066)
(-0.375993, 0.442345)
(-0.380912, 0.47614)
(-0.384, 0.512)
(-0.384874, 0.54982)
(-0.38312, 0.589416)
(-0.378306, 0.63051)
(-0.369995, 0.672719)
(-0.357771, 0.715542)
(-0.34126, 0.758355)
(-0.320164, 0.800411)
(-0.294299, 0.840854)
(-0.263622, 0.87874)
(-0.228269, 0.913075)
(-0.188573, 0.942866)
(-0.145076, 0.967175)
(-0.0985185, 0.985185)
(-0.0498131, 0.996262)   
(-0, 1)


Any suggestions ?


Thanks.
 
A

Alex Neumann

Alex said:
Howard said:
You'll have to post *something*, at least! Are we supposed to guess what
the problem is? We don't even know what the correct or incorrect results
are. (To be just a "wee" bit facetious: does it fly around the room
singing "Mammy", instead of sorting your fruits into apples and oranges?
:))

More seriously, if you could at least post the relevant parts of your
code, along with an explanation about what is expected and what it
actually seen, that would help us (and you).

-Howard

Ok... here the code first:

---
FILE 1: porcupine.cpp
---
#include <iostream>
#include <stdlib.h>
#include "math.h"
#include "point2D.h"

using namespace std;


// Helper to calculate the normal vector
Point2D norm_vector(Point2D point)
{
return Point2D(-point.y, point.x);
}


// Helper to calculate the norm
float norm(Point2D point)
{
return sqrt( pow(point.x, 2) + pow(point.y, 2) );
}


// Helper to calculate the vectorproduct
float vectorproduct(Point2D point_a, Point2D point_b)
{
return point_a.x * point_b.y - point_a.y * point_b.x;
}


// Helper to calculate the faculty
int faculty(int n)
{
int faculty = 1;

for(n; n>0; n--)
{
faculty = faculty * n;
}

return faculty;
}


// Helper to calculate the binomial
float binomial(int n, int i)
{
return faculty(n) / (faculty(i) * faculty(n-i));
}


// Helper to calculate Bernstein
float bernstein(float t, int n, int i)
{
return binomial(n,i) * pow(t,i) * pow( (1.0-t), (n-i) );
}


// Helper to calculate Bezier
Point2D bezier(float t, int n, Point2D points[])
{
Point2D result;
int i = 0;

for(i; i<=n; i++)
{
result.x += bernstein(t,n,i) * points.x;
result.y += bernstein(t,n,i) * points.y;
}

return result;
}


// Helper to calculate the 1st derivative of a Bezier curve
Point2D bezier_first_derivative(float t, int n, Point2D points[])
{
Point2D result;
int intervallborder_s = 0;
int intervallborder_t = 1;
int i = 0;

for(i; i<=n-1; i++)
{
result.x += bernstein(t,n-1,i) * (points[i+1].x - points.x);
result.y += bernstein(t,n-1,i) * (points[i+1].y - points.y);
}

result.x = result.x * (n / (intervallborder_t - intervallborder_s));
result.y = result.y * (n / (intervallborder_t - intervallborder_s));

return result;
}


// Helper to calculate the 1st derivative of a Bezier curve
Point2D bezier_second_derivative(float t, int n, Point2D points[])
{
Point2D result;
int intervallborder_s = 0;
int intervallborder_t = 1;
int i = 0;

for(i; i<=n-2; i++)
{
result.x += bernstein(t,n-2,i) * (points[i+2].x - 2*points[i+1].x
+
points.x);
result.y += bernstein(t,n-2,i) * (points[i+2].y - 2*points[i+1].y
+
points.y);
}

result.x = result.x * ( n*(n-1.0) / pow( (double)(intervallborder_t -
intervallborder_s), 2) );
result.y = result.y * ( n*(n-1.0) / pow( (double)(intervallborder_t -
intervallborder_s), 2) );

return result;
}


// Calculate curvature
float curvature(float t, int n, Point2D points[])
{
Point2D bsd = bezier_second_derivative(t,n,points);
Point2D bfd = bezier_first_derivative(t,n,points);

float vp = vectorproduct(bsd, bfd);
float n_bfd = norm(bfd);

return vp / pow(n_bfd, 3);
}


// Calculate curvature vector
Point2D curvature_vector(float t, int n, Point2D points[])
{
Point2D bfd = bezier_first_derivative(t,n,points);

// Calculate normal vector
Point2D norm_bfd = norm_vector(bfd);

// Multiply with curvature
float c = curvature(t,n,points);

Point2D result = Point2D(norm_bfd.x * c, norm_bfd.y * c);

return result;
}

// Main
int main(int argc, char *argv[])
{
// Read the value specifying the degree
int n = atoi(argv[1]);

// Read the corresponding Bezier points
Point2D points[n];
int j = 0;

for (int i=2; i<(2*(n+1))+2; i+=2)
{
points[j] = Point2D(atof(argv), atof(argv[i+1]));
j += 1;
}

// Set a start value for t
float t = 0.0;

// Iterate and print the p_i's and the corresponding curvature values
for (int k=0; k<=20; k++)
{
Point2D pi = bezier(t, n, points);
//Point2D pi = curvature_vector(t, n, points);
//cout << curvature(t,n,points) << endl;
cout << pi.x << "\t\t" << pi.y << endl;
t = t + 0.05;
}

return 0;
}



---
File 2: point2d.h
---
class Point2D
{
public:
float x;
float y;

Point2D();
Point2D(float x, float y);
};

Point2D::point2D()
{
this->x=0;
this->y=0;
}

Point2D::point2D(float x, float y)
{
this->x=x;
this->y=y;
}



This is what I get:

bash-2.05b# ./porcupine 2 0 0 1 1 2 1
13073.4 9.21956e-41
11798.7 8.32063e-41
10589.4 7.4678e-41
9445.51 6.66107e-41
8366.96 5.90059e-41
7353.77 5.18607e-41
6405.95 4.51765e-41
5523.5 3.89533e-41
4706.41 3.31898e-41
3954.7 2.78886e-41
3268.34 2.30486e-41
2647.36 1.86695e-41
2091.74 1.47515e-41
1601.49 1.12945e-41
1176.6 8.29709e-42
817.085 5.76354e-42
522.934 3.68962e-42
294.15 2.07532e-42
130.733 9.23456e-43
32.6832 2.31214e-43
1.85784e-10 1.4013e-45


And this is what is expected (and what I get under windows):


Sorry, correction: This is expected:

(0, 0)
(0.1, 0.0975)
(0.2, 0.19)
(0.3, 0.2775)
(0.4, 0.36)
(0.5, 0.4375)
(0.6, 0.51)
(0.7, 0.5775)
(0.8, 0.64)
(0.9, 0.6975)
(1, 0.75)
(1.1, 0.7975)
(1.2, 0.84)
(1.3, 0.8775)
(1.4, 0.91)
(1.5, 0.9375)
(1.6, 0.96)
(1.7, 0.9775)
(1.8, 0.99)
(1.9, 0.9975)
(2, 1)
 
H

Howard

Alex Neumann said:
Howard wrote:


// Main
int main(int argc, char *argv[])
{
// Read the value specifying the degree
int n = atoi(argv[1]);

// Read the corresponding Bezier points
Point2D points[n];
int j = 0;

for (int i=2; i<(2*(n+1))+2; i+=2)
{
points[j] = Point2D(atof(argv), atof(argv[i+1]));
j += 1;
}


Without looking at the rest of your code carefully, I see a couple problems
right off.

Does this even compile? You're declaring an array (Point2D) of size n, but
n is a run-time variable. Arrays can only be declared in this manner with a
constant expression, not a variable. I get a compile error if I try to
compile code like that. You need to use a dynamic array if you want to
declare an array size based on a variable.

Also, even if you *had* used a dynamic array (with something like "Point2D*
points = new Point2D[n];"), then you've still got a problem, in that you're
creating three points, but n is 2, so your array only holds 2 points. So,
your code will write past the end of the array, causing undefined behavior.
Anything could happen after that. Your array needs to be of size n+1.

(I haven't looked any further, because these problems make the program
incorrect already.)

-Howard
 
J

John Harrison

Alex Neumann said:
Hi,

I have written a C++ program, very small, under Windows.
Normally I work under Linux, but I had to use a Windows machine over the
weekend.
The program does not use anything special, only

#include <iostream>
#include <stdlib.h>
#include "math.h"

I have copied the .cpp files from my Windows machine to my Linux machine
now.
Compiling with g++ 3.3.2-r5 under Gentoo works fine, but when I execute, the
results I get are just wrong, totally wrong. So this is nothing due to
rounding or so, there is no slight difference, it is just totally wrong.

I am not a C++ guru since I usually code in other languages.

What can be the reason for that ?

Undefined behaviour.

Programs which break the rules of C++ often result in what the C++ standard
calls undefined behaviour. When a program has undefined behaviour it can do
anything. It can work fine on one machine and fail on another, it can work
fine when you run it for your boss, but fail when you run it for a customer,
anything.

Now how you've broken the rules of C++ is another question, but if you are
not an experienced C++ programmer it is very easy to do.

john
 
I

Ivan Vecerina

Alex Neumann said:
Ok... here the code first:
Some comments and explanations as I skim through...
FILE 1: porcupine.cpp
In C++, using stdlib.h or math.h is non standard.
For portability, replace this with:
#include <cstdlib>
// Helper to calculate the faculty
int faculty(int n)
ok... I call this factorial... will do.
// Helper to calculate the binomial
float binomial(int n, int i)
{
return faculty(n) / (faculty(i) * faculty(n-i));
NB: this approach will overflow int very quickly.
faculty(>=13) will overflow on a 32-bit platform.
I'm not sure this is what causes the problem you observe, as I won't go
through your algorithms...
(I suggest you post on comp.graphics for this...)
// Main
int main(int argc, char *argv[])
{
// Read the value specifying the degree
int n = atoi(argv[1]);

// Read the corresponding Bezier points
Point2D points[n];

Declaring an array of a run-time-specified size (n is not a compile-time
constant) is not supported in standard C++.
Some C++ compilers support it as an extension (because it is now allowed in
C).
The portable and safer way to do the same is:
#include <vector>
....
std::vector<Point2D> points(n);


That's it for what I can say from the C++ side...

hth - Ivan
 
P

P.J. Plauger

Some comments and explanations as I skim through...

In C++, using stdlib.h or math.h is non standard.

Nope. The only nonstandard thing here is writing "math.h"
instead of said:
For portability, replace this with:
#include <cstdlib>
#include <cmath>
= proper C++, plus will declare all functions in namespace std

Yes, these headers do declare (most) C names in namespace std,
which can be helpful. But there's more than one flavor of
"proper C++".

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
 
I

Ivan Vecerina

P.J. Plauger said:
message news:[email protected]... ....

Nope. The only nonstandard thing here is writing "math.h"
instead of <math.h>.

I trust what you say. Could you point me to where the C++
standard guarantee the availability of C headers?
Is it unconceivable/illegal for a C++ platform to not be
providing the C-named headers in the default include path?
Plus what is a user supposed to expect in terms of the
presence or absence of overloads defined in C++?
Yes, these headers do declare (most) C names in namespace std,
which can be helpful. But there's more than one flavor of
"proper C++".

My instinct when writing standard-compliant C++ code
has been to use the headers as I saw them defined in the
C++ standard. As of today, I thought this offers a relatively
good guarantee of portability, and is the practice to encourage.
Though I will be happy if the C and C++ standards are
kept on a converging path...


Best regards,
Ivan
 
M

Mark A. Gibbs

Ivan said:
I trust what you say. Could you point me to where the C++
standard guarantee the availability of C headers?

17.4.1.2 p3-end

and

Annex D - D.5
Is it unconceivable/illegal for a C++ platform to not be
providing the C-named headers in the default include path?

yes. they must be there.
Plus what is a user supposed to expect in terms of the
presence or absence of overloads defined in C++?

it is specified that all macros remain macros, regardless of whether or
not they can be "improved" via inline functions, constants or templates.

i believe (off the top of my head) that overloads are added for many of
the math functions, allowing double, float or long(?) to be used
transparently. check in said:
My instinct when writing standard-compliant C++ code
has been to use the headers as I saw them defined in the
C++ standard. As of today, I thought this offers a relatively
good guarantee of portability, and is the practice to encourage.
Though I will be happy if the C and C++ standards are
kept on a converging path...

that's actually been a topic of focus recently. apparently, the last(?)
meetings of the c and c++ committees were essentially held together
(some people are members of both).

if you're writing a c++ program, i say take advantage of namespace std
and prefer <cmath> over <math.h>. there is no difference except the
stuff in <cmath> is in namespace std, and some overloads are added.

i don't follow the c committee's work, but i can't imagine that c
namespaces haven't been considered, and if they are implemented, they
will probably take the same form as c++'s, with similar "new" headers.
still, you should probably ask the c group that if it's a decision factor.

mark
 
I

Ivan Vecerina

Mark A. Gibbs said:
17.4.1.2 p3-end
and
Annex D - D.5
Thank you for these references. So the use of .h library headers
is described as deprecated but currently normative.
[ though we all know that 'deprecated' doesn't necessarily mean
that it will be gone... (e.g. static namespace-level functions) ]
it is specified that all macros remain macros, regardless of whether or
not they can be "improved" via inline functions, constants or templates.

i believe (off the top of my head) that overloads are added for many of
the math functions, allowing double, float or long(?) to be used
transparently. check in <cmath> and <cstdlib>. i can't recall any others.

As I understand §26.5, the overloads of the functions are added
in the C++-specific headers ( <cmath> and <cstdlib> ).
IIRC, however, the C99 standard adds such "overloads" in <math.h> too.
So maybe it's not clear whether the function overloads will be available
when including said:
that's actually been a topic of focus recently. apparently, the last(?)
meetings of the c and c++ committees were essentially held together
(some people are members of both).

I know about this from reports of Herb Sutter and others,
and I am definitely among the supporters of this convergence...
if you're writing a c++ program, i say take advantage of namespace std
and prefer <cmath> over <math.h>. there is no difference except the
stuff in <cmath> is in namespace std, and some overloads are added.
Agreed.


Cheers,
Ivan
 
P

P.J. Plauger

Mark A. Gibbs said:
17.4.1.2 p3-end
and
Annex D - D.5
Thank you for these references. So the use of .h library headers
is described as deprecated but currently normative.
[ though we all know that 'deprecated' doesn't necessarily mean
that it will be gone... (e.g. static namespace-level functions) ]

Yep. I'll be surprised if the *.h headers ever go away.

But this requirement is easily handled by such constructs as:

#define setjmp(buf) setjmp(buf)
others.

As I understand §26.5, the overloads of the functions are added
in the C++-specific headers ( <cmath> and <cstdlib> ).

Nope. All the overloads added to the c* headers by the C++ Standard
must appear in the *.h headers too.
IIRC, however, the C99 standard adds such "overloads" in <math.h> too.

C99 adds many of the same overloads as C++, but not all. C99 also adds
overloads not required by C++.
So maybe it's not clear whether the function overloads will be available
when including <math.h> instead of <cmath> on a given platform.

It *should* be clear. In real life, there's a considerable degree of
non-conformance among current implementations in this area.
I know about this from reports of Herb Sutter and others,
and I am definitely among the supporters of this convergence...

The C++ committee has approved, as part of the non-normative library
Technical Report (aka TR1) the addition of essentially *all* C99
library additions. They've been available in the Dinkumware libraries
for the past couple of years.

Not exactly. If you include <math.h> you're *supposed* to get all
functions declared in namespace std and hoisted to the global namespace
by using declarations. And you're *supposed* to get all the added
overloads. So there's less difference than you think. Still, because
of the current state of the art, you're generally better off including
<cmath> instead, because you're *more likely* to get what you expect.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,763
Messages
2,569,562
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top