Date: Sat, 06 Sep 1997 11:11:58 -0500
From: "L. Van Warren" <lvwarren@wdv.com>
To: lvwarren@wdv.com
Subject: [Fwd: Java and C]
This is a multi-part message in MIME format.
--------------7E96B65DD4A73F0FB3F97582
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
--------------7E96B65DD4A73F0FB3F97582
Content-Type: message/rfc822
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
Received: from heavy.web.ipa.net (heavy.web.ipa.net [205.218.170.194])
by sibyl.intellinet.com (8.8.5/8.8.4) with ESMTP
id LAA06011 for <lvwarren@intellinet.com>; Sat, 6 Sep 1997 11:15:02 -0500 (CDT)
Received: from siren.ipa.net (siren.ipa.net [205.218.170.20])
by heavy.web.ipa.net (8.8.6/8.8.4) with ESMTP
id LAA24479 for <lvwarren@wdv.com>; Sat, 6 Sep 1997 11:15:49 -0500 (CDT)
Received: from hp-customer (pool-4-94.lit.ipa.net [209.12.93.94])
by siren.ipa.net (8.8.6/8.8.6) with ESMTP id LAA21007;
Sat, 6 Sep 1997 11:13:52 -0500 (CDT)
Message-ID: <34117F42.1643B0EB@wdv.com>
Date: Sat, 06 Sep 1997 11:05:22 -0500
From: "L. Van Warren" <lvwarren@wdv.com>
Organization: Warren Design Vision
X-Mailer: Mozilla 4.01 [en] (Win95; I)
MIME-Version: 1.0
To: Cliff Berg <cliffbdf@digitalfocus.com>
Subject: Re: Java and C
X-Priority: 3 (Normal)
References: <34110AD7.B92A78D3@digitalfocus.com>
Content-Type: multipart/mixed; boundary="------------505F0A557B56ED7A952C8718"
This is a multi-part message in MIME format.
--------------505F0A557B56ED7A952C8718
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Dear Cliff -
With all due respect, let me point out one detail which may cause you to
reconsider your response. I was not using the general purpose Java
Vector class at all, but rather my own Vec class which consists of fixed
array of 4 floating point numbers as the fundamental datatype. As you
know, in engineering and physics, homogeneous vector algebra in a 4
tuple is a fundamental abstraction representing {x, y, z, w}. I have
been using that abstraction in high performance graphics implementations
since 1983. It was my alarm at the poor performance of a semantically
clear implementation of this abstract data type that prompted my
communication.
Perhaps your own unique point of view however can break this performance
logjam. To this end I am attaching a *working* version of the class to
this message. If you would rather cut to the chase and see this class
running in an applet, please visit:
http://www.wdv.com/Software/jaVanLib/jaVanTest.html
the top line of the applet is a choice menu with a scrollbar.
scroll down in the menu to the last line, "Vec Geom: p5"
and run the applet to see the comparative performance of the methods.
it is these methods which run 20 to 40 time slower than a C++
implementation.
if you can figure out a way to improve the performance of these
methods without sacrificing the clarity of the implementation,
my hat is off to you and I will listen attentively to what you say...
sincerely,
L. Van Warren MS CS, AE
President
Warren Design Vision
Cliff Berg wrote:
>
> You wrote:
>
> L. Van Warren (lvwarren@wdv.com)
> Sat, 24 May 1997 14:19:10 -0500
>
> Messages sorted by: [ date ][ thread ][ subject ][ author ]
> Next message: Radu Nicolescu: "Re: Frequently Asked Questions -
> Applet Security"
> Previous message: Xiao, Kevin: "Java Security"
>
> Date: Sat, 24 May 1997 14:19:10 -0500
>
> From: "L. Van Warren" <lvwarren@wdv.com>
>
> To: jdk-comments@web2.javasoft.com, java-security@web2.javasoft.com,
>
> Subject: Java is 40 times slower than C
>
> Well -
>
> I had been porting my code libraries to Java in the hope of making
> them platform independent, pointerless, and object oriented. I have
> been reusing some of this software since 1983. Why not transform
> everything into the most modern Java form, a well-layered onion, a final
>
> port for the year 2000, one last change before discarding all that awful
>
> 'C'?
>
> I started the project by building a visual environment that would
> present the results from the battery of tests in an aesthetic way.
> A perfect simulation of green engineering graph paper complete with
> holes and printability and a menu for selecting classes and test runs.
> *whew*
>
> This Saturday morning, for my birthday, I got the results from my
> carefully controlled numerical experiment comparing the speed of 'C'
> code to Java on my 120 MHz PowerPC using Metrowerks CW 11.
>
> The bottom line is that Java is 40 times slower than C.
>
> Bread and butter operations like:
>
> c = addVec(a, b); /* C */
>
> run 40 times slower in clean Java, i.e.
>
> c = a.add(b); // Java
>
> Now maybe you don't use such operations, or need them to be platform
> independent. Most of the engineering and scientific computing that I
> requires grinding numbers, especially vectors.
> Even most games and simulations require that. Have you seen any
> sophisticated games or simulations on the net in Java? I haven't. Now
> I know why...
>
> Using esoteric tricks like optimizing and making the class "final" as
> in "Math" did speed things up a little. I did some awful things and
> sped it up so it was ONLY 20 times slower. But, I would never use THAT
> code.
>
> I had heard that Java was an order of magnitude slower,
> but I didn't believe it. I thought, "I can make it go faster, I am
> good".
>
> Consider some car A that ran 40 times slower than car B.
> Would you use it?
> A goes 80 mph on the freeway. How fast does B go?
> B goes 2 mph. B doesn't get on the street, much less the freeway.
> I can crawl on my face at 2 mph.
>
> Consider an airplane A that ran 40 times slower than airplane B.
> 400 mph for A equals a 10 mph jog for B.
> Would you jog from LA to New York,
> every time you had to run an errand?
>
> Thought you might find this result interesting. My head is swimming.
> My whole approach is devastated. I am going spend the rest of my
> birthday considering other careers...
>
> - Van
>
> =========
>
> The Vector object in Java is very inefficient for several reasons.
> First, it is a general purpose class, which must staisfy alot of
> requirements. Therefore, you would not use it for high-performance
> requirements. For example, all its operations are synchronized, for
> thread safety (this imposes a very large performance penalty). If you
> are in a tight loop in a single thread, you would not use a Vector;
> instead, you would write your own Vector class. Second, the way you
> declare the Vector determines how many times it needs to go back to the
> heap. You should declare it with the maximum size you might need.
> Finally, For a high-performance application, you probably would not use
> a Vector object at all. You would use a statically-allocated structure,
> set to the maximum size you might need.
>
> CJB
--------------505F0A557B56ED7A952C8718
Content-Type: java/*; name="Vec.java"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline; filename="Vec.java"
/*
* @(#)Vec.java 1.0 97/5/21 =
*
* Copyright (c) 1997 Warren Design Vision =A5 All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this software
* and its documentation for a license fee of $10 per transfer.
* Send payment to:
* Van Warren
* Warren Design Vision (WDV)
* http://www.wdv.com
*
* A transfer is the first time act of copying this software.
* by a specific individual. Subsequent use of the
* software by the same individual is free,
* provided that this copyright notice appears in all copies.
* Transfer by that individual to another individual
* requires payment of the license fee.
*
* WDV MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
* THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE, OR NON-INFRINGEMENT. WDV SHALL NOT BE LIABLE FOR
* ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
*/
=
/** Design Notes:
The Vec package is a point x, y z OR
a normal nx, ny, nz;
*/
import java.lang.*;
class VH // Vec Helper
{
// From CRC Math Tables, 25th Edition page 300
=
// Cartesian
static final int X =3D 0;
static final int Y =3D 1;
static final int Z =3D 2;
// spherical
static final int PHI =3D 0;
static final int THE =3D 1;
static final int RHO =3D 2;
// cylindrical
static final int R =3D 0;
//static final int THE =3D 1; // same as spherical
//static final int Z =3D 2; // same as Cartesian
// map
static final int LAT =3D 0;
static final int LON =3D 1;
//static final int RHO =3D 2; // same as spherical
}
public class Vec
{
// data =
public double x[] =3D {0, 0, 0};
// constructors
public Vec (double X, double Y, double Z) { x[0] =3D X; x[1] =3D Y; x[=
2] =3D Z; }
// Vector operations
public Vec plus (Vec that) { return(new Vec(this.x[0] + that.x[0] , t=
his.x[1] + that.x[1] , this.x[2] + that.x[2] )); }
public Vec minus(Vec that) { return(new Vec(this.x[0] - that.x[0] , t=
his.x[1] - that.x[1] , this.x[2] - that.x[2] )); }
public Vec times(Vec that) { return(new Vec(this.x[0] * that.x[0] , t=
his.x[1] * that.x[1] , this.x[2] * that.x[2] )); }
public double[] times(double that[])
{ double c[] =3D {0, 0, 0};
c[0] =3D this.x[0] * that[0];
c[1] =3D this.x[1] * that[1];
c[2] =3D this.x[2] * that[2];
=
return( c );
}
public double[] times(double a[], double b[])
{ double c[] =3D {0, 0, 0};
c[0] =3D a[0] * b[0];
c[1] =3D a[1] * b[1];
c[2] =3D a[2] * b[2];
=
return( c );
}
public double dot (Vec that) { return( (this.x[0] * that.x[0] + t=
his.x[1] * that.x[1] + this.x[2] * that.x[2] )); }
public Vec over (Vec that) { return(new Vec(this.x[0] / that.x[0] , t=
his.x[1] / that.x[1] , this.x[2] / that.x[2] )); }
public Vec times(double C) { return(new Vec(this.x[0] * C , t=
his.x[1] * C , this.x[2] * C )); }
public Vec abs ( ) { return(new Vec( Math.abs(this.x[0]), =
Math.abs(this.x[1]), Math.abs(this.x[2]))); }
public Vec nrm ( )
{ double L=3DMath.sqrt(dot(this));
if(L=3D=3D0.0) L=3D1; return(new Vec(this.x[0] / L =
, this.x[1] / L , this.x[2] / L )); =
} =
public Vec lirp (Vec that, double t)
{ double omt=3D1-t;
return
( new
Vec
(
omt*this.x[0] + t*that.x[0],
omt*this.x[1] + t*that.x[1],
omt*this.x[2] + t*that.x[2]
)
);
}
=
public Vec cross(Vec that)
{
return
( new
Vec
(
this.x[1]*that.x[2]-this.x[2]*that.x[1],
this.x[2]*that.x[0]-this.x[0]*that.x[2],
this.x[0]*that.x[1]-this.x[1]*that.x[0]
)
);
}
=
public Vec latlonrhoToCartesian() { return this.latlonrhoTospherical(=
).sphericalToCartesian(); }
public Vec CartesianTolatlonrho() { return this.CartesianTospherical(=
).sphericalTolatlonrho(); }
public Vec CartesianTospherical()
{
double phi;
double theta;
double rho =3D Math.sqrt (dot(this) );
=
if( rho =3D=3D 0) { return( new Vec(0, 0, 0) ); }
else { phi =3D Math.acos(this.x[2]/rho); }
=
=
if(this.x[0] =3D=3D 0) { theta =3D Math2.PI_2 ; }
else { theta =3D Math.atan2(this.x[1], this.x[0]); }
=
return( new Vec(phi, theta, rho) );
}
public Vec sphericalToCartesian()
{
double X, Y, Z;
=
X =3D this.x[2] * Math.cos(this.x[1]) * Math.sin(this.x[0]);
Y =3D this.x[2] * Math.sin(this.x[1]) * Math.sin(this.x[0]);
Z =3D this.x[2] * Math.cos(this.x[0]);
return( new Vec(X, Y, Z) );
}
public Vec sphericalTolatlonrho()
{
return
( new
Vec
(
Math2.PI_2-this.x[0],
this.x[1],
this.x[2]
)
);
}
public Vec latlonrhoTospherical()
{
return
( new
Vec
(
Math2.PI_2-this.x[0],
this.x[1],
this.x[2]
)
);
}
public Vec CartesianTocylindrical()
{
return
( new
Vec
(
Math.sqrt(this.x[0]*this.x[0] + this.x[1]*this.x[1]),
Math.atan2(this.x[1], this.x[0]),
this.x[2]
)
);
}
public Vec cylindricalToCartesian()
{
return
( new
Vec
(
this.x[0]*Math.cos(this.x[1]),
this.x[0]*Math.sin(this.x[1]),
this.x[2]
)
);
}
public Vec HSVToRGB(Vec a)
{
double h, s, v, p, q, t, f;
double x, y, z;
int i;
=
h =3D this.x[0] * 360.0; s =3D this.x[1]; v =3D this.x[2];
=
if(this.x[0] =3D=3D 360.0) { this.x[0] =3D 0.0; }
=
h /=3D 60.0;
i =3D (int)Math.floor(h);
f =3D h - i;
p =3D v *(1-s);
q =3D v*(1 - (s*f));
t =3D v*(1-(s*(1-f)));
=
switch(i)
{
case 0: x =3D v; y =3D t; z =3D p; break;
case 1: x =3D q; y =3D v; z =3D p; break;
case 2: x =3D p; y =3D v; z =3D t; break;
case 3: x =3D p; y =3D q; z =3D v; break;
case 4: x =3D t; y =3D p; z =3D v; break;
case 5: x =3D v; y =3D p; z =3D q; break;
default:x =3D 1; y =3D 1; z =3D 1; break;
}
=
return new Vec(x, y, z);
}
public void print(Vec a)
{
System.out.println("Vec(" + this.x[0] + ", " + this.x[1] + ", "+ this.x=
[2] + ", " + this.x[3] + ")" );
}
public String toString()
{
StringBuffer stringBuffer =3D new StringBuffer();
=
stringBuffer.append("Vec( ");
stringBuffer.append(this.x[0]); stringBuffer.append(", ");
stringBuffer.append(this.x[1]); stringBuffer.append(", ");
stringBuffer.append(this.x[2]); stringBuffer.append(")");
return(stringBuffer.toString());
}
}
public final class Vec2 // this was a vain attempt at speeding up Java =
vector operations by changing argument lists.
{
public static double[] times(double a[], double b[])
{
double c[] =3D {0, 0, 0};
c[0] =3D a[0] * b[0];
c[1] =3D a[1] * b[1];
c[2] =3D a[2] * b[2];
=
return( c );
}
public static void times(double a[], double b[], double c[])
{
c[0] =3D a[0] * b[0];
c[1] =3D a[1] * b[1];
c[2] =3D a[2] * b[2];
}
}
public class VecTest
{
=
public void testPage1(EDP eDP, String auth, String titl, String date)
{
eDP.clear();
eDP.drawPaper(auth, titl, date);
eDP.setScheme("text");
=
// Test minimax arithmetic
eDP.write("Test vector operation correctness:");
=
Vec a =3D new Vec(1, -2, 3);
Vec b =3D new Vec(3, 2, 1);
=
eDP.write("Basic Operations");
eDP.write(" a : " + a.toString());
eDP.write(" b: " + b.toString());
eDP.write(" a + b: " + a.plus (b).toString());
eDP.write(" a - b: " + a.minus(b).toString());
eDP.write(" a * b: " + a.times(b).toString());
eDP.write(" a / b: " + a.over (b).toString());
eDP.write(" 2 * a: " + a.times(2).toString());
eDP.write("");
eDP.write("Vector Products");
eDP.write(" a x b: " + a.cross(b).toString());
eDP.write(" a . b: " + String.valueOf(a.dot(b)));
eDP.write("");
eDP.write("Absolute Value, Normalization and Linear InteRPolation");
eDP.write(" |a| : " + a.abs().toString());
eDP.write("nrm(a): " + a.nrm().toString());
eDP.write("lirp(a,b,0.5): " + a.lirp(b, 0.5).toString());
eDP.write(""); =
}
=
public void testPage2(EDP eDP, String auth, String titl, String date)
{
eDP.clear();
eDP.drawPaper(auth, titl, date);
eDP.setScheme("text");
=
eDP.write("Test Coordinate Transformations:");
=
for(int i =3D -1; i < 2; i +=3D 2) for(int j =3D -1; j < 2; j +=3D 2) f=
or(int k =3D -1; k < 2; k +=3D 2)
{
Vec a =3D new Vec( Math2.DOUBLE(i), Math2.DOUBLE(j), Math2.DOUBL=
E(k));
eDP.write(" a : " + a.toString()); =
Vec b =3D a.CartesianTospherical();
eDP.write("b =3D a.CartesianTospherical() : " + a.CartesianTosp=
herical().toString());
eDP.write("a =3D=3D b.sphericalToCartesian()?: " + b.sphericalTo=
Cartesian().toString());
}
eDP.write(""); =
}
=
public void testPage3(EDP eDP, String auth, String titl, String date)
{
eDP.clear();
eDP.drawPaper(auth, titl, date);
eDP.setScheme("text");
=
eDP.write("Test Coordinate Transformations:");
=
for(int i =3D -1; i < 2; i +=3D 2) for(int j =3D -1; j < 2; j +=3D 2) f=
or(int k =3D -1; k < 2; k +=3D 2)
{
Vec a =3D new Vec( Math2.DOUBLE(i), Math2.DOUBLE(j), Math2.DOUBL=
E(k));
eDP.write(" a : " + a.toString()); =
Vec b =3D a.CartesianTolatlonrho();
eDP.write("b =3D a.CartesianTolatlonrho() : " + a.CartesianTola=
tlonrho().toString());
eDP.write("a =3D=3D b.latlonrhoToCartesian()?: " + b.latlonrhoTo=
Cartesian().toString());
}
eDP.write("");
}
=
public void testPage4(EDP eDP, String auth, String titl, String date)
{
eDP.clear();
eDP.drawPaper(auth, titl, date);
eDP.setScheme("text");
=
eDP.write("Test Coordinate Transformations:");
=
for(int i =3D -1; i < 2; i +=3D 2) for(int j =3D -1; j < 2; j +=3D 2) f=
or(int k =3D -1; k < 2; k +=3D 2)
{
Vec a =3D new Vec( Math2.DOUBLE(i), Math2.DOUBLE(j), Math2.DOUBL=
E(k));
eDP.write(" a : " + a.toString()); =
Vec b =3D a.CartesianTocylindrical();
eDP.write("b =3D a.CartesianTocylindrical() : " + a.CartesianTo=
cylindrical().toString());
eDP.write("a =3D=3D b.cylindricalToCartesian()?: " + b.cylindric=
alToCartesian().toString());
}
}
public long TimeIt(EDP eDP, String label, long start)
{
long elapsed =3D System.currentTimeMillis()-start;
eDP.write(label + (double)(elapsed)/1000.0 + " s");
return(elapsed);
}
=
public void testPage5(EDP eDP, String auth, String titl, String date)
{
int NCALLS =3D 10000;
int n;
double f;
long start, elapsed, CTotal=3D0;
eDP.clear();
eDP.drawPaper(auth, titl, date);
eDP.setScheme("text");
eDP.write("TIMING TEST"); =
=
Vec a =3D new Vec(1, 2, 3);
Vec b =3D new Vec(1, 2, 3);
Vec c;
=
start =3D System.currentTimeMillis();
for( n =3D 0; n < NCALLS; n++) { c =3D new Vec(1, 2, 3);}
CTotal +=3D TimeIt(eDP, "Vec3: new Vec():", start);
=
start =3D System.currentTimeMillis();
for( n =3D 0; n < NCALLS; n++) { c =3D a.plus(b);}
CTotal +=3D TimeIt(eDP, "Vec3: a.add():", start);
=
start =3D System.currentTimeMillis();
for( n =3D 0; n < NCALLS; n++) { c =3D a.minus(b);}
CTotal +=3D TimeIt(eDP, "Vec3: a.sub():", start);
=
start =3D System.currentTimeMillis();
for( n =3D 0; n < NCALLS; n++) { c =3D a.times(b);}
CTotal +=3D TimeIt(eDP, "Vec3: a.times(b):", start);
=
double d[] =3D {0, 0, 0};
start =3D System.currentTimeMillis();
for( n =3D 0; n < NCALLS; n++) { d =3D a.times(b.x);}
CTotal +=3D TimeIt(eDP, "Vec3: a.times(b.x <-- dirty):", start);
=
start =3D System.currentTimeMillis();
for( n =3D 0; n < NCALLS; n++) { d =3D a.times(a.x, b.x);}
CTotal +=3D TimeIt(eDP, "Vec3: a.times(a.x, b.x <-- dirtier):", start)=
;
=
start =3D System.currentTimeMillis();
for( n =3D 0; n < NCALLS; n++) { d =3D Vec2.times(a.x, b.x);}
CTotal +=3D TimeIt(eDP, "Vec3Vec2.times(a.x, b.x <-- dirtiest):", start=
);
=
start =3D System.currentTimeMillis();
for( n =3D 0; n < NCALLS; n++) { c =3D a.times(2);}
CTotal +=3D TimeIt(eDP, "Vec3: a.scl():", start);
=
start =3D System.currentTimeMillis();
for( n =3D 0; n < NCALLS; n++) { c =3D a.cross(b);}
CTotal +=3D TimeIt(eDP, "Vec3: a.crs():", start);
=
start =3D System.currentTimeMillis();
for( n =3D 0; n < NCALLS; n++) { c =3D a.abs();}
CTotal +=3D TimeIt(eDP, "Vec3: a.abs():", start);
=
start =3D System.currentTimeMillis();
for( n =3D 0; n < NCALLS; n++) { c =3D a.nrm();}
CTotal +=3D TimeIt(eDP, "Vec3: a.nrm():", start);
=
start =3D System.currentTimeMillis();
for( n =3D 0; n < NCALLS; n++) { c =3D a.lirp(b, 0.5);}
CTotal +=3D TimeIt(eDP, "Vec3: a.lrp():", start);
=
start =3D System.currentTimeMillis();
for( n =3D 0; n < NCALLS; n++) { f =3D a.dot(b);}
CTotal +=3D TimeIt(eDP, "Vec3: a.dot():", start);
=
start =3D System.currentTimeMillis();
for( n =3D 0; n < NCALLS; n++) { c =3D a.latlonrhoToCartesian();}
CTotal +=3D TimeIt(eDP, "Vec3: a.l2c():", start);
=
start =3D System.currentTimeMillis();
for( n =3D 0; n < NCALLS; n++) { c =3D a.CartesianTolatlonrho();}
CTotal +=3D TimeIt(eDP, "Vec3: a.c2l():", start);
=
start =3D System.currentTimeMillis();
for( n =3D 0; n < NCALLS; n++) { c =3D a.sphericalToCartesian();}
CTotal +=3D TimeIt(eDP, "Vec3: a.s2C():", start);
=
start =3D System.currentTimeMillis();
for( n =3D 0; n < NCALLS; n++) { c =3D a.CartesianTospherical();}
CTotal +=3D TimeIt(eDP, "Vec3: a.C2s():", start);
=
start =3D System.currentTimeMillis();
for( n =3D 0; n < NCALLS; n++) { c =3D a.sphericalTolatlonrho();}
CTotal +=3D TimeIt(eDP, "Vec3: a.s2l():", start);
=
start =3D System.currentTimeMillis();
for( n =3D 0; n < NCALLS; n++) { c =3D a.latlonrhoTospherical();}
CTotal +=3D TimeIt(eDP, "Vec3: a.l2s():", start);
=
start =3D System.currentTimeMillis();
for( n =3D 0; n < NCALLS; n++) { c =3D a.cylindricalToCartesian();}
CTotal +=3D TimeIt(eDP, "Vec3: a.c2C():", start);
=
start =3D System.currentTimeMillis();
for( n =3D 0; n < NCALLS; n++) { c =3D a.CartesianTocylindrical();}
CTotal +=3D TimeIt(eDP, "Vec3: a.C2c():", start);
eDP.write("Total elapsed time for " + NCALLS + " calls of 18 vector fun=
ctions " + (double)CTotal/1000.0 + " s");
}
}
--------------505F0A557B56ED7A952C8718--
--------------7E96B65DD4A73F0FB3F97582--