I wrote this simple rounding method in C#, which will round any floating point number (input) to the nearest multiple of any target number (target):
float RoundToFloat(float input, float target)
{
float quotient = input / target;
if (quotient - Mathf.Floor(quotient) < .5)
{
return Mathf.Floor(quotient) * target;
}
else
{
return Mathf.Ceil(quotient) * target;
}
}
However this seems to break when the input is a negative number. What do I have to do to make it work? I've tried calculating the absolute value of the quotient, and flipping whether I use ceil / floor if the input is negative, but keep getting weird results either way.
Any advice would be much appreciated!
Got it ... you need to reverse the applications of Floor and Ceiling for negative numbers, because the rounding has to be in the 'correct direction' with respect to 0.
Floor always goes more negative, while Ceiling does the opposite.
You can do this with a "simple" addition to your if: an "iff", also known as "Boolean equals".
if (quotient - Mathf.Floor(quotient) < .5) ==
(quotient >= 0) {
Related
I'm making a function that calculates the angle between 2 given vectors for my unity game using the dot product formula:
vector(a)*vector(b)=|vector(a)|*|vector(b)|*cos(the angle)
so I figured that the angle would equals
acos((vector(a)*vector(b))/(|vector(a)|*|vector(b)|))
Anyway here's my code:
float rotateAngle(Vector2 a,Vector2 b)
{
return Mathf.Acos((a.x * b.x + a.y * b.y) / ((Mathf.Sqrt(a.x * a.x + a.y * a.y)) * (Mathf.Sqrt(b.x * b.x + b.y * b.y)))) * (180 / Mathf.PI);
}
But when i played it the console showed NaN. I've tried and reviewed the code and the formula but returned empty-handed.
Can someone help me? Thank you in advanced!!
float.NaN is the result of undefined (for real numbers) mathematical operations such as 0 / 0 (note from the docs that x / 0 where x != 0 rather returns positive or negative infinity) or the square root of a negative value. As soon as one operant in an operation already is NaN then also the entire operation returns again NaN.
The second (square root of a negative value) can not happen here since you are using squared values so most probably your vectors have a magnitude of 0.
If you look at the Vector2 source code you will find their implementation of Vector2.Angle or Vector2.SignedAngle (which you should rather use btw as they are tested and way more efficient).
public static float Angle(Vector2 from, Vector2 to)
{
// sqrt(a) * sqrt(b) = sqrt(a * b) -- valid for real numbers
float denominator = (float)Math.Sqrt(from.sqrMagnitude * to.sqrMagnitude);
if (denominator < kEpsilonNormalSqrt)
return 0F;
float dot = Mathf.Clamp(Dot(from, to) / denominator, -1F, 1F);
return (float)Math.Acos(dot) * Mathf.Rad2Deg;
}
// Returns the signed angle in degrees between /from/ and /to/. Always returns the smallest possible angle
public static float SignedAngle(Vector2 from, Vector2 to)
{
float unsigned_angle = Angle(from, to);
float sign = Mathf.Sign(from.x * to.y - from.y * to.x);
return unsigned_angle * sign;
}
There you will find that the first thing they check is
float denominator = (float)Math.Sqrt(from.sqrMagnitude * to.sqrMagnitude);
if (denominator < kEpsilonNormalSqrt)
return 0F;
which basically makes exactly sure that both given vectors have a "big enough" magnitude, in particular one that is not 0 ;)
Long story short: Don't reinvent the wheel and rather use already built-in Vector2.Angle or Vector2.SignedAngle
NaN are typically the result of invalid mathematical operations on floating point numbers. A common source is division by zero, so my guess would be that the vector is 0,0.
I would also recommend using the built in functions for computing the normalization, Length/Magnitude, Dot etc. that will make the code much easier to read, and the compiler should be fairly good at optimizing that kind of code. If you need to do any additional optimization, only do so after you have done some measurements.
Hey i'm comparing 2 Vector.y's but it isnt working!
Here the code:
print(last.y + " == " + controller.transform.position.y);
if (last.y == controller.transform.position.y)
The print: 0,7999999 == 0,7999999
You are comparing floating point numbers. To get those exactly equal is hard. Unity only shows a limited amount of decimals in the editor. Try rounding the numbers.
https://docs.unity3d.com/ScriptReference/Mathf.Round.html
I.e.:
float randomNumber = 2.543686;
randomNumber = Mathf.Round(randomNumber * 100.0) / 100.0;
will return 2.54
Depending on how precise you want you could also do:
// If absolute difference between last y and controller pos y is less than 0.0001
if (Mathf.abs(last.y - controller.transformer.position.y) < 0.0001f) {
// do something
}
I am performing the following, but instead of zRem having the expected value of zero I get 2.384186E-07:
Vector3 t = this.transform.position - _startPosition;
float xRem = t.x % 1;
float zRem = t.z % 1;
In this instance:
this.transform.position = 2.5, 0, 3.5
_startPosition = 1.5, 0, 1.5
xRem is correct, but zRem have the value 2.384186E-07.
Any suggestions on how to fix this?
UPDATE #1:
When using the values above it should not enter this block, but because of zRem it does.
if(!Mathf.Approximately(xRem, 0f) || !Mathf.Approximately(zRem, 0f))
{
return;
}
Well, mod is not failing... Float point arithmetics always involve some level of precision/error.
I know, Mathf.Aproximately is meant to take ilthis into account, but Unity have its own Epsilon value for comparing floats and, guess what, it's value isn't documented.
https://docs.unity3d.com/ScriptReference/Mathf.Epsilon.html
(Maybe it is system dependent, according to the representation model of float values. Maybe it's IEEE conformant, I don't know)
Thing is: you should define what threshold use that conforms with your game logic, something like this:
if(xRem <= threshold)
Or
if(Mathf.abs(xRem) <= threshold)
I have interprated the formula in wikipedia in c# code, i do get a nice normal curve, but is it rational to get values that exceeds 1? isnt it suppose to be a distribution function?
this is the C# implementation :
double up = Math.Exp(-Math.Pow(x , 2) / ( 2 * s * s ));
double down = ( s * Math.Sqrt(2 * Math.PI) );
return up / down;
i double checked it several times and it seems fine to me so whats wrong? my implementation or understanding?
for example if we define x=0 and s=0.1 this impl would return 3.989...
A distribution function, a pdf, has the property that its values are >= 0 and the integral of the pdf over -inf to +inf must be 1. But the integrand, that is the pdf, can take any value >= 0, including values greater than 1.
In other words, there is no reason, a priori, to believe that a pdf value > 1 indicates a problem.
You can think about this for the normal curve by considering what reducing the variance means. Smaller variance values concentrate the probability mass in the centre. Given that the total mass is always one, as the mass concentrates in the centre, the peak value must increase. You can see that trend in the graph the you link to.
What you should do is compare the output of your code with known good implementations. For instance, Wolfram Alpha gives the same value as you quote: http://www.wolframalpha.com/input/?i=normal+distribution+pdf+mean%3D0+standard+deviation%3D0.1+x%3D0&x=6&y=7
Do a little more testing of this nature, captured in a unit test, and you will be able to rely on your code with confidence.
Wouldn't you want something more like this?
public static double NormalDistribution(double value)
{
return (1 / Math.Sqrt(2 * Math.PI)) * Math.Exp(-Math.Pow(value, 2) / 2);
}
Yes, it's totally OK; The distribution itself (PDF) can be anything from 0 to +infinity; the thing should be in the range [0..1] is the corresponding integral(s) (e.g. CDF).
You can convince yourself if look at the case of non-random value: if the value is not a random at all and can have only one constant value the distribution degenerates (standard error is zero, mean is the value) into Dirac Delta Function: a peak of infinite hight but of zero width; integral however (CDF) from -infinity to +infinity is 1.
// If you have special functions implemented (i.e. Erf)
// outcoume is in [0..inf) range
public static Double NormalPDF(Double value, Double mean, Double sigma) {
Double v = (value - mean) / sigma;
return Math.Exp(-v * v / 2.0) / (sigma * Math.Sqrt(Math.PI * 2));
}
// outcome is in [0..1] range
public static Double NormalCDF(Double value, Double mean, Double sigma, Boolean isTwoTail) {
if (isTwoTail)
value = 1.0 - (1.0 - value) / 2.0;
//TODO: You should have Erf implemented
return 0.5 + Erf((value - mean) / (Math.Sqrt(2) * sigma)) / 2.0;
}
This question already has answers here:
Difference between decimal, float and double in .NET?
(18 answers)
Closed 9 years ago.
Consider this program
float a = 0.7f;
if (a < 0.7)
{
Console.WriteLine("Less");
}
The output is Less. Why??
Because 0.7 does not have an exact representation as a float or a double: it is not an exact sum of negative powers of 2.
It happens that the closest representation of 0.7 as a is float approximately 0.69999998807907104492, while the closest double representation is 0.69999999999999995559. As you can see, double is slightly greater, which explains the behavior of your program.
Here is a small demo that you could run to see the values on your system:
printf("%20.20f %20.20f\n", 0.7, (float)0.7);
(live demo on ideone).
The takeaway lesson here is that you should not expect double and float representations of mathematically equal numbers to compare for equality correctly. Only a small subset of fractional numbers are representable in floating point system as exact numbers.
Since the overwhelming majority of fractions would be approximated, it is a good idea to do the comparisons with some level of tolerance. For example, instead of writing if (a == 0.7) you should write if (abs(a - 0.7) < 1E-8)
You're unknowingly comparing apples and potatoes in your code.
float a = 0.7f; // "0.7f" is a float
if(a< 0 .7) // "0.7" is a double
{
Console.WriteLine("Less"); //You'll see it because of different representations
}
Your check will work as you expect if you match the number types:
float a = 0.7f;
if(a < 0.7f)
{
Console.WriteLine("Less"); // You won't see this
}
This is why numbers should never be hard-coded. Best way to fix your code:
float check = 0.7f;
float a = 0.7f;
if(a < check)
{
Console.WriteLine("Less"); // You won't see this either
}