The test program is "done" well not really but a first version is available on the net.
Which also includes your line. "My" second implementation has problems with this line. The second method uses some sort of dot product or cross product. Which is kinda surprising because I think Nicholas's implementation also works like that... oh well ;)
My first implementation however... which I do fully understand still works perfectly =D
Can you find/think up any other possibly problems ? ;)
See this link for the source code, binaries, data, etc, etc, etc.
VerificationProgramVersion009.zip
formatting link
See the other usenet thread called "VerificationProgram009 etc" for more details etc ;)
I wrote a little program which uses rational numbers and floating point numbers and shows the difference.
The rational number version is able to perfectly calculate the point. The floating point version fails miserably at it ;)
The rational number version is about 20 times slower than the floating point version ;)
program started
(Rational) PointX in rational notation: 768/5 (Rational) PointY in rational notation: 2991/10
(Rational) PointX in real notation: 153.6000000000000000 (Rational) PointY in real notation: 299.1000000000000000 (Rational) ticks: 282 (Rational) time (in seconds): 0.0000787809623849
(Floating point) PointX: 153.5999999999999940 (Floating point) PointY: 299.0999999999999660 (Floating point) ticks: 14 (Floating point) time (in seconds): 0.0000039111116078
press enter to exit
Here is the source code. Thanks to delphi fundamentals for the Trational class etc =D
Now for the final question ;)
Can you still find a point which would in theory be on the line segment but would still be mis-calculated by the rational number version ? ;)
program TestRationalNumbers;
{$APPTYPE CONSOLE}
uses SysUtils, cUtils in 'Utils\\cUtils.pas', cStrings in 'Utils\\cStrings.pas', cRational in 'Maths\\cRational.pas', cMaths in 'Maths\\cMaths.pas', Windows;
// rational number versions:
procedure calc_perpendicular( var x, y : Trational ); var temp_x, temp_y : Trational; begin temp_x := Trational.Create; temp_y := Trational.Create;
// temp_x := -y; temp_x.Assign( y ); temp_x.Negate;
// temp_y := x; temp_y.Assign( x );
// x := temp_x; // y := temp_y; x.Assign( temp_x ); y.Assign( temp_y );
temp_x.Destroy; temp_y.Destroy; end;
procedure calc_normalize( var x, y : Trational ); var temp_squared_x : Trational; temp_squared_y : Trational; temp_length : Trational;
begin temp_squared_x := Trational.Create; temp_squared_y := Trational.Create; temp_length := Trational.Create;
// temp_length := sqrt( (x*x) + (y*y) ); temp_squared_x.Assign( x ); temp_squared_y.Assign( y );
// divide vector by it's own length there by creating a "normal" :) calc_normalize( _normal_x, _normal_y ); end;
// original double versions // using flawed floating point shit ;)
// helper procedure to generate points on or near line segments procedure GeneratePointForLineSegment( StartX, StartY, EndX, EndY : Trational; DistanceFromStart : Trational; // distance from start // < 0 is before start // 0 is on start // 0.5 is on center // 1 is one end // > 1 is after end DistanceFromLine : Trational; // closest distance from line
// follows the normal // positive is left side of line // zero is on line // negative is right side of line var px, py : Trational ); var NX, NY : Trational;
begin NX := Trational.Create; NY := Trational.Create;
// create a perpendicular point... we do this by calculating a normal and multiplieing // this with the distance from the line and adding this to px and py ;)
// calculate normilized normal for line calc_normal( StartX,StartY, EndX,EndY, NX,NY );
// offset the point along the normal with distance from line // PX := PX + NX * DistanceFromLine; // PY := PY + NY * DistanceFromLine;
procedure org_calc_perpendicular( var x, y : double ); var temp_x, temp_y : double; begin temp_x := -y; temp_y := x; x := temp_x; y := temp_y; end;
procedure org_calc_normalize( var x, y : double ); var temp_length : double; begin temp_length := sqrt( (x*x) + (y*y) ); if temp_length0 then begin x := x / temp_length; y := y / temp_length; end; end;
procedure org_calc_normal( _x1,_y1, _x2,_y2 : double; var _normal_x, _normal_y : double ); begin _normal_x := _x2-_x1; _normal_y := _y2-_y1;
// divide vector by it's own length there by creating a "normal" :) org_calc_normalize( _normal_x, _normal_y ); end;
// helper procedure to generate points on or near line segments procedure org_GeneratePointForLineSegment( StartX, StartY, EndX, EndY : double; DistanceFromStart : double; // distance from start // < 0 is before start // 0 is on start // 0.5 is on center // 1 is one end // > 1 is after end DistanceFromLine : double; // closest distance from line
// follows the normal // positive is left side of line // zero is on line // negative is right side of line var px, py : double ); var NX, NY : double; begin // theory of method1 ;) PX := StartX + DistanceFromStart * (EndX - StartX); PY := StartY + DistanceFromStart * (EndY - StartY);
// create a perpendicular point... we do this by calculating a normal and multiplieing // this with the distance from the line and adding this to px and py ;)
// calculate normilized normal for line org_calc_normal( StartX,StartY, EndX,EndY, NX,NY );
// offset the point along the normal with distance from line PX := PX + NX * DistanceFromLine; PY := PY + NY * DistanceFromLine; end;
var vHighPerformanceCounterFrequency : int64; vCounter1 : int64; vCounter2 : int64;
if vMeasurementsEnabled then begin if not QueryPerformanceFrequency( vHighPerformanceCounterFrequency ) then begin writeln('High performance counter not present, speed measurements disabled'); vMeasurementsEnabled := false; end; end;
writeln; writeln( '(Rational) PointX in rational notation: ', vPointX.AsString ); writeln( '(Rational) PointY in rational notation: ', vPointY.AsString );
writeln; writeln( '(Rational) PointX in real notation: ', vPointX.AsReal : 16 :
16 ); writeln( '(Rational) PointY in real notation: ', vPointY.AsReal : 16 :
16 );
if vMeasurementsEnabled then begin writeln('(Rational) ticks: ', vRationalTicks ); writeln('(Rational) time (in seconds): ', vRationalTime : 16 : 16 ); end;
if vMeasurementsEnabled then begin writeln('(Floating point) ticks: ', vFloatingPointTicks ); writeln('(Floating point) time (in seconds): ', vFloatingPointTime : 16 :
I don't need to understand fully how floating point works. Sometimes I forget about rounding errors, so this thread was a nice refreshment. However in the back of my mind I know floating points are inaccurate, that is why I requested the methods to be "as accurate as possible". "as possible" meaning as possibly as *you* can get it without being to fricking slow lol =D
The epsilon method is flawed in my mind since it assumes the points are quite large but in fact could be quite small thereby completely failing.
Maybe you have a gross and dangerous misunderstanding of using a smudge factor/epsilon ;)
I also don't like to study flawed/worthless shit like floating point format etc... I rather spent my time finding solutions to this shit lol =D. So far I have found a better alternative which is a rational number library... it still uses floating points inside which are used to represent the rational numbers but since it uses fractions it should be a lot more accurate than just using floating points directly ;)
Another solution might be a fixed point library =D
And that's why you need to study some fundementals. Start with absolute versus relative tolerance (GIYF) and decide which (or some other measure) is better in your case.
And that's why you need to study some fundementals. Start with absolute versus relative tolerance (GIYF) and decide which (or some other measure) is better in your case.
Yes, you do have a fixed point implementation. It has a constant delta value of 1. It's called integer artithmetic.
In a fixed point numbering system, numbers are represented as integer multiples of some base value, which is sometimes called the "delta". For example, a fixed-point representation with a delta of 0.01 might be useful for representing money, with dollar amounts being represented as a whole number of cents.
Some languages have direct support for such types. In others, you can always simulate it by using integer arithmetic and keeping track of the delta yourself.
Well, not quite; you've swapped the coordinates. You mean (299.1,153.6), not (153.6,299.1).
If your end points are (0,0) and (997,512), and you're using integer arithmetic (with a delta of 1), there are no representable points on the line segment excluding the end points. (299.1,153.6) is not representable.
Equivalently, if you're using a fixed-point delta of 0.01, and your end points are (0,0) and (9.97,5.12) there are still no representable points on the line segment excluding the end points. (2.991,1.536) is not representable.
Now if you're willing to have your is_this_point_on_this_line_segment() function always return false for some line segments, that's ok. If you expect it to return true for some significant number of points, either you can use a numeric representation that supports arbitrary precision (integer, fixed-point, and floating-point won't do; rational numbers with unlimited range on the numerator and denominator probably will), or you can define some concept of "close enough".
What might turn out to be more useful is a function that, given the end points of a line segment an arbitrary point, tells you the distance between the line segment and the point. Defining the "distance" when the point is beyond the end points is left as an exercise.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org
San Diego Supercomputer Center
We must do something. This is something. Therefore, we must do this.
Ok, fixed point implementations therefore have the same rounding problems as floating point implementations ;) =D Since both work with a "point" =D
that
No, the original poster has swapped the coordinates ;)
In another post the original poster mentioned this line segment:
" I pick the points (0,0) and (512,997) slightly easier to see as integers, but you can shift the binary point over and make them floating point. Find any point on the segment between them. "
Yes "close enough" would be the epsilon method... However using multiple floating point operations will eventually create numerical drift so at some point even the epsilon method will probably fail because the rounding errors get to large !? ;)
Neh, this solution faces the same rounding problems.
Read Knuth. Google brounding. Get educated. It's all quite simple. Generalize to n dimensions, two is boring. You have not yet defined the problem you wish to solve. See if you can do that. Bet you can't. "Is this point on this line segment" is not a problem definition. If you are talking mathematics the solution is simple and known, if you provide the rest of the problem definition. If you are talking computers and programming, you didn't pose any interesting problem. The answer is always "yes and no" without further definition of what you mean.
Hmmm? I google'd "brounding" and it seems to have something to do with electrical grounding (but appears to have an inflection I didn't quite catch... a brazed on grounding point, maybe??)
I don't see what brounding has to do with the topic at hand?
--
These .signatures are sold by volume, and not by weight.
ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here.
All logos and trade names are the property of their respective owners.