On Dec 27, 3:10 am, Brian C. [email protected] wrote:
include Math
=> 0.0
–
Posted viahttp://www.ruby-forum.com/.
Here’s the nature of the problem.
Ruby currently gives incorrect values for x|y axis angles
cos PI/2 => 6.12303176911189e-17
sin PI => 1.22460635382238e-16
cos 3PI/2 => -1.83690953073357e-16
sin 2PI => -2.44921970764475e-16
Thus, sin gives incorrect answers on the +|- x axis
and, cos gives incorrect answers on the +|- y axis
Here’s the total solution.
In order to produce the mathematically correct answers
we must FORCE the answers to meet mathematical necessity.
i.e. (1) 1 = cos^2 + sin^2
thus, (2) cos|sin = [1-(sin|cos)^2]^(1/2)
also, (3) for angle x when sin|cos= -1|1 > cos|sin= 0.0
To ‘fix totally’ these errors in sin|cos near the x|y axis define sin1|
cos1 here using Ruby’s native cos|sin.
def sin1(x)
y=(1-cos(x)**2)**0.5 # calculate (2)
return 0.0 if y==0
return sin(x) < 0 ? -y : y # for correct quadrant sign
end
def cos1(x)
y=(1-sin(x)**2)**0.5 # calculate (2)
return 0.0 if y==0
return cos(x) < 0 ? -y : y # for correct quadrant sign
end
Now sin|cos == sin1|cos1 for all angles -1|1 degree from
each axis.
For |x| < 1 degree from 0, 90, 180, 270, 360, and their
multiples, sin1|cos1 will produce the mathematically
correct complimentary answers to satisfy (1) and (3).
In testing, I found only one instance on each side of
each +|- axis where the floating point approximations
gave answers which violated (3).
Here’s an example at 0 degrees|radians
first let:
degrees = PI/180
x|y axis check
sin1(0degrees) => 0.0
cos1(0degrees) => 1.0
sin1(90degrees) => 1.0
cos1(90degrees) => 0.0
sin1(180degrees) => 0.0
cos1(180degrees) => -1.0
sin1(270degrees) => -1.0
cos1(270degrees) => 0.0
sin1(360degrees) => 0.0
cos1(360degrees) => 1.0
1st Quadrant
sin1((0+1e-5)*degrees) => 1.74413620095247e-07
cos1((0+1e-5)*degrees) => 0.999999999999985
sin1((0+1e-6)*degrees) => 1.49011611938477e-08
cos1((0+1e-6)*degrees) => 1.0 # this pair violates (3)
sin1((0+1e-7)*degrees) => 0.0 # correct now for
cos1((0+1e-7)*degrees) => 1.0 # both as angle gets
sin1((0+1e-8)*degrees) => 0.0 # closer and closer
cos1((0+1e-8)*degrees) => 1.0 # to x-axis
4th Quandrant
sin1((0-1e-5)*degrees) => -1.74413620095247e-07
cos1((0-1e-5)*degrees) => 0.999999999999985
sin1((0-1e-6)*degrees) => -1.49011611938477e-08
cos1((0-1e-6)*degrees) => 1.0 # this pair violates (3)
sin1((0-1e-7)*degrees) => 0.0 # correct now for
cos1((0-1e-7)*degrees) => 1.0 # both as angle gets
sin1((0-1e-8)*degrees) => 0.0 # closer and closer
cos1((0-1e-8)*degrees) => 1.0 # to x-axis
Also for 4th Quadrant
sin1((360-1e-5)*degrees)=> -1.74413620095247e-07
cos1((360-1e-5)*degrees)=> 0.999999999999985
sin1((360-1e-6)*degrees)=> -1.49011611938477e-08
cos1((360-1e-6)*degrees)=> 1.0 # this pair violates (3)
sin1((360-1e-7)*degrees)=> 0.0 # correct now for
cos1((360-1e-7)*degrees)=> 1.0 # both as angle gets
sin1((360-1e-8)*degrees)=> 0.0 # closer and closer
cos1((360-1e-8)*degrees)=> 1.0 # to x-axis
This shows that the precision, or the smallest unit value
of an angle you can resolve, is on the order of |1e-5| at x|y-axis.
Any thing smaller provides no precision toward the answer, no matter
how many decimal places past this point you choose to calculate. These
are the most non-linear regions in the series expansion for cos|sin.
The same effect occurs as you increase the angle size,
but you can get greater precision (angle resolution),
with the greatest resolution occurring at |45| degrees.
Here, you get about |1e-14| degrees of angular precsion.
ie, as you go from 45-1e-14 > 45-1e-15 cos|sin stay the
same for smaller and smaller delta angles.
Now, sin1|cos1 (and tan1=sin1/cos1) meet the mathematical
requirements of (1),(2),(3) and are as inherently precise
as the underlying trig lib, and can become more precise as the trig
lib functions get better and/or the cpu size grows
They can NEVER BE WORSE than the native trig lib functions, and will
ALWAYS be mathematically MORE accurate, because they are DESIGNED to
meet mathematical trig requirements.
I would PROPOSE that Ruby adopt the structure presented
here and implement them in the C source to make them as
fast and efficient to compute as possible.
I would ENCOURAGE people to actually run|test the code
against the present trig functions to see for themselves
that they work for ALL angles.
This was done with Ruby 1.9.1p243 on Intel P4 cpu system.