Why does Math.Tan(90) provide a non-undefined value? - c#

While working with Math.Tan() I found that the result for 90 degree is not undefined. But is, inturn 1.6331779e+16
Here is the screenshot for the app
Here is the code,
// convert to degrees
angle = (Convert.ToDouble(op1) * Math.PI / 180);
// write the output
FinalResult.Text = Math.Tan(Convert.ToDouble(angle)).ToString();
Why is such behaviour, is it expected?

This question has been addressed (and answered, quite thoroughly) over on https://math.stackexchange.com/ in the question Why does the google calculator give tan 90 degrees = 1.6331779e+16?
or in other words ... You need to read David Goldberg's paper, What Every Computer Scientist Should Know About Floating-Point Arithmetic. You can purchase a copy from the ACM (or download one if you are a member of the ACM) at http://dl.acm.org/citation.cfm?id=103163. Other versions are available, gratis, as well.
A copy of the original is at http://perso.ens-lyon.fr/jean-michel.muller/goldberg.pdf. Also:
http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
https://ece.uwaterloo.ca/~dwharder/NumericalAnalysis/02Numerics/Double/paper.pdf
And CiteSeer links to other locations as well:
http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.22.6768

The calculation is done with floating point numbers which are not perfect (not that Math.PI can ever be perfectly represented as a decimal anyways).
http://en.wikipedia.org/wiki/Floating_point
and more specifically..
https://math.stackexchange.com/questions/536144/why-does-the-google-calculator-give-tan-90-degrees-1-6331779e16
If you want a rounded result then check the input for something like >89.9999 && <90.00001. Don't use == with floating point values.
For explanation of why not to use == with floating point numbers, try running this example:
var d = 0.2;
for(double k = 1.0; k<100; k++) {
var t = 0.2 * k;
t = t / k;
Console.WriteLine("{0} == {1} ==> {2}", d, t, d == t);
}
We're multiplying 0.2 by a whole number, dividing it by the same whole number, and then comparing to 0.2. It should be true every time, right? It's not. Many times it returns false.

Related

Why doesnt check the count? Still counting but doesnt check [duplicate]

I'm currently writing some code where I have something along the lines of:
double a = SomeCalculation1();
double b = SomeCalculation2();
if (a < b)
DoSomething2();
else if (a > b)
DoSomething3();
And then in other places I may need to do equality:
double a = SomeCalculation3();
double b = SomeCalculation4();
if (a == 0.0)
DoSomethingUseful(1 / a);
if (b == 0.0)
return 0; // or something else here
In short, I have lots of floating point math going on and I need to do various comparisons for conditions. I can't convert it to integer math because such a thing is meaningless in this context.
I've read before that floating point comparisons can be unreliable, since you can have things like this going on:
double a = 1.0 / 3.0;
double b = a + a + a;
if ((3 * a) != b)
Console.WriteLine("Oh no!");
In short, I'd like to know: How can I reliably compare floating point numbers (less than, greater than, equality)?
The number range I am using is roughly from 10E-14 to 10E6, so I do need to work with small numbers as well as large.
I've tagged this as language agnostic because I'm interested in how I can accomplish this no matter what language I'm using.
TL;DR
Use the following function instead of the currently accepted solution to avoid some undesirable results in certain limit cases, while being potentially more efficient.
Know the expected imprecision you have on your numbers and feed them accordingly in the comparison function.
bool nearly_equal(
float a, float b,
float epsilon = 128 * FLT_EPSILON, float abs_th = FLT_MIN)
// those defaults are arbitrary and could be removed
{
assert(std::numeric_limits<float>::epsilon() <= epsilon);
assert(epsilon < 1.f);
if (a == b) return true;
auto diff = std::abs(a-b);
auto norm = std::min((std::abs(a) + std::abs(b)), std::numeric_limits<float>::max());
// or even faster: std::min(std::abs(a + b), std::numeric_limits<float>::max());
// keeping this commented out until I update figures below
return diff < std::max(abs_th, epsilon * norm);
}
Graphics, please?
When comparing floating point numbers, there are two "modes".
The first one is the relative mode, where the difference between x and y is considered relatively to their amplitude |x| + |y|. When plot in 2D, it gives the following profile, where green means equality of x and y. (I took an epsilon of 0.5 for illustration purposes).
The relative mode is what is used for "normal" or "large enough" floating points values. (More on that later).
The second one is an absolute mode, when we simply compare their difference to a fixed number. It gives the following profile (again with an epsilon of 0.5 and a abs_th of 1 for illustration).
This absolute mode of comparison is what is used for "tiny" floating point values.
Now the question is, how do we stitch together those two response patterns.
In Michael Borgwardt's answer, the switch is based on the value of diff, which should be below abs_th (Float.MIN_NORMAL in his answer). This switch zone is shown as hatched in the graph below.
Because abs_th * epsilon is smaller that abs_th, the green patches do not stick together, which in turn gives the solution a bad property: we can find triplets of numbers such that x < y_1 < y_2 and yet x == y2 but x != y1.
Take this striking example:
x = 4.9303807e-32
y1 = 4.930381e-32
y2 = 4.9309825e-32
We have x < y1 < y2, and in fact y2 - x is more than 2000 times larger than y1 - x. And yet with the current solution,
nearlyEqual(x, y1, 1e-4) == False
nearlyEqual(x, y2, 1e-4) == True
By contrast, in the solution proposed above, the switch zone is based on the value of |x| + |y|, which is represented by the hatched square below. It ensures that both zones connects gracefully.
Also, the code above does not have branching, which could be more efficient. Consider that operations such as max and abs, which a priori needs branching, often have dedicated assembly instructions. For this reason, I think this approach is superior to another solution that would be to fix Michael's nearlyEqual by changing the switch from diff < abs_th to diff < eps * abs_th, which would then produce essentially the same response pattern.
Where to switch between relative and absolute comparison?
The switch between those modes is made around abs_th, which is taken as FLT_MIN in the accepted answer. This choice means that the representation of float32 is what limits the precision of our floating point numbers.
This does not always make sense. For example, if the numbers you compare are the results of a subtraction, perhaps something in the range of FLT_EPSILON makes more sense. If they are squared roots of subtracted numbers, the numerical imprecision could be even higher.
It is rather obvious when you consider comparing a floating point with 0. Here, any relative comparison will fail, because |x - 0| / (|x| + 0) = 1. So the comparison needs to switch to absolute mode when x is on the order of the imprecision of your computation -- and rarely is it as low as FLT_MIN.
This is the reason for the introduction of the abs_th parameter above.
Also, by not multiplying abs_th with epsilon, the interpretation of this parameter is simple and correspond to the level of numerical precision that we expect on those numbers.
Mathematical rumbling
(kept here mostly for my own pleasure)
More generally I assume that a well-behaved floating point comparison operator =~ should have some basic properties.
The following are rather obvious:
self-equality: a =~ a
symmetry: a =~ b implies b =~ a
invariance by opposition: a =~ b implies -a =~ -b
(We don't have a =~ b and b =~ c implies a =~ c, =~ is not an equivalence relationship).
I would add the following properties that are more specific to floating point comparisons
if a < b < c, then a =~ c implies a =~ b (closer values should also be equal)
if a, b, m >= 0 then a =~ b implies a + m =~ b + m (larger values with the same difference should also be equal)
if 0 <= λ < 1 then a =~ b implies λa =~ λb (perhaps less obvious to argument for).
Those properties already give strong constrains on possible near-equality functions. The function proposed above verifies them. Perhaps one or several otherwise obvious properties are missing.
When one think of =~ as a family of equality relationship =~[Ɛ,t] parameterized by Ɛ and abs_th, one could also add
if Ɛ1 < Ɛ2 then a =~[Ɛ1,t] b implies a =~[Ɛ2,t] b (equality for a given tolerance implies equality at a higher tolerance)
if t1 < t2 then a =~[Ɛ,t1] b implies a =~[Ɛ,t2] b (equality for a given imprecision implies equality at a higher imprecision)
The proposed solution also verifies these.
Comparing for greater/smaller is not really a problem unless you're working right at the edge of the float/double precision limit.
For a "fuzzy equals" comparison, this (Java code, should be easy to adapt) is what I came up with for The Floating-Point Guide after a lot of work and taking into account lots of criticism:
public static boolean nearlyEqual(float a, float b, float epsilon) {
final float absA = Math.abs(a);
final float absB = Math.abs(b);
final float diff = Math.abs(a - b);
if (a == b) { // shortcut, handles infinities
return true;
} else if (a == 0 || b == 0 || diff < Float.MIN_NORMAL) {
// a or b is zero or both are extremely close to it
// relative error is less meaningful here
return diff < (epsilon * Float.MIN_NORMAL);
} else { // use relative error
return diff / (absA + absB) < epsilon;
}
}
It comes with a test suite. You should immediately dismiss any solution that doesn't, because it is virtually guaranteed to fail in some edge cases like having one value 0, two very small values opposite of zero, or infinities.
An alternative (see link above for more details) is to convert the floats' bit patterns to integer and accept everything within a fixed integer distance.
In any case, there probably isn't any solution that is perfect for all applications. Ideally, you'd develop/adapt your own with a test suite covering your actual use cases.
I had the problem of Comparing floating point numbers A < B and A > B
Here is what seems to work:
if(A - B < Epsilon) && (fabs(A-B) > Epsilon)
{
printf("A is less than B");
}
if (A - B > Epsilon) && (fabs(A-B) > Epsilon)
{
printf("A is greater than B");
}
The fabs--absolute value-- takes care of if they are essentially equal.
We have to choose a tolerance level to compare float numbers. For example,
final float TOLERANCE = 0.00001;
if (Math.abs(f1 - f2) < TOLERANCE)
Console.WriteLine("Oh yes!");
One note. Your example is rather funny.
double a = 1.0 / 3.0;
double b = a + a + a;
if (a != b)
Console.WriteLine("Oh no!");
Some maths here
a = 1/3
b = 1/3 + 1/3 + 1/3 = 1.
1/3 != 1
Oh, yes..
Do you mean
if (b != 1)
Console.WriteLine("Oh no!")
Idea I had for floating point comparison in swift
infix operator ~= {}
func ~= (a: Float, b: Float) -> Bool {
return fabsf(a - b) < Float(FLT_EPSILON)
}
func ~= (a: CGFloat, b: CGFloat) -> Bool {
return fabs(a - b) < CGFloat(FLT_EPSILON)
}
func ~= (a: Double, b: Double) -> Bool {
return fabs(a - b) < Double(FLT_EPSILON)
}
Adaptation to PHP from Michael Borgwardt & bosonix's answer:
class Comparison
{
const MIN_NORMAL = 1.17549435E-38; //from Java Specs
// from http://floating-point-gui.de/errors/comparison/
public function nearlyEqual($a, $b, $epsilon = 0.000001)
{
$absA = abs($a);
$absB = abs($b);
$diff = abs($a - $b);
if ($a == $b) {
return true;
} else {
if ($a == 0 || $b == 0 || $diff < self::MIN_NORMAL) {
return $diff < ($epsilon * self::MIN_NORMAL);
} else {
return $diff / ($absA + $absB) < $epsilon;
}
}
}
}
You should ask yourself why you are comparing the numbers. If you know the purpose of the comparison then you should also know the required accuracy of your numbers. That is different in each situation and each application context. But in pretty much all practical cases there is a required absolute accuracy. It is only very seldom that a relative accuracy is applicable.
To give an example: if your goal is to draw a graph on the screen, then you likely want floating point values to compare equal if they map to the same pixel on the screen. If the size of your screen is 1000 pixels, and your numbers are in the 1e6 range, then you likely will want 100 to compare equal to 200.
Given the required absolute accuracy, then the algorithm becomes:
public static ComparisonResult compare(float a, float b, float accuracy)
{
if (isnan(a) || isnan(b)) // if NaN needs to be supported
return UNORDERED;
if (a == b) // short-cut and takes care of infinities
return EQUAL;
if (abs(a-b) < accuracy) // comparison wrt. the accuracy
return EQUAL;
if (a < b) // larger / smaller
return SMALLER;
else
return LARGER;
}
The standard advice is to use some small "epsilon" value (chosen depending on your application, probably), and consider floats that are within epsilon of each other to be equal. e.g. something like
#define EPSILON 0.00000001
if ((a - b) < EPSILON && (b - a) < EPSILON) {
printf("a and b are about equal\n");
}
A more complete answer is complicated, because floating point error is extremely subtle and confusing to reason about. If you really care about equality in any precise sense, you're probably seeking a solution that doesn't involve floating point.
I tried writing an equality function with the above comments in mind. Here's what I came up with:
Edit: Change from Math.Max(a, b) to Math.Max(Math.Abs(a), Math.Abs(b))
static bool fpEqual(double a, double b)
{
double diff = Math.Abs(a - b);
double epsilon = Math.Max(Math.Abs(a), Math.Abs(b)) * Double.Epsilon;
return (diff < epsilon);
}
Thoughts? I still need to work out a greater than, and a less than as well.
I came up with a simple approach to adjusting the size of epsilon to the size of the numbers being compared. So, instead of using:
iif(abs(a - b) < 1e-6, "equal", "not")
if a and b can be large, I changed that to:
iif(abs(a - b) < (10 ^ -abs(7 - log(a))), "equal", "not")
I suppose that doesn't satisfy all the theoretical issues discussed in the other answers, but it has the advantage of being one line of code, so it can be used in an Excel formula or an Access query without needing a VBA function.
I did a search to see if others have used this method and I didn't find anything. I tested it in my application and it seems to be working well. So it seems to be a method that is adequate for contexts that don't require the complexity of the other answers. But I wonder if it has a problem I haven't thought of since no one else seems to be using it.
If there's a reason the test with the log is not valid for simple comparisons of numbers of various sizes, please say why in a comment.
You need to take into account that the truncation error is a relative one. Two numbers are about equal if their difference is about as large as their ulp (Unit in the last place).
However, if you do floating point calculations, your error potential goes up with every operation (esp. careful with subtractions!), so your error tolerance needs to increase accordingly.
The best way to compare doubles for equality/inequality is by taking the absolute value of their difference and comparing it to a small enough (depending on your context) value.
double eps = 0.000000001; //for instance
double a = someCalc1();
double b = someCalc2();
double diff = Math.abs(a - b);
if (diff < eps) {
//equal
}

How to test something like the great circle distance calculation properly?

What is the best way to test something that does not equal exact values, like the great circle calculation:
/// <summary>
/// Get the great circle distance (shortest distance possible) between two points in km.
/// </summary>
/// <param name="endPoint">end point</param>
/// <returns>the great circle distance in km</returns>
public double GreatCircleDistanceInKm(IGeoPoint endPoint)
{
var earthRadius = Constants.EARTH_RADIUS_KM;
var diffLat = Utility.DegreesToRadians(endPoint.Latitude - this.Latitude);
var diffLong = Utility.DegreesToRadians(endPoint.Longitude - this.Longitude);
var a = Math.Sin(diffLat / 2) * Math.Sin(diffLat / 2) +
Math.Cos(Utility.DegreesToRadians(this.Latitude)) * Math.Cos(Utility.DegreesToRadians(endPoint.Latitude)) *
Math.Sin(diffLong / 2) * Math.Sin(diffLong / 2);
var c = 2 * Math.Asin(Math.Min(1, Math.Sqrt(a)));
var d = earthRadius * c;
return d;
}
Currently my test is like this:
[TestMethod]
public void GeoPoint_GreatCircleDistanceInKm_IsCorrect()
{
// arrange
var startPoint = new GeoPoint(0, 45, 90); // id, lat, long
var endPoint1 = new GeoPoint(0, 45, 90);
var endPoint2 = new GeoPoint(0, 0, 0);
// act
var greatCircleDistanceZero = startPoint.GreatCircleDistanceInKm(endPoint1);
var greatCircleDistanceBig = startPoint.GreatCircleDistanceInKm(endPoint2);
// assert
Assert.AreEqual(0, greatCircleDistanceZero);
Assert.AreEqual(10007.543398010288, greatCircleDistanceBig);
}
But this seems wrong, I am finding the answer first then testing against it. How should such methods be tested? Should I go through the algorithm/calculation and try and find out how it works, so I can make it result in exact values?
Clarification:
My question is this the correct method of conducting a test for such things, ie. Should my test bound to the actual implementation (because as you see I am using a fine-grained expected value) or should it be more generic somehow?
You can use Assert.AreEqual(double expected, double actual, double delta). You should use a delta that is sufficiently small (e.g. 0.00000001). Using double.Epsilon isn't recommended here.
From MSDN:
Because Epsilon defines the minimum expression of a positive value whose range is near zero, the margin of difference between two similar values must be greater than Epsilon. Typically, it is many times greater than Epsilon. Because of this, we recommend that you do not use Epsilon when comparing Double values for equality.
To your other questions: Yes, such methods should be tested. But it is not a good idea to write tests after you inspected how the algorithm is implemented, because it may be implemented wrong. You need an overall idea what for example the method should be doing (in your case calculating the greate circle distance). Now you can specify test cases by specifying the input and the expected output. You can retrieve the expected output from another source (e.g. calculating it by hand).
A little side note: In TDD test cases are usually specified before the actual code is written. So there is no algorithm you can go through and find out how it works.
Maybe
Assert.IsTrue(Math.Abs(greatCircleDistanceZero - 0) < Double.Epsilon);
Assert.IsTrue(Math.Abs(greatCircleDistanceBig - 10007.543398010288) < Double.Epsilon);
The following table shows the distance between 2 points on the equator. As the latitude moves from the poles the NS distance is constant but EW distance decreases. As I assume using Great Circle Distance any accuracy greater than 2 decimal places in your results is redundant.
0 decimal places 1.0 = 111.32 km
1 decimal places 0.1 = 11.132 km
2 decimal places 0.01 = 1.1132 km
3 decimal places 0.001 = 111.32 m
4 decimal places 0.0001 = 11.132 m
5 decimal places 0.00001 = 1.1132 m

Evaluate if two doubles are equal based on a given precision, not within a certain fixed tolerance

I'm running NUnit tests to evaluate some known test data and calculated results. The numbers are floating point doubles so I don't expect them to be exactly equal, but I'm not sure how to treat them as equal for a given precision.
In NUnit we can compare with a fixed tolerance:
double expected = 0.389842845321551d;
double actual = 0.38984284532155145d; // really comes from a data import
Expect(actual, EqualTo(expected).Within(0.000000000000001));
and that works fine for numbers below zero, but as the numbers grow the tolerance really needs to be changed so we always care about the same number of digits of precision.
Specifically, this test fails:
double expected = 1.95346834136148d;
double actual = 1.9534683413614817d; // really comes from a data import
Expect(actual, EqualTo(expected).Within(0.000000000000001));
and of course larger numbers fail with tolerance..
double expected = 1632.4587642911599d;
double actual = 1632.4587642911633d; // really comes from a data import
Expect(actual, EqualTo(expected).Within(0.000000000000001));
What's the correct way to evaluate two floating point numbers are equal with a given precision? Is there a built-in way to do this in NUnit?
From msdn:
By default, a Double value contains 15 decimal digits of precision, although a maximum of 17 digits is maintained internally.
Let's assume 15, then.
So, we could say that we want the tolerance to be to the same degree.
How many precise figures do we have after the decimal point? We need to know the distance of the most significant digit from the decimal point, right? The magnitude. We can get this with a Log10.
Then we need to divide 1 by 10 ^ precision to get a value around the precision we want.
Now, you'll need to do more test cases than I have, but this seems to work:
double expected = 1632.4587642911599d;
double actual = 1632.4587642911633d; // really comes from a data import
// Log10(100) = 2, so to get the manitude we add 1.
int magnitude = 1 + (expected == 0.0 ? -1 : Convert.ToInt32(Math.Floor(Math.Log10(expected))));
int precision = 15 - magnitude ;
double tolerance = 1.0 / Math.Pow(10, precision);
Assert.That(actual, Is.EqualTo(expected).Within(tolerance));
It's late - there could be a gotcha in here. I tested it against your three sets of test data and each passed. Changing pricision to be 16 - magnitude caused the test to fail. Setting it to 14 - magnitude obviously caused it to pass as the tolerance was greater.
This is what I came up with for The Floating-Point Guide (Java code, but should translate easily, and comes with a test suite, which you really really need):
public static boolean nearlyEqual(float a, float b, float epsilon)
{
final float absA = Math.abs(a);
final float absB = Math.abs(b);
final float diff = Math.abs(a - b);
if (a * b == 0) { // a or b or both are zero
// relative error is not meaningful here
return diff < (epsilon * epsilon);
} else { // use relative error
return diff / (absA + absB) < epsilon;
}
}
The really tricky question is what to do when one of the numbers to compare is zero. The best answer may be that such a comparison should always consider the domain meaning of the numbers being compared rather than trying to be universal.
How about converting the items each to string and comparing the strings?
string test1 = String.Format("{0:0.0##}", expected);
string test2 = String.Format("{0:0.0##}", actual);
Assert.AreEqual(test1, test2);
Assert.That(x, Is.EqualTo(y).Within(10).Percent);
is a decent option (changes it to a relative comparison, where x is required to be within 10% of y). You may want to add extra handling for 0, as otherwise you'll get an exact comparison in that case.
Update:
Another good option is
Assert.That(x, Is.EqualTo(y).Within(1).Ulps);
where Ulps means units in the last place. See https://docs.nunit.org/articles/nunit/writing-tests/constraints/EqualConstraint.html#comparing-floating-point-values.
I don't know if there's a built-in way to do it with nunit, but I would suggest multiplying each float by the 10x the precision you're seeking, storing the results as longs, and comparing the two longs to each other.
For example:
double expected = 1632.4587642911599d;
double actual = 1632.4587642911633d;
//for a precision of 4
long lActual = (long) 10000 * actual;
long lExpected = (long) 10000 * expected;
if(lActual == lExpected) { // Do comparison
// Perform desired actions
}
This is a quick idea, but how about shifting them down till they are below zero? Should be something like num/(10^ceil(log10(num))) . . . not to sure about how well it would work, but its an idea.
1632.4587642911599 / (10^ceil(log10(1632.4587642911599))) = 0.16324587642911599
How about:
const double significantFigures = 10;
Assert.AreEqual(Actual / Expected, 1.0, 1.0 / Math.Pow(10, significantFigures));
The difference between the two values should be less than either value divided by the precision.
Assert.Less(Math.Abs(firstValue - secondValue), firstValue / Math.Pow(10, precision));
open FsUnit
actual |> should (equalWithin errorMargin) expected

Accuracy of Math.Sin() and Math.Cos() in C#

I am terribly annoyed by the inaccuracy of the intrinsic trig functions in the CLR. It is well know that
Math.Sin(Math.PI)=0.00000000000000012246063538223773
instead of 0. Something similar happens with Math.Cos(Math.PI/2).
But when I am doing a long series of calculations that on special cases evaluate to
Math.Sin(Math.PI/2+x)-Math.Cos(x)
and the result is zero for x=0.2, but not zero for x=0.1 (try it). Another issue is when the argument is a large number, the inaccuracy gets proportionally large.
So I wonder if anyone has coded some better representation of the trig functions in C# for sharing with the world. Does the CLR call some standard C math library implementing CORDIC or something similar? link:wikipedia CORDIC
This has nothing to do with accuracy of trigonometric functions but more with the CLS type system. According to the documentation a double has 15-16 digits precision (which is exactly what you get) so you can't be more precise with this type. So if you want more precision you will need to create a new type that is capable of storing it.
Also notice that you should never be writing a code like this:
double d = CalcFromSomewhere();
if (d == 0)
{
DoSomething();
}
You should do instead:
double d = CalcFromSomewhere();
double epsilon = 1e-5; // define the precision you are working with
if (Math.Abs(d) < epsilon)
{
DoSomething();
}
I hear you. I am terribly annoyed by the inaccuracy of division. The other day I did:
Console.WriteLine(1.0 / 3.0);
and I got 0.333333333333333, instead of the correct answer which is 0.333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333...
Perhaps now you see what the problem is. Math.Pi is not equal to pi any more than 1.0 / 3.0 is equal to one third. Both of them differ from the true value by a few hundred quadrillionths, and therefore any calculations you perform with Math.Pi or 1.0/3.0 are also going to be off by a few hundred quadrillionths, including taking the sine.
If you don't like that approximate arithmetic is approximate then don't use approximate arithmetic. Use exact arithmetic. I used to use Waterloo Maple when I needed exact arithmetic; perhaps you should buy a copy of that.
This is a result of floating-point precision. You get a certain number of significant digits possible, and anything that can't be represented exactly is approximated. For example, pi is not a rational number, and so it's impossible to get an exact representation. Since you can't get an exact value of pi, you aren't going to get exact sines and cosines of numbers including pi (nor will you get exact values of sines and cosines most of the time).
The best intermediate explanation is "What Every Computer Scientist Should Know About Floating-Point Arithmetic". If you don't want to go into that, just remember that floating point numbers are usually approximations, and that floating-point calculations are like moving piles of sand on the ground: with everything you do with them, you lose a little sand and pick up a little dirt.
If you want exact representation, you'll need to find yourself a symbolic algebra system.
You need to use an arbitrary-precision decimal library. (.Net 4.0 has an arbitrary integer class, but not decimal).
A few popular ones are available:
BigNum
W3B.Sine
I reject the idea the the errors are due to round-off. What can be done is define sin(x) as follows, using a Taylor's expansion with 6 terms:
const double π=Math.PI;
const double π2=Math.PI/2;
const double π4=Math.PI/4;
public static double Sin(double x)
{
if (x==0) { return 0; }
if (x<0) { return -Sin(-x); }
if (x>π) { return -Sin(x-π); }
if (x>π4) { return Cos(π2-x); }
double x2=x*x;
return x*(x2/6*(x2/20*(x2/42*(x2/72*(x2/110*(x2/156-1)+1)-1)+1)-1)+1);
}
public static double Cos(double x)
{
if (x==0) { return 1; }
if (x<0) { return Cos(-x); }
if (x>π) { return -Cos(x-π); }
if (x>π4) { return Sin(π2-x); }
double x2=x*x;
return x2/2*(x2/12*(x2/30*(x2/56*(x2/90*(x2/132-1)+1)-1)+1)-1)+1;
}
Typical error is 1e-16 and worst case is 1e-11. It is worse than the CLR, but it is controllable by adding more terms. The good news is that for the special cases in the OP and for Sin(45°) the answer is exact.
Our current implementation of sine and cosine is
public static double Sin(double d) {
d = d % (2 * Math.PI); // Math.Sin calculates wrong results for values larger than 1e6
if (d == 0 || d == Math.PI || d == -Math.PI) {
return 0.0;
}
else {
return Math.Sin(d);
}
}
public static double Cos(double d) {
d = d % (2 * Math.PI); // Math.Cos calculates wrong results for values larger than 1e6
double multipleOfPi = d / Math.PI; // avoid calling the expensive modulo function twice
if (multipleOfPi == 0.5 || multipleOfPi == -0.5 || multipleOfPi == 1.5 || multipleOfPi == -1.5) {
return 0.0;
}
else {
return Math.Cos(d);
}
}

Test if a floating point number is an integer

This code works (C# 3)
double d;
if(d == (double)(int)d) ...;
Is there a better way to do this?
For extraneous reasons I want to avoid the double cast so; what nice ways exist other than this? (even if they aren't as good)
Note: Several people pointed out the (important) point that == is often problematic regrading floating point. In this cases I expect values in the range of 0 to a few hundred and they are supposed to be integers (non ints are errors) so if those points "shouldn't" be an issue for me.
d == Math.Floor(d)
does the same thing in other words.
NB: Hopefully you're aware that you have to be very careful when doing this kind of thing; floats/doubles will very easily accumulate miniscule errors that make exact comparisons (like this one) fail for no obvious reason.
This would work I think:
if (d % 1 == 0) {
//...
}
If your double is the result of another calculation, you probably want something like:
d == Math.Floor(d + 0.00001);
That way, if there's been a slight rounding error, it'll still match.
I cannot answer the C#-specific part of the question, but I must point out you are probably missing a generic problem with floating point numbers.
Generally, integerness is not well defined on floats. For the same reason that equality is not well defined on floats. Floating point calculations normally include both rounding and representation errors.
For example, 1.1 + 0.6 != 1.7.
Yup, that's just the way floating point numbers work.
Here, 1.1 + 0.6 - 1.7 == 2.2204460492503131e-16.
Strictly speaking, the closest thing to equality comparison you can do with floats is comparing them up to a chosen precision.
If this is not sufficient, you must work with a decimal number representation, with a floating point number representation with built-in error range, or with symbolic computations.
A simple test such as 'x == floor(x)' is mathematically assured to work correctly, for any fixed-precision FP number.
All legal fixed-precision FP encodings represent distinct real numbers, and so for every integer x, there is at most one fixed-precision FP encoding that matches it exactly.
Therefore, for every integer x that CAN be represented in such way, we have x == floor(x) necessarily, since floor(x) by definition returns the largest FP number y such that y <= x and y represents an integer; so floor(x) must return x.
If you are just going to convert it, Mike F / Khoth's answer is good, but doesn't quite answer your question. If you are going to actually test, and it's actually important, I recommend you implement something that includes a margin of error.
For instance, if you are considering money and you want to test for even dollar amounts, you might say (following Khoth's pattern):
if( Math.abs(d - Math.Floor(d + 0.001)) < 0.001)
In other words, take the absolute value of the difference of the value and it's integer representation and ensure that it's small.
You don't need the extra (double) in there. This works:
if (d == (int)d) {
//...
}
Use Math.Truncate()
This will let you choose what precision you're looking for, plus or minus half a tick, to account for floating point drift. The comparison is integral also which is nice.
static void Main(string[] args)
{
const int precision = 10000;
foreach (var d in new[] { 2, 2.9, 2.001, 1.999, 1.99999999, 2.00000001 })
{
if ((int) (d*precision + .5)%precision == 0)
{
Console.WriteLine("{0} is an int", d);
}
}
}
and the output is
2 is an int
1.99999999 is an int
2.00000001 is an int
Something like this
double d = 4.0;
int i = 4;
bool equal = d.CompareTo(i) == 0; // true
Could you use this
bool IsInt(double x)
{
try
{
int y = Int16.Parse(x.ToString());
return true;
}
catch
{
return false;
}
}
To handle the precision of the double...
Math.Abs(d - Math.Floor(d)) <= double.Epsilon
Consider the following case where a value less then double.Epsilon fails to compare as zero.
// number of possible rounds
const int rounds = 1;
// precision causes rounding up to double.Epsilon
double d = double.Epsilon*.75;
// due to the rounding this comparison fails
Console.WriteLine(d == Math.Floor(d));
// this comparison succeeds by accounting for the rounding
Console.WriteLine(Math.Abs(d - Math.Floor(d)) <= rounds*double.Epsilon);
// The difference is double.Epsilon, 4.940656458412465E-324
Console.WriteLine(Math.Abs(d - Math.Floor(d)).ToString("E15"));

Categories