# Trig value errors

Hardware: 32-bit Intel P4 cpu

The following examples below show what I consider
to be ‘mathematical’ errors (to distinguish from
‘arithmetic’ errors) for sin, cos, and tan.

The problem is that for cos(x)/sin(x), from the
mathematical perspective, and their requirements,
whatever value of x that causes sin/[cos] = -1/+1
REQUIRES cos/[sin] of x MUST BE ZERO - cos/[sin]=0

Ruby 1.9.1p243 output below

1)onedegree =2*PI/360 =>0.0241660973353061

2)cos onedgree =>0.999847695156391
3)sin onedgree =>0.0241637452361323

4)cos onedegree/1e05 =>0.999999999999971
5)sin onedegree/1e05 =>2.41660973353059e-07

6)cos onedegree/1e06 =>1.0
7)sin onedegree/1e06 =>2.41660973353061e-08

8)cos onedegree/1e07 =>1.0
9)sin onedegree/1e07 =>2.41660973353061e-09

10)cos 0 =>1.0
11)sin 0 =>0.0

12)cos PI/2 =>6.123023176911189e-17
13)sin PI/2 =>1.0

14)cos PI =>-1.0
15)sin PI => 1.22460635382238e-16

16)cos 3PI/2 =>-1.83690953073357e-16
17)sin 3
PI/2 =>-1.0

18)cos 2PI => 1.0
19)sin 2
PI =>-2.44921970764475e-16

Examples 4)-9) show that at some point for cos a
decision was made to fix (roundoff.truncation,?)
cos(of a very smal number) = 1.0, however,
the implementation doesn’t make that (necessary)
decision to set the sin of that angle equal to 0.
In fact, I gave up after sin(onedegree/1e100) to

10)-19) show the errors for cos/sin for angles
that correspond to the x/y axis as the angle traverses
the unit circle ccw from 0 - 2*PI. These errors also
affect the tan functions in the same manner.

It would greatly enhance the use of Ruby in scientific
and engineering domains if Ruby implemented the trig
functions so that MATH done with the trig functions
produce exact results for all angles on the axis.

The values in 12), 15), 16) and 19) are so small they
represent |delta angles| that would hardly be encountered
to represent real physical events, even in astrophysics,
or quantum mechanics. And if someone REALLY needed to calculate trig
values for angles that small they can
use Mathmematica, etc, or better SAGE (OSS symbolic
math program, done in Python: www.sagemath.org/).

These fixes should be fairly simple to implement by
putting the relevant checks on the inputs to the trig
functions to set the outputs to ‘0’ for the values of
the angles = n*PI/2 for n = any integer, when needed.
It may be as simple as representing cos(x) = sin(x+PI/2)
or vice versa. Or even simpler, check the output of the
current functions and set to zero if the absolute value
is smaller than some real-life epsilon (1e-10 ?)

Just make the defaults give the correct results.

Yes, it’s a little more work in the core.
Yes, it may make for slower functions, if anyone cares.

But…being able to do ACCURATE MATH creates benefits
that far supercede any hassles to write the core to do it.
I can see Ruby’s use in academia, science, and engineering being more
accepting if it reduces unnecessary quirks with trig functions, so
people get what they expect when doing basic operations. It may even
impress people to see Ruby’s concern for detail placed in such high
regard. Finally, this violates the POLS for trigs, because, after
all, the whole point is to make the language make me happy, not the
other way around.

On 23.12.2009 03:10, jzakiya wrote:

But…being able to do ACCURATE MATH creates benefits
that far supercede any hassles to write the core to do it.

Floats won’t be properly accurate in a mathematical sense, anyway, since
they are approximations. Their accuracy is highly dependend on the WORD
length of a CPU / Mathematical Co-processor (i.e. 8bit, 16bit, 32bit,
64bit, 128bit, etc).

Further reading provides: IEEE 754-2008 revision - Wikipedia

Your apparently required level of accuracy is the realm of specialized
math libraries, if not specialized languages and/or hardware, since it
isn’t needed in most (any?) circumstances by Average J. Programmer. Only
a select few of us get to write code for, say, CERN. Then there’s existing code to consider. AFAIK, IEEE 754 is the way Ruby
handles floating point numbers, and there will be code that relies,
for better or for worse, on this behavior (and rather rightly, since
IEEE 754 is the accepted standard to handle floats), and a higher level
of accuracy could cause quite a number of ripple effects, requiring a
carefully planned change (maybe an eventual Ruby 2.0 even).

On Dec 22, 9:38 pm, Phillip G. [email protected] wrote:

Further reading provides:IEEE 754-2008 revision - Wikipedia
of accuracy could cause quite a number of ripple effects, requiring a
carefully planned change (maybe an eventual Ruby 2.0 even).

Phillip G.

The reason I made the distinction between ‘mathematical’ versus
‘arithmetical’ accuracy is because ‘mathematical’ accuracy, in the
case of the trig values, REQUIRES the
trig values on an axis to defined as +1, -1, or 0.

There are no mathematical ambiguities at these points.

The issue I am raising is not a floating point issue, or how you
choose to compute the trig values (series expansion, or whatever). I’m
saying the current trigs implementations has by design (a choice of
priorities) decided to return mathematically erroneous results, even
though they may be computed arithmetically accurate.

I am requesting that the trig functions return the correct
‘mathematically’ results that are inherent for the specific cases for
angles n*PI/2, which REQUIRES that sin/cos=1,0,-1. As I showed in my
examples, this decision is being done in some cases, but not others.

We know cos(PI/2)=0 not 6.123023176911189e-17, so round
it, truncate, whatever, to 0. Make it mathematically correct by
whatever arithmetic process you choose.

It’s not about how many decimal places of arithmetic accuracy being
represented, it’s a matter of conceptual accuracy that the language
has MADE A CHOICE not to satisfy.

On Dec 22, 7:08 pm, jzakiya [email protected] wrote:

Hardware: 32-bit Intel P4 cpu
[snip]
Ruby 1.9.1p243 output below

1)onedegree =2*PI/360 =>0.0241660973353061

Seriously? I don’t believe it. Here’s what I get:

irb(main):001:0> RUBY_VERSION
=> “1.9.1”
irb(main):002:0> include Math
=> Object
irb(main):003:0> onedegree = 2*PI/360
=> 0.0174532925199433

That’s HUGELY different from the value you get. I am now suspicious of

6)cos onedegree/1e06 =>1.0

Sort of. Here’s what I get:

irb(main):004:0> x = cos(onedegree/1e06)
=> 1.0
irb(main):005:0> x - 1.0
=> -1.11022302462516e-16
irb(main):006:0> puts “%.30f” % x
0.999999999999999888977697537484

Examples 4)-9) show that at some point for cos a
decision was made to fix (roundoff.truncation,?)
cos(of a very smal number) = 1.0

False. What they show is that the string representation of floating
point values doesn’t always show you the full picture.

jzakiya wrote

We know cos(PI/2)=0 not 6.123023176911189e-17,
so round it, truncate, whatever, to 0.

But Ruby PI is not (exactly) the mathematical pi,
so it’s going to be difficult to decide in cos(x),
with x very close to pi/2, whether x was “really” pi/2,
or something a bit different from pi/2 ?

Phrogz wrote:

I thought asking Alpha would be an easy place to start.

http://www.wolframalpha.com

I didn’t know about WolframAlpha! Thanks!
sin(pi/2) #=> 1
tan(pi/2) #=> infinity; so far, so good
sin(pi0.5) #=> 1
sin(pi
0.5) - 1 #=> 0 “number name zero”, so it is zero!
tan(pi*0.5) #=> 1.63312 x 10^16
(Actually in some ways I find that last result
a little surprising, because floating point
holds 0.5 exactly. But also not surprising!)

Since Fleck Jean-Julien mentioned Octave:

Well, what you are looking for is … or Octave,
some kind of symbolic mathematics software.
… But even there you can still quite easily find
“mathematical bugs” that is results that are not in the
simplest form expected even by my least gifted students.

A naive user (me) of Octave gets:
sin(pi/2) #=> 1
cos(pi/2) #=> 6.123…189e-017
(By naive, I mean that a more experienced user
might be able to do better than that.)

On Dec 22, 10:07 pm, Phrogz [email protected] wrote:

irb(main):004:0> x = cos(onedegree/1e06)
=> 1.0
irb(main):005:0> x - 1.0
=> -1.11022302462516e-16
irb(main):006:0> puts “%.30f” % x
0.999999999999999888977697537484

As an interesting and related aside, I wanted to find out what the
correct value for this calculation was (to a certain number of
decimals). I thought asking Alpha would be an easy place to start.

This query (which has the parameter off by a factor of 1000) works:

and results in:
0.9999999998476912901

Trying for smaller parameter values, however, results in Alpha giving
up:

(For me, that query always results in a message: “This Wolfram|Alpha
server is temporarily unavailable.”)

On 23.12.2009 08:15, jzakiya wrote:

This didn’t nullify THE POINT I illustrated, which was
using an increasingly smaller angle approaching zero as
an argument, it eventually produced a value of ‘1’ for
cos, but not ‘0’ for the same sin angle, as it should.

How many real world (as in, reality, out in the wild, where money and
lives matter) cases do you know where a) Ruby is used for these
calculations and b) these calculations matter?

I feel I’ve made my points as clear as I think is needed.
If it doesn’t bother you that the present implementation produces
incorrect results for clearly unambiguous
situations then we just have different standards for the
need to adhere to mathematical rigor and produce exact
results. BUT THAT IS A CHOICE THAT HUMANS MAKE, AND IS
NOT MANDATED BY NATURE.

A core tenent of mathematical rigor is consistency. Ruby is
consistent. The results are, within the limitations already elaborated
on earlier, correct, too.

If you need higher accuracy, you need a different tool.

Now to something no mathematician worth his or her salt likes to hear:
Math is not observed in nature. Math is a support science for physics,
to help describe actual, observeable, phenomena, and express theories
and formulae in an unambiguous manner, as well as in an abstract manner
to allow the manipulation of said formulae.

On Dec 23, 12:11 am, jzakiya [email protected] wrote:

On Dec 22, 10:07 pm, Phrogz [email protected] wrote:

irb(main):004:0> x = cos(onedegree/1e06)
=> 1.0
irb(main):005:0> x - 1.0
=> -1.11022302462516e-16
irb(main):006:0> puts “%.30f” % x
0.999999999999999888977697537484

This didn’t nullify THE POINT I illustrated, which was
using an increasingly smaller angle approaching zero as
an argument, it eventually produced a value of ‘1’ for
cos, but not ‘0’ for the same sin angle, as it should.

No, it didn’t produce a value of 1. Look at the second part of my
post, which you quoted, at the top of this message.

2009/12/23 jzakiya [email protected]:

As an interesting and related aside, I wanted to find out what the
server is temporarily unavailable.")
an argument, it eventually produced a value of ‘1’ for
cos, but not ‘0’ for the same sin angle, as it should.

I feel I’ve made my points as clear as I think is needed.
If it doesn’t bother you that the present implementation produces
incorrect results for clearly unambiguous
situations then we just have different standards for the
need to adhere to mathematical rigor and produce exact
results. BUT THAT IS A CHOICE THAT HUMANS MAKE, AND IS
NOT MANDATED BY NATURE.

Please don’t shout. Not sure what the term “nature” means here.
AFAIK mathematics are a human invention…

def tan(x); sin(x)/cos(x) end

If you want define: TRIG-EPSILON = 1e-11, or whatever,
so you can change it easily and make it available.

With these simple changes you even get the added benefit
that tan(PI/2) => Infinity as it should (1/0), instead of
currently tan(PI/2) => 1.63317787283838e16

This would be a bad idea. As John stated already, values returned
from these functions are mandated by IEEE 754 standard. Changing how
these fundamental functions behave is calling for trouble. The very
moment you do that, completely unrelated code may break.

If you insist on getting the results you are expecting there’s nothing
stopping you from defining your own versions under a different name
and use those in your calculations. Otherwise you should use a system
for symbolic math as Jean-Julien suggested.

Btw, your own example proves that we are talking about an arithmetic
error and not a mathematical error. A mathematical error in my eyes
would be if Math.sin(Math::PI / 2) returned something negative.

Kind regards

robert

Further reading: IEEE 754 - Wikipedia

You can also search the archives for “rounding error” or “bug float”
and will find more than enough material.

Again, one really simple fix to eliminate these ERRORS

Well, what you are looking for is Maple, Mathematica or Octave, some
kind of symbolic mathematics software.
They all have worked very hard to make all those kind of things
consistent in a mathematical point of view. But even there you can
still quite easily find “mathematical bugs” that is results that are
not in the simplest form expected even by my least gifted students.

Cheers,

On Dec 23, 12:42 am, Phrogz [email protected] wrote:

correct value for this calculation was (to a certain number of
decimals). I thought asking Alpha would be an easy place to start.

This query (which has the parameter off by a factor of 1000) works:cos( 2*pi / 360 / 1e3 ) - Wolfram|Alpha
and results in:
0.9999999998476912901

Trying for smaller parameter values, however, results in Alpha giving
up:cos( 2*pi / 360 / 1e4 ) - Wolfram|Alpha
(For me, that query always results in a message: “This Wolfram|Alpha
server is temporarily unavailable.”)

You are correct, arithmetically:

2*PI/360 => 0.0174532925199433 # equiv to 1.0 degree

I incorrectly wrote in the post the value for:
2*PI/260 => 0.0241660973353061 # equiv to 1.38 degree

This didn’t nullify THE POINT I illustrated, which was
using an increasingly smaller angle approaching zero as
an argument, it eventually produced a value of ‘1’ for
cos, but not ‘0’ for the same sin angle, as it should.

I feel I’ve made my points as clear as I think is needed.
If it doesn’t bother you that the present implementation produces
incorrect results for clearly unambiguous
situations then we just have different standards for the
need to adhere to mathematical rigor and produce exact
results. BUT THAT IS A CHOICE THAT HUMANS MAKE, AND IS
NOT MANDATED BY NATURE.

Again, one really simple fix to eliminate these ERRORS
is to do something like the following in the Math module.

rename current functions as follows:
cos > cosine; sin > sine, tan > tangent

then redefine old aliases so that:

def cos(x); cosine(x).abs < 1e-11 ? 0.0 : cosine(x) end
def sin(x); sine(x).abs < 1e-11 ? 0.0 : sin(x) end
def tan(x); sin(x)/cos(x) end

If you want define: TRIG-EPSILON = 1e-11, or whatever,
so you can change it easily and make it available.

With these simple changes you even get the added benefit
that tan(PI/2) => Infinity as it should (1/0), instead of
currently tan(PI/2) => 1.63317787283838e16

On Wed, Dec 23, 2009 at 2:03 PM, Phillip G. [email protected]
wrote:

On 23.12.2009 08:15, jzakiya wrote:

This didn’t nullify THE POINT I illustrated, which was
using an increasingly smaller angle approaching zero as
an argument, it eventually produced a value of ‘1’ for
cos, but not ‘0’ for the same sin angle, as it should.

No, it didn’t.

irb(main):020:0> x = cos(onedegree/1e06)
=> 1.0
irb(main):021:0> x - 1.0
=> -1.11022302462516e-016

In the first line, I assign x the value of cos(small). The irb output
of that number is 1.0. In the second line however, I show that x
cannot be equal to 1.0, as there is a non-zero difference between
them. (This is why you never check for equality of floats like this)

So, cos(small) only looks like 1.0, it isn’t actually equal to 1.0.
Therefore it’s not really much surprise than sin(small) isn’t 0.

Paul S.

[email protected]

On Dec 22, 8:47Â pm, jzakiya [email protected] wrote:

We know cos(PI/2)=0 not 6.123023176911189e-17, so round
it, truncate, whatever, to 0. Make it mathematically correct by
whatever arithmetic process you choose.

We know that cos( Ï€/2 ) = 0, yes. But Math::PI â‰ Ï€. Math::PI â‰ˆ Ï€.
Similarly, Math::PI/2 â‰ Ï€/2, so of course it’s reasonable to say that
Math.cos( Math::PI/2 ) â‰ˆ 0.0, but perhaps not exactly.

9e-17 is insignificantly small. Perhaps you want to round or truncate?

I’m
saying the current trigs implementations has by design (a choice of
priorities) decided to return mathematically erroneous results, even
though they may be computed arithmetically accurate.

It’s not about how many decimal places of arithmetic accuracy being
represented, it’s a matter of conceptual accuracy that the language
has MADE A CHOICE not to satisfy.

Can you explain why you keep making the assertion that someone has
made a choice to purposefully return what you deem incorrect results?
Is there source code for Math.cos where you’ve found a condition that
chooses to return 0 below a certain threshold? Or are you convinced
someone made a choice based on your anecdotal results of passing in
very small floating point numbers?

Good Evening,

On Tue, Dec 22, 2009 at 7:50 PM, jzakiya [email protected] wrote:

it’s a matter of conceptual accuracy that the language
has MADE A CHOICE not to satisfy.

First, the choice was not made by Ruby - you might want to do a little
homework in the future and see how the calculations are performed. Ruby
(and
Python as far as I can see from their man pages) utilize the C standard
for
trig calculations. This allows Ruby to simply wrap standard functions to
handle the calculations. Standards that are used in a very large and
wide
variety of programs and languages. Because they are standards, it most
likely means an awful lot of thought went into them to decide the where
and
when and how of accuracy.

Unfortunately, it seems that you have needs which go above and beyond
the C
standard. Something like the GNU HPA (High Precision Arithmetic Library)
might
be something you need an interface to (although it might not be any
better
for you at the end of the day).

project
doesn’t always garner the attention of everyone. We all hate the corner
edges - but people are constantly trying to round (no pun intend) them
off
as best they can. Things keep getting better every day and asking why
something exists as opposed to accusing the community of messing with
you

John

If you want more precision, you could use BigDecimal (and BigMath).
Then you would get something like:

irb(main):025:0> p=2000; cos(PI(p)/2, p).to_s
=> “0.64773210554205705…E-2016”
irb(main):026:0> p=2000; sin(PI(p)/2, p).to_s
=> “0.99999999999999999999999999999999999999…E0”

Well, I think it’s safe to round the 2016th decimal, isn’t it ?
Also rounding a ton of 9.

So, rounding to the precision(2000), you get what you want.

irb(main):036:0> p=20; cos(PI(p)/2, p).round(p).to_f
=> 0.0
irb(main):037:0> p=20; sin(PI(p)/2, p).round(p).to_f
=> 1.0

And well, you really don’t need 2000 of precision, 20 is far enough in
this
case.

2009/12/23 Phrogz [email protected]

On 23.12.2009 17:32, Colin B. wrote:

chemistry, etc, etc! And for a “support science” it does
rather well, frequently discovering/inventing (depending
before physicists realised they needed them!
But to be fair, there is a two-way traffic.

Well, if me and my professors had a choice, we wouldn’t bother with
maths (I’m in college to get an engineering degree), so I’m quiet
oviously jsut a little biased. And while maths, unlike other support sciences does have decent, and
interesting research all of its own, if it weren’t for sciences that
need maths, nobody would need it, and it would find itself in the same
thankless corner as philosophy: Undervalued as well as underappreciated.

For example, I like the beauty of maths in music, and the visualization
of Mandelbrot fractals, and feel that maths can stand on its own very,
very well. Mind, I’m not putting down maths as a field of science, at all! It has
established itself firmly in the science community, otherwise there
wouldn’t be dedicated math degrees. And it is indeed true that maths makes life easier, for quite near
everyone.

Robert K. wrote:

… Not sure what the term “nature” means here.
AFAIK mathematics are a human invention …

Are you sure about that? I think there are differing views
even amongst mathematicians: some agree with you,
but I think the majority vote (for now) is for “Realism”,
in one of its several flavours.

Phillip G. wrote:

Now to something no mathematician worth his or her salt
likes to hear: Math is not observed in nature.
Math is a support science for physics,
to help describe actual, observeable, phenomena,
and express theories and formulae in an unambiguous manner,
as well as in an abstract manner to allow
the manipulation of said formulae.

That’s a bit limiting: it’s also very useful in engineering,
chemistry, etc, etc! And for a “support science” it does
rather well, frequently discovering/inventing (depending
before physicists realised they needed them!
But to be fair, there is a two-way traffic.

(A warning for readers: my degree is in maths,
but I am not a mathematician!)

Dear Matz,

I use a Linux calculator named Qaculate.
I do not know the people who designed and
coded it, but it makes me happy. Why?

When I put in sin(180) it outputs ‘0’
not 1.22460635382238e-16, and when I change
to radians for angles and do sin(PI) it
also gives ‘0’ and not 1.22460635382238e-16.

This makes me happy.

In fact, this little Linux calculator produces
all the correct (exact) answers for angles on
an axis for both cos and sin, whether you input
the angles in degrees or radians. Astonishing!!

I don’t now anything about how the people who
designed and implemented Qalculate decided to
use whatever language they chose to write it in,
or what libraries they decided to use. I don’t
know (or care) about any of those under-the-hood
things.

What I do KNOW is that the people who designed and
implemented this calculator CARED that it produced
the mathematically exact results for those angles.

This makes me happy.

I use another add-on calculator for Firefox, called,
tada! Calculator. Again, I don’t know the people who
designed and/or coded it, and I don’t know what
language or libraries they used to do it in either.
But when I use this little calculator in Firefox I do
know I get sin(PI) = 0, not 1.22460635382238e-16.

So, for this calculator too, somebody(s) CARED enough
to make sure the answers came out correctly (exact)
for angles on an axis too. So when I use this calculator,

This makes me happy.

I think Ruby is a Great language, and a fun language.
And I agree with your philosophy that languages that
people use should serve them, not the other way around.

So I humbly tell you I am Surprised that Ruby produces
the math errors I’ve illustrated in this thread, and

This makes me unhappy.

So I am asking you to see that these errors be fixed.

If Qaculator and Calculator can produce the correct
results, then so can Ruby. All that is necessary is that
you CARE enough that it does it.

It would make me very happy if I could share my code, and
not have to include patches and redefinitions in it just
to assure other people get the same (exact) results I do.

I agree with your Principle of Least Surprises (POLS).

The language should work to please the user.
The language should be intuitive to the user.
The language should not cause unnecessary surprises.

This will make me happy.

Thanks

On 2009-12-23, jzakiya [email protected] wrote:

I use a Linux calculator named Qaculate.
I do not know the people who designed and
coded it, but it makes me happy. Why?

Because it’s not using IEEE 754 floats.

So I am asking you to see that these errors be fixed.

All your ranting misses the point.

THE RESULTS YOU ARE GETTING ARE MANDATED BY AN INTERNATIONAL STANDARD,
AND EVERY PIECE OF MATHEMATICAL CODE WRITTEN IN ANY LANGUAGE FOR THE
LAST
TWO DECADES WHICH DOES NOT PROVIDE ITS OWN ARITHMETIC LIBRARIES FOR
SPECIAL PURPOSES HAS ONLY BEEN TESTED WITH THESE RESULTS FROM THESE
INPUTS.

Changing this would break EVERYTHING.

Here’s a suggestion: Write a class which provides the semantics you
want,
and use it instead of floating point numbers. The semantics of floating
point values are very rigidly defined, and failure to generate the exact
same behaviors as other systems would be MUCH worse than generating