99999 in coordinate system

Hi. I am creating a snake game in Unity. I’ve faced the problem that’s when my snake goes (+0.64 every period of time) it sometimes places itself on 4.159999 position instead of 4.16 that it should move to. For example, the snake stays at 3.52 position and in the next second it should be at 4.8 (cause 3.52 + 0.64 is equal 4.16), but instead of it somehow moves to 4.159999 position and I don’t understand why. That code line is
p1 = new Vector3(p1.x, p1.y + 0.64f);
I see nothing that could entail such irrational number.
I tryed to correct this by rounding the number up to the nearest hundredth. But this cause the same problem, but in other positions.
What should I do?
Thanks.

Worry less about floating point precision.

Why do you need accuracy to that level?

I’ll explain. Thing is I should control the positions to set the end of the border so that I could teleport the snake to the other side of the borders. That end is 5.12, but having irrational numbers in the snake position I cannot set the precise number that should be the end of the border.

in current computers numbers are held in base 2, base 2 cannot support decimals exactly, there is always going to be some slight variation. This is not something you can “fix”.

Don’t compare floating point numbers directly, if you want to know if they’re the “same” check that their different is suitably tiny. You can set your boundaries just fine, check if the position is outside of them just fine. The very slight floating point inaccuracy might involve your snake being very slightly not where it “should” be for a tiny fraction of a second. As @LaneFox says, it’s not something you need to overly worry about given your use case.

fyi I don’t think “irrational number” means what you are using it for :stuck_out_tongue:

Alright

Well, alright. I got it. But if I make a condition in which postion should be => 4.8 snake will anyway go through the border cause its postion is 4.79999 :hushed:. But okay, I think It could be fixed by reducing the border coordinate a bit.:slight_smile:

Thanks

just for completeness… by this i mean don’t do

floatA == floatB
// 4.599999 != 4.6

you’ll run into this alot when comparing positions (Vector3 being made up of 3 floats after all), the “usual” work around is “snapping” the value to exactly what you want once you’ve determined it is “close enough”

//psuedocode
if 
      Vector3.Distance(transform.position, point1) < 0.0001 
then
     transform.position = point1

Ah. I see. That’s better solution. I’ll try it

Float error can be annoying. Not only do a lot of base 10 fractional values become repeating irrationals in base 2 (like 0.1 is 0.000110011001100…), but also there is precision issues. 32-bit floats can only store 24 bits of precision, which is about 6 to 7 decimal digits of precision for whole numbers. And sometimes even fewer for fractional because some fractions may require a lot of digits to be represented in base 2.

Usually you ignore float error and just never use them for direct comparison.

But sometimes you can’t avoid it.

Because of that I actually have goto functions in my MathUtil and VectorUtil classes to help with this:

(in the section ‘Simple Fuzzy Arithmetic’)

  #region "Simple fuzzy arithmetic"

  /// <summary>
  /// Test if float is kind of equal to some other value by some epsilon.
  ///
  /// Due to float error, two values may be considered similar... but the computer considers them different.
  /// By using some epsilon (degree of error) once can test if the two values are similar.
  /// </summary>
  /// <param name="a"></param>
  /// <param name="b"></param>
  /// <param name="epsilon"></param>
  /// <returns></returns>
  /// <remarks></remarks>
  public static bool FuzzyEqual(float a, float b, float epsilon)
  {
  return Math.Abs(a - b) < epsilon;
  }

  public static bool FuzzyEqual(float a, float b)
  {
  return FuzzyEqual(a, b, EPSILON);
  }

  /// <summary>
  /// Test if float is less than some other value by some degree of error in epsilon.
  ///
  /// Due to float error, two values may be considered similar... but the computer considers them different.
  /// By using some epsilon (degree of error) once can test if the two values are similar.
  /// </summary>
  /// <param name="a"></param>
  /// <param name="b"></param>
  /// <param name="epsilon"></param>
  /// <param name="exclusive"></param>
  /// <returns></returns>
  /// <remarks></remarks>
  public static bool FuzzyLessThan(float a, float b, float epsilon, bool exclusive)
  {
  //exclusive means we prefer to easily exclude a true result
  if (exclusive)
  return a < b - epsilon;
  else
  return a < b + epsilon;
  }

  public static bool FuzzyLessThan(float a, float b, bool exclusive)
  {
  return FuzzyLessThan(a, b, EPSILON, exclusive);
  }

  /// <summary>
  /// Test if float is less than some other value by some degree of error in epsilon.
  ///
  /// Due to float error, two values may be considered similar... but the computer considers them different.
  /// By using some epsilon (degree of error) once can test if the two values are similar.
  /// </summary>
  /// <param name="a"></param>
  /// <param name="b"></param>
  /// <param name="epsilon"></param>
  /// <param name="exclusive"></param>
  /// <returns></returns>
  /// <remarks></remarks>
  public static bool FuzzyGreaterThan(float a, float b, float epsilon, bool exclusive)
  {
  //exclusive means we prefer to easily exclude a true result
  if (exclusive)
  return a > b + epsilon;
  else
  return a > b - epsilon;
  }

  public static bool FuzzyGreaterThan(float a, float b, bool exclusive)
  {
  return FuzzyGreaterThan(a, b, EPSILON, exclusive);
  }

  /// <summary>
  /// Test if a value is near some target value, if with in some range of 'epsilon', the target is returned.
  ///
  /// eg:
  /// Slam(1.52,2,0.1) == 1.52
  /// Slam(1.62,2,0.1) == 1.62
  /// Slam(1.72,2,0.1) == 1.72
  /// Slam(1.82,2,0.1) == 1.82
  /// Slam(1.92,2,0.1) == 2
  /// </summary>
  /// <param name="value"></param>
  /// <param name="target"></param>
  /// <param name="epsilon"></param>
  /// <returns></returns>
  /// <remarks></remarks>
  public static float Slam(float value, float target, float epsilon)
  {
  if (Math.Abs(value - target) < epsilon)
  {
  return target;
  }
  else
  {
  return value;
  }
  }

  public static float Slam(float value, float target)
  {
  return Slam(value, target, EPSILON);
  }
  #endregion

(in the section ‘Compare Vector’)

  #region Compare Vector

  /// <summary>
  /// Compares if a and b are nearly on the same axis and will probably return a zero vector from a cross product
  /// </summary>
  /// <param name="a"></param>
  /// <param name="b"></param>
  /// <param name="epsilon"></param>
  /// <returns></returns>
  public static bool NearSameAxis(Vector3 a, Vector3 b, float epsilon = MathUtil.EPSILON)
  {
  return MathUtil.FuzzyEqual(Mathf.Abs(Vector3.Dot(a.normalized, b.normalized)), 1.0f, epsilon);
  }

  public static bool NearZeroVector(this Vector3 v)
  {
  return MathUtil.FuzzyEqual(v.sqrMagnitude, 0f, MathUtil.EPSILON_SQR);
  }

  public static bool NearZeroVector(this Vector2 v)
  {
  return MathUtil.FuzzyEqual(v.sqrMagnitude, 0f, MathUtil.EPSILON_SQR);
  }

  public static bool FuzzyEquals(this Vector2 a, Vector2 b)
  {
  return MathUtil.FuzzyEqual(Vector3.SqrMagnitude(a - b), MathUtil.EPSILON_SQR);
  }

  public static bool FuzzyEquals(this Vector2 a, Vector2 b, float epsilon)
  {
  return MathUtil.FuzzyEqual(Vector3.SqrMagnitude(a - b), epsilon);
  }

  public static bool FuzzyEquals(this Vector3 a, Vector3 b)
  {
  return MathUtil.FuzzyEqual(Vector3.SqrMagnitude(a - b), MathUtil.EPSILON_SQR);
  }

  public static bool FuzzyEquals(this Vector3 a, Vector3 b, float epsilon)
  {
  return MathUtil.FuzzyEqual(Vector3.SqrMagnitude(a - b), epsilon);
  }

  #endregion

Thanks for adittional information

Another question, guys, if you please.
Why should I type -5.12-0.32f (=-5.44) for the snake to be in -4.8 position?

Does that GameObject sit inside another GameObject that is positioned slightly off the origin?

Note, the ‘position’ shown in the editor is the ‘localPosition’. Where as the ‘position’ property you read/write to in code is the world position. Use ‘localPosition’ in code to access that instead.

You can (and should) bypass this entire issue by just using integers rather than floating point. Do all the game logic with integers, and scale those to whatever you need for display. i.e., instead of using .64 units for your grid spacing just use 1. You can scale that by .64 when applying the position to transform.position, but internally you’d always be using integers.

–Eric

No. The object sits nowhere

Ah. I’m sorry. My mistake. I’ve found the code that was causing that offset