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)
Related
I am generating a random number between a range but I want the number to not be 0. It can be 0.1, 0.2...etc but not 0. How do I do this?
public float selectedValue;
void Start()
{
selectedValue = Random.Range(-0.5f, 0.5f);
}
Keep finding random values until its value is not zero
float RandomNumExceptZero (float min, float max){
float randomNum = 0.0f;
do {
randomNum = Random.Range (min, max);
} while (randomNum == 0.0f );
return randomNum ;
}
Building on the suggestion of #Psi you could do this:
public float selectedValue;
void Start()
{
selectedValue = Random.Range(float.MinValue, 0.5f)*(Random.value > 0.5f?1:-1);
}
Random.Range() takes in 2 arguments in which the second argument is exclusive. You can use it for your advantage by excluding the value 0. The logic used is to find a random value between -0.5f and 0 (exclusive). Use another randomizer to get either a positive value or a negative value
public float selectedValue;
void Start()
{
selectedValue = Random.Range(-0.5f, 0);
int sign = Random.Range(0, 2);
// the value sign can be either 0 or 1
// if the sign is positive, invert the sign of selectedValue
if(sign) selectedValue = -selectedValue;
}
I just want to point out that there are 2,113,929,216 (*) float values in the interval [-0.5, 0.5) which gives a ≈ 0.000000047305 % chance that exactly 0.0f will be generated.
(*) found by brute force with C++ std::next_after but both implementation should follow IEEE 754 so I don't expect to be language differences in this regard, unless Unity somehow doesn't use subnormal numbers.
Well, just make if{} in Update() to pick another random number with same function if it is 0.0f. No way it will get 0.0f two times in a row
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.
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) {
Bear with me for a minute.
I have a method that should add or subtract a fixed value, depending on a given input.
I know that my max value is 1.0f, the min value is 0.0f. The fixed value is 0.1f.
Now if the input value is 1.0f the method should subtract until the value is 0f. If the input value is 0f the method should add 0.1f until the value is 1.0f.
So a working method for 0f to 1f would be:
void Foo(float input) {
float step = .1f;
for (float i=0f; i<=1f; i += step) {
input = i;
}
}
Obviously I could have an if-statement checking the input value, but is there another way to achieve this within one method? I feel like I'm just missing a very basic arithmetical operation here.
just a suggestion
I think step could be adjusted to be positive or negative based on the initial value, and use a do-while so it runs the first time, until it hits the final value.
Based on your code
void Foo(float input) {
float step = input == 0f ? .1f : -0.1f;
do
{
input = input + step
} while (input > 0f && input < 1.0f);
}
If you want to really avoid using an if statement at all for the step, you can actually derive it from the input directly. In turn you might get some extra numerical errors, but as you're using floats already this might not be of your concern.
void foo(float input)
{
float step = (.5f - input)/5.f;
do
{
input += step;
} while (input > 0.0f && input < 1.0f);
}
Running it on my machine gives me
foo(1.0f) --> -7.45058e-08
foo(0.0f) --> 1
I am wanting to lerp the variable that controls my animations speed so it transitions fluidly in the blend tree.
void Idle()
{
_agent.SetDestination(transform.position);
//Something like the following line
_speed = Mathf.Lerp(0.0f, _speed, -0.01f);
_animationController._anim.SetFloat("Speed", _speed);
}
I'v read that you can't lerp negatives, so how do I do this?
I think you're using Lerp bad.
As written in Unity Documentation (http://docs.unity3d.com/ScriptReference/Mathf.Lerp.html), you should pass 3 floats, the minimum as first argument, the maximum as second and the time as third.
This third should be beetwen 0 and 1.
Aside from that, you can always make the number negative after lerping it.
Some examples :
In case you want from -10 to 10, lerp from 0 to 20 and then substract 10.
float whatever = Mathf.Lerp(0f, 20f, t);
whatever -= 10f;
In case you want from 0 to -50, lerp from 0 to 50 and then make it negative.
float whatever = Mathf.Lerp(0f, 50f, t);
whatever = -whatever;
The t value in a lerp function between a and b typically needs to be in the 0-1 range. When t is 0, the function returns a and when t is 1, the function returns b. All the values of t in between will return a value between a and b as a linear function. This is a simplified one-dimensional lerp:
return a + (b - a) * t;
In this context, negative values of t don't make sense. For example, if your speed variable is 4.0f, the result of lerp(0, 4, -0.01f) would be:
0 + (4 - 0) * -0.01
which returns -0.04.
The simplest way to solve this issue is to simply flip a and b instead of trying to use a negative t.
_speed = Mathf.Lerp(_speed, 0.0f, 0.01f);
Another suggestion would be to use Mathf.SmoothStep and store the original speed instead of applying the function on the constantly changing _speed to get a really smooth transition.
Well, you cannot actually.
A psuedo-codish implementation of a Lerp function would look like this:
float Lerp(float begin, float end, float t)
{
t = Mathf.Clamp(t, 0, 1);
return begin * (1 - t) + end * t;
}
Therefore, any attempt to give a t value outside of [0, 1], ie. an extrapolate attempt, would be clamped to the valid range.