Difference Between How Dictionary ContainsKey Handles Transform.Forward and New Vector3

I’m in the process of setting up a grid system for a turn based game. The grid is stored as a Dictionary<Vector3,Node> where Node is a class that handles where it is available for units to occupy, among other things.

One unit that I’ve created spawns a projectile based on where the player is (aiming towards), and in subsequent turns the projectile moves in its transform.forward direction, which shouldn’t change after it’s been instantiated. If the projectile’s next target Node is available, it moves to that Node; otherwise, it destroys itself and does damage to the player. Here’s the code (held in a “Linear Movement” component on the projectile) that is responsible for checking if the projectile can move to the next Node:

Dictionary<Vector3,Node> grid = GridManager.instance.grid; //Caching a reference to the grid from its singleton

//Other stuff

public bool NextNodeIsWalkable { get
    if (!grid.ContainsKey(moveTarget)) return false;
    return grid[moveTarget].isWalkable;
} }

This is all well and good; it’s pretty simple code. The problem comes in when we set moveTarget:

private Vector3 moveTarget { get
            return Vector3.right * transform.position.x + Vector3.forward * transform.position.z + moveDirection;
     } }

moveDirection itself is set as moveDirection = transform.forward in OnEnable.

In some cases - which seem to me to be completely random, though they are always when the arrow is moving horizontally and never vertically - the grid.ContainsKey(moveTarget) check returns false even when there is an available Node, causing the projectile to explode.

There are a few puzzling behaviors here.

  1. As alluded to above, if the projectile is moving vertically, it always behaves as expected.
  2. In some cases, if I switch the positions of the player and the enemy which generates the projectiles (so that the projectile is moving right instead of left, or vice versa), the grid.ContainsKey(moveTarget) check behaves as expected, finding a Node in the dictionary, and telling the projectile to move.
  3. If I change the variable moveDirection to be a hardcoded Vector3 in the given direction, it always behaves as expected, finding the Node in the dictionary which it wasn’t finding before, even in the cases where the transform.forward Vector3 is identical to the hardcoded Vector3 I’ve put in. I think this is really the crux of my question - why would these behave differently? Where am I going wrong?
    I can post screenshots of my VisualStudio debugging if that would be helpful.

Edit - I’ve also just realized I mistakenly didn’t put this in the help room automatically, my apologies. If there’s a way to move it over there I would much appreciate some guidance as well.

Editing to say that after many frustrating hours (it is well past midnight here) I believe I have discovered the answer. I want to share since I didn’t see much else on this via google:

I think there were inaccuracies in the float components of the Vector3 returned by transform.forward, causing it to display in the debugger (and the debug log) as the correct Vector but with infinitessimal errors under the hood that weren’t showing up, and hence when it got passed in to the dictionary the dictionary didn’t recognize it as a key… This is a result of the inherent inaccuracies of floats.

I was able to solve this issue by calling Vector3Int.RoundToInt(moveDirection) in the moveTarget getter property.