Getting `nan` instead of 0 in my Dot Product

So I wanted to get the Dot Product of two vectors, and when they are facing eachother, it should get me a 0, but in this case it gives me -nan(ind). The orientation of my parts is what’s causing the issue apparently, because when I change the orientation back to default it gives me correct results. Refer to the Code to see the orientations.

Code
local Part = script.Parent --Part's orientation is Vector3(0,60,0)
local LookAt = script.Parent.Parent.lookhere --LookAt's orientation is Vector3(0,-120,0)

local Facing = Part.CFrame.LookVector
local Vector = (LookAt.Position - Part.Position).unit	
local Angle = math.acos(Facing:Dot(Vector))
--The Angle gets me that nan instead of 0 if the two vectors are facing eachother

How can I detect that I got -nan(ind) the same way I am able to see if something is nil or not?

Edit: Thanks to @blokav I was able to understand what @daftcube meant by math.clamp’ing the output. It should be done something like this.

local Angle = math.acos(math.clamp(Facing:Dot(Vector), -1, 1))

Just do

local x = math.acos(Facing:Dot(Vector))
local Angle = x and x or 0

Still same issue, getting nan instead of 0.

This fix proposed by @Varjoy does not fix the problem because nan is distinct from nil. nan stands for “not a number,” and you get it when trying to calculate undefined values. For example, 1/0=NaN. Looking at your code, you use arccosine, which is only defined on the range [-1,1]. Specifically, what is probably happening here is that for some reason, floating point precision errors are causing the dot product of the two vectors to be slightly above 1, which causes math.acos to return nan as acos is not well-defined beyond 1.

There are some funny properties of NaN, like NaN+1=NaN but NaN ~= NaN that can cause cascading issues where mathematical operations in your program slowly infect all of your numerical variables with NaN.

If you’re trying to get the angle between two vectors, you’re probably going to want to use this function:

function AngleBetweenVectors(a, b)
    return math.acos( ( a:Dot(b) ) / (a.Magnitude * b.Magnitude) )
end

This implements the standard Angle Between Vectors formula that is derived from the relationship a x b = |a||b|cos(theta).

If this doesn’t work, you can always try to clamp the input of math.acos inside its range using math.clamp.

EDIT 6/18/2021: Meant NaN, but wrote nand. Oops, fixed it for posterity.

6 Likes

Actually values out of those range results in a complex number so it’s defined for numbers out of these range.

Actually 1/0 == math.huge (Infinity).
What’s the d in nand? Never heard of nand

1 Like

I tried both ways you suggested, the first one doesn’t work, and math.clamp wouldn’t work cause non of the values are outside [-1,1]

Alright, just try this:
The fix proposed by @daftcube works, but it overcomplicates it, and make it looks harder than it is!

local Angle = math.acos(Facing:Dot(Vector))
if (Angle == Angle) then
print("Hey!")
    else
print("It's NAN!")
end

Or:

local X = math.acos(Facing:Dot(Vector))
local Angle = X == X and X or 0

Please can you check what the value of
(LookAt.Position - Part.Position)
is, as if by coincidence this creates the vector 0,0,0 .Unit will return nan,nan,nan

1 Like

Now that sounds like theretical mathmatics, how can you perform arithmatic on a expression?

What do you mean by perform arithmetic on an expressoin?
This is IEEE floating point, not mathematics.

oops! forgot this was coding, where dx is 0.0000000000001 lol. No harm thou :wink:

Well sure, we can talk about complex numbers, but if we’re talking about the standard implementation of arcsine / arccosine as exists in the Roblox API, we’re only dealing with approximations of real numbers (see IEEE floating point standard). I guess to be specific, it’s not well-defined on the real numbers beyond [-1,1].

2 Likes

When you use inverse trig functions it’s usually a good idea to clamp the input between -1 and 1.

local Angle = math.acos(math.clamp(Facing:Dot(Vector), -1, 1))
4 Likes

Make sure LookAt and Part aren’t in the same position otherwise your code looks fine. If the two parts have the same position, you can find the angle by doing:

local Angle = math.acos(Facing:Dot(LookAt.CFrame.LookVector))

It’s returning this 0.866025209, 0, 0.500000417

i need to find 3 angles based off of side length