# Unity.Mathematics available on github

Discussion in 'Data Oriented Technology Stack' started by xoofx, Apr 10, 2018.

1. ### Vacummus

Joined:
Dec 18, 2013
Posts:
77
Is there an equivalent to Mathf.SmoothDamp in the mathematics library that can be used in jobs?

2. ### Antypodish

Joined:
Apr 29, 2014
Posts:
5,170
I haven't seen so I am a bit skeptical. But maybe is somewhere else?

3. ### Vacummus

Joined:
Dec 18, 2013
Posts:
77
The closest I have found is math.smoothstep. However, this one behaves differently from Mathf.SmoothStep.

https://docs.unity3d.com/ScriptReference/Mathf.SmoothStep.html

^ To replicate the same behavior given in that example with math.smoothstep I had to do the following:

Code (CSharp):
1. using UnityEngine;
2. using Unity.Mathematics;
3.
4. public class Example : MonoBehaviour
5. {
6.     // Minimum and maximum values for the transition.
7.     float minimum = 10.0f;
8.     float maximum = 20.0f;
9.
10.     // Time taken for the transition.
11.     float duration = 5.0f;
12.
13.     float startTime;
14.
15.     void Start()
16.     {
17.         // Make a note of the time the script started.
18.         startTime = Time.time;
19.     }
20.
21.     void Update()
22.     {
23.         // Calculate the fraction of the total duration that has passed.
24.
25.         var elapsedTime = (Time.time - startTime);
26.         // smoothstep returns a value between 0 and 1
27.         var elapsedTimeRange = math.smoothstep(0, duration, elapsedTime);
28.         // use elapsedTimeRange to get value between start and end
29.         // to get our final result
30.         var current = math.lerp(start, end, elapsedTimeRange);
31.     }
32. }

Last edited: Jan 5, 2019
Antypodish likes this.
4. ### Antypodish

Joined:
Apr 29, 2014
Posts:
5,170
Seams like a neat solution.
Just wonder, what if time wraps?
I mean game would have to be running for quite long time.
But that would introduce some unexpected results.

5. ### Vacummus

Joined:
Dec 18, 2013
Posts:
77
We could use Time.deltaTime instead (the logic will be different from the code above). And that would be better since we won't have to keep track of "startTime", we only need to keep track of the "current" value which you'll most likely be keeping track anyways. It would also make it easier to use with ECS. I'll try out the Time.deltaTime approach with ECS (jobified) and post my results here.

Antypodish likes this.
6. ### Vacummus

Joined:
Dec 18, 2013
Posts:
77
So I haven't been able to derive the elapsed time from the "current" value. I believe it's still possible, just takes a lot of math since you have the reverse engineer the math.smoothstep to get the value, so not sure how much value there is in that. But from the example above, you can still use Time.deltaTime instead of Time.time, and that would look something like this:

Code (CSharp):
1. using UnityEngine;
2. using Unity.Mathematics;
3.
4. public class Example : MonoBehaviour
5. {
6.     // Minimum and maximum values for the transition.
7.     float minimum = 10.0f;
8.     float maximum = 20.0f;
9.     // Time taken for the transition.
10.     float duration = 5.0f;
11.     float elapsedTime;
12.
13.     void Update()
14.     {
15.         // Calculate the fraction of the total duration that has passed.
16.         elapsedTime += Time.deltaTime;
17.         // smoothstep returns a value between 0 and 1
18.         var elapsedTimeRange = math.smoothstep(0, duration, elapsedTime);
19.         // use elapsedTimeRange to get value between start and end
20.         // to get our final result
21.         var current = math.lerp(start, end, elapsedTimeRange);
22.     }
23. }
For my use case though (which is to smoothly damp the movement speed of the player) I decided not to go with math.smoothStep. Instead I just went with using math.lerp in a way that works similarly to Mathf.SmoothDamp. Like for example:

Code (CSharp):
1. currentSpeed = math.lerp(currentSpeed, desiredSpeed, 0.1);
It's a little more performant and allows me to more smoothly damp the speed when the desiredSpeed changes then I would be able to do with smoothstep.

7. ### illinar

Joined:
Apr 6, 2011
Posts:
557
Some curves would be very useful to have in this library. At least 2 point curves.

8. ### Baste

Joined:
Jan 24, 2013
Posts:
4,107
The universe is apparently about 10^10 years old. Time.time's max value in seconds is ~10^31 years.

PhilSA, Nyarlathothep and Antypodish like this.
9. ### Antypodish

Joined:
Apr 29, 2014
Posts:
5,170
Do you try to say, we got plenty of time to run, to develop our game
Time.time is float. So technically, if we don't want loose precision, that is a near 70 years.
Still, looks like no need to worry, at least until next century/millennia bomb.

Qbit86 likes this.
10. ### alexzzzz

Joined:
Nov 20, 2010
Posts:
1,404
530000f seconds + .016f seconds = 530000f seconds
So, after the first six days the time just stops. And we'll get zero intervals, divisions by zero, infinities and NaNs.

11. ### Antypodish

Joined:
Apr 29, 2014
Posts:
5,170
I think I am talking rubbish anyway

There is discussion
https://gamedev.stackexchange.com/q...ppens-when-time-time-gets-very-large-in-unity
But I am not convinced 100% for the answer.
However, it referencing.
https://randomascii.wordpress.com/2012/02/13/dont-store-that-in-a-float/

And this table.

Float Value Time Value Float Precision Time Precision
1 1 second 1.19E-07 119 nanoseconds
10 10 seconds 9.54E-07 .954 microsecond
100 ~1.5 minutes 7.63E-06 7.63 microseconds
1,000 ~16 minutes 6.10E-05 61.0 microseconds
10,000 ~3 hours 0.000977 .976 milliseconds
100,000 ~1 day 0.00781 7.81 milliseconds
1,000,000 ~11 days 0.0625 62.5 milliseconds
10,000,000 ~4 months 1 1 second
100,000,000 ~3 years 8 8 seconds
1,000,000,000 ~32 years 64 64 seconds

Considering float got 9 digits precision, that is near 10 billions, seconds, without milliseconds.
Hence over 300 years. But surely there is somewhere bottom line, far before reaching 9 digits.

Someone here to confirm actual Time.time max?

12. ### alexzzzz

Joined:
Nov 20, 2010
Posts:
1,404
According to the table, 10,000,001 can't be more precise than that. It's 8 digits. It's 10 million seconds, 115 days.

Antypodish likes this.
13. ### Antypodish

Joined:
Apr 29, 2014
Posts:
5,170
Oh boi, yeah you completely right.

14. ### daschatten

Joined:
Jul 16, 2015
Posts:
143
I often need something like

Code (CSharp):
1. var distDiff = position.Value - positions[j].Value;
2. var distSquared = math.dot(distDiff, distDiff);
It would be nice to have math.dot with a single argument signature so i can use:

Code (CSharp):
1. var distSquared = math.dot(position.Value - positions[j].Value);

15. ### M_R

Joined:
Apr 15, 2015
Posts:
450
``math.lengthsq``
exists

daschatten and Antypodish like this.

Joined:
Jul 16, 2015
Posts:
143
Thanks

17. ### xVergilx

Joined:
Dec 22, 2014
Posts:
1,875
Does anyone know how to compare two floats?
Is there an alternative to the Mathf.Epsilon?

Would that be FLT_MIN_NORMAL?

Will this return correct values when comparing?
Code (CSharp):
1. public static bool Compare(float a, float b) {
2.     return math.abs(a - b) <= math.FLT_MIN_NORMAL * math.max(1.0f, math.max(math.abs(a), math.abs(b)));
3. }

18. ### xVergilx

Joined:
Dec 22, 2014
Posts:
1,875
Also, there's a misleeding naming on degrees / radians plus it's summary is messed up:
Code (CSharp):
1. /// <summary>Returns the result of converting a float value from radians to degrees.</summary>
2.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
3.         public static float radians(float x) { return x * 0.0174532925f; }
4.
5.         /// <summary>Returns the result of a componentwise conversion of a float2 vector from radians to degrees.</summary>
6.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
7.         public static float2 radians(float2 x) { return x * 0.0174532925f; }
8.
9.         /// <summary>Returns the result of a componentwise conversion of a float3 vector from radians to degrees.</summary>
10.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
11.         public static float3 radians(float3 x) { return x * 0.0174532925f; }
12.
13.         /// <summary>Returns the result of a componentwise conversion of a float4 vector from radians to degrees.</summary>
14.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
15.         public static float4 radians(float4 x) { return x * 0.0174532925f; }
16.
17.
18.         /// <summary>Returns the result of converting a float value from radians to degrees.</summary>
19.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
20.         public static double radians(double x) { return x * 0.017453292519943296; }
21.
22.         /// <summary>Returns the result of a componentwise conversion of a float2 vector from radians to degrees.</summary>
23.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
24.         public static double2 radians(double2 x) { return x * 0.017453292519943296; }
25.
26.         /// <summary>Returns the result of a componentwise conversion of a float3 vector from radians to degrees.</summary>
27.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
28.         public static double3 radians(double3 x) { return x * 0.017453292519943296; }
29.
30.         /// <summary>Returns the result of a componentwise conversion of a float4 vector from radians to degrees.</summary>
31.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
32.         public static double4 radians(double4 x) { return x * 0.017453292519943296; }
33.
34.
35.         /// <summary>Returns the result of converting a double value from radians to degrees.</summary>
36.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
37.         public static float degrees(float x) { return x * 57.295779513f; }
38.
39.         /// <summary>Returns the result of a componentwise conversion of a double2 vector from radians to degrees.</summary>
40.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
41.         public static float2 degrees(float2 x) { return x * 57.295779513f; }
42.
43.         /// <summary>Returns the result of a componentwise conversion of a double3 vector from radians to degrees.</summary>
44.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
45.         public static float3 degrees(float3 x) { return x * 57.295779513f; }
46.
47.         /// <summary>Returns the result of a componentwise conversion of a double4 vector from radians to degrees.</summary>
48.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
49.         public static float4 degrees(float4 x) { return x * 57.295779513f; }
50.
51.
52.         /// <summary>Returns the result of converting a double value from radians to degrees.</summary>
53.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
54.         public static double degrees(double x) { return x * 57.29577951308232; }
55.
56.         /// <summary>Returns the result of a componentwise conversion of a double2 vector from radians to degrees.</summary>
57.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
58.         public static double2 degrees(double2 x) { return x * 57.29577951308232; }
59.
60.         /// <summary>Returns the result of a componentwise conversion of a double3 vector from radians to degrees.</summary>
61.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
62.         public static double3 degrees(double3 x) { return x * 57.29577951308232; }
63.
64.         /// <summary>Returns the result of a componentwise conversion of a double4 vector from radians to degrees.</summary>
65.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
66.         public static double4 degrees(double4 x) { return x * 57.29577951308232; }
Note how it is identical is both cases "radians to degrees" where its logic not identical.

Last edited: Feb 9, 2019
dadude123, Qbit86 and RaL like this.
19. ### alexzzzz

Joined:
Nov 20, 2010
Posts:
1,404
It should be something like
Code (csharp):
1. abs(a-b) <= FLT_EPSILON * max(abs(a), abs(b))
but there's no FLT_EPSILON declared. FLT_MIN_NORMAL is not the thing we want here, neither is Mathf.Epsilon. The value should be 1.19e-07 or something like that, definitely not 1e-38 or 1e-45.

FLT_EPSILON must be the smallest positive number so that (1.0f + e) != 1.0f
FLT_EPSILON must be the difference between 1 and the closest value greater than 1. Sounds similar but this way the value is twice as large.

Last edited: Feb 9, 2019
xVergilx likes this.
20. ### xVergilx

Joined:
Dec 22, 2014
Posts:
1,875
Right, totally forgot I could just define the Epsilon itself (just by snatching it from the Mathf).
Would be nice to have it defined in the lib tho.

21. ### xVergilx

Joined:
Dec 22, 2014
Posts:
1,875
Actually, I'm not so sure anymore, it's defined like this (In Mathf lib):
Code (CSharp):
1. public static readonly float Epsilon = !MathfInternal.IsFlushToZeroEnabled ? MathfInternal.FloatMinDenormal : MathfInternal.FloatMinNormal;
Code (CSharp):
1. [StructLayout(LayoutKind.Sequential, Size = 1)]
2.   public struct MathfInternal
3.   {
4.     public static volatile float FloatMinNormal = 1.175494E-38f;
5.     public static volatile float FloatMinDenormal = float.Epsilon;
6.     public static bool IsFlushToZeroEnabled = (double) MathfInternal.FloatMinDenormal == 0.0;
7.   }
And the epsilon is:
Code (CSharp):
1.  public const float Epsilon = 1.401298E-45f;
So it's actually ^-45 or ^-38

Question is, why it it's not the same value each time.

I have used this code so many times, and never wondered how it's implemented. This is really impressively disturbing.

22. ### xVergilx

Joined:
Dec 22, 2014
Posts:
1,875
Btw, In C++ Epsilon is defined like 1E-5 or smaller. Maybe I should define it in the same way for my lib.

23. ### alexzzzz

Joined:
Nov 20, 2010
Posts:
1,404
Since the error accumulates with the number of operations you do (or CPU does) to compute the final value, using FLT_EPSILON is not enough, multiples of FLT_EPSILON should be used. It's just that using anything less than 1.1920929e-7 for floats doesn't make sense at all.

Code (CSharp):
1. const float FLT_EPSILON = 1.1920929e-7f;
2. if (abs(x-10) <= abs(x)*FLT_EPSILON) {}
This roughly means, while comparing X to 10, ignore the last bit of X as it may be incorrect,
abs(x)*2*FLT_EPSILON ― ignore the last two bits of X,
abs(x)*4*FLT_EPSILON ― last three bits...

xVergilx likes this.
24. ### alexzzzz

Joined:
Nov 20, 2010
Posts:
1,404
Last edited: Jan 29, 2019
xVergilx likes this.
25. ### xVergilx

Joined:
Dec 22, 2014
Posts:
1,875
Now that we've picked up about anything, I've almost forgot this exists in Mathf:
Code (CSharp):
1. public static bool Approximately(float a, float b)
2.     {
3.       return (double) Mathf.Abs(b - a) < (double) Mathf.Max(1E-06f * Mathf.Max(Mathf.Abs(a), Mathf.Abs(b)), Mathf.Epsilon * 8f);
4.     }

26. ### MostHated

Joined:
Nov 29, 2015
Posts:
722
I had a fairly large number of conditional things throughout my project but it seems that most of them no longer work. Some of them I definitely understand, having had to switch from reference type to value on several of them that were checking for null, but someone them I am just not able to make sense of.

This one, none of the "or" operators would work anymore, and then when I tried to trim it down until I could get it working so I could try and figure out another way to check things, well, it never did.
Code (CSharp):
1. if (pathPoints != null && currentWaypoint != null &&
2.                 Vector3.Distance(transform.position, currentWaypoint.transform.position) <= distanceFromWaypoint)
3.             {
4.                 if (currentWaypoint == goalWaypoint || pathPoints == null || pathPoints.Waypoints.Count == 0)
I made it down to this, but it seems no matter what I do, with parenthesis, without, moving them around, I tried to wrap some of it, etc, the && (and) always comes back with some sort of issue. This particular one currently is always coming back with a bool/bool3 issue.

Code (CSharp):
1. if ((vehicleData.currentWaypoint > 0) && (math.distance(position.Value, vehicleData.currentWaypoint) <= vehicleData.distanceFromWaypoint))
Is there any sort of guide, or perhaps any tricks anyone happens to know on getting them to work a bit easier, or am I just stuck with the logic it provides?I mean, its not a huge deal, I can just work around it, but it would be nice.

Last edited: Feb 9, 2019
27. ### riskparitygawd

Joined:
Sep 22, 2018
Posts:
11
The check on a float3 needs to be !vehicleData.currentWaypoint.Equals(float3.zero) or similar

28. ### MostHated

Joined:
Nov 29, 2015
Posts:
722
Well, I'll be. It sure was. Thanks for that, lol.

29. ### tertle

Joined:
Jan 25, 2011
Posts:
1,554
Also, as a shortcut for "bool/bool3 issue" there is a math.all(bool3) method as well as a math.any(bool3) if you require

GilCat and MostHated like this.
30. ### snacktime

Joined:
Apr 15, 2013
Posts:
2,312
So random.NextInt(min,max) is always returning 0 or 1 if min is 0 regardless of what max is. Haven't actually tested it with min set to something other then 0.

This is what I use to create the random instance, new instance for every job run.

Code (csharp):
1.
2. var random = new Unity.Mathematics.Random((uint)UnityEngine.Random.Range(1, 100000));
3.

31. ### snacktime

Joined:
Apr 15, 2013
Posts:
2,312
Nevermind that was an error in my testing, once I created a proper unit test for it it worked fine.

32. ### Sibz9000

Joined:
Feb 24, 2018
Posts:
80
Unity.Mathematics.Random isn't very random with incremental seed:
Code (CSharp):
1. for (int i = 0; i < 2000; i++)
2. {
3.   var rng = new Unity.Mathematics.Random((uint)i+1);
4.   Debug.LogFormat("Rnd1: {0}", rng.NextInt(1, 10));
5. }
Result is 1 until i=1856 then its 2....

Haven't tested much more than that but I noticed in my code I was getting similar chains of numbers with seeds around the same number. The same code with System.Random yields, as expected, completely random numbers each increment.

My work around: Call NextInt twice before the considering any number random. After 2 calls it seems random.

Last edited: Feb 26, 2019
33. ### M_R

Joined:
Apr 15, 2015
Posts:
450
you should not use incremental seeds with random. any random. you should instead keep the same instance and call Next repeatedly on that.
if you want to generate the random number explicitly based on a counter, consider using a random hash instead

34. ### Sibz9000

Joined:
Feb 24, 2018
Posts:
80
I know this. I just reported it as it's just certainly not random if given a seed between 1-1856, the first int is always 1. I just noticed this in some test code so thought I better mention it.

35. ### LazyGameDevZA

Joined:
Nov 10, 2016
Posts:
76
Thing is you're comparing the randomness on a scale of integers ranging from 1 - 9. Inherintly there's not a lot of randomness that can come from that. I suspect checking raw uint produced by NextState() would yield a more random distribution than the test above.

36. ### bitinn

Joined:
Aug 20, 2016
Posts:
538
Hi all, wondering about 2 questions:

- Is there any benefit to use use float3 from this package over Vector3 in terms of memory footprint? (Looking at both's source code, I feel they store the same amount of the data: 3 floats)

- Does it improve memory access on CPU? (Imagine a sizable grid map, but each item on the cell is allowed a custom rotation, does it make sense to use float3 over Vector3?)

37. ### bitinn

Joined:
Aug 20, 2016
Posts:
538
OK to answer 2 of my own questions:

- This package has half which is implemented with ushort, so that's definitely a possible save on memory.

- I think the memory access speed boost with burst is only possible when using C# job system and NativeArray, not just with any regular C# Array. (Please correct me if I am wrong.)

But one more curious question:

- Does putting using Unity.Mathematics inside namespace offer anything special? Or is it just to make sure its definition are searched and used in priority, as explained here? (I am not aware of any conflicting type in UnityEngine.)

38. ### Antypodish

Joined:
Apr 29, 2014
Posts:
5,170
Unity mathematics is designed, to be compatible with burst. Also, as long I am correct, is closely related to shaders mathematics.

Last edited: Mar 18, 2019
39. ### PhilSA

Joined:
Jul 11, 2013
Posts:
1,061
According to my tests, Unity.Mathematics is slightly slower than legacy math when not used in Burst jobs. Like maybe 5% slower

krzysie7 and bitinn like this.
40. ### Vanamerax

Joined:
Jan 12, 2012
Posts:
818
I would like to request left/right shift operator (<<, >>) implementations with both operands as int4 etc.

Currently we can do this:
Code (CSharp):
1. int4 result = new int4(1,1,1,1) << 1;
However, I would like to do this:
Code (CSharp):
1. int4 result = new int4(1,1,1,1) << new int4(1,2,3,4);
Which should shift the members componentwise such that the example above results in an int4 with the values (2,4,8,16).

Similarly for int2, int3, uint2, uint3, uint4 variants.

41. ### elcionap

Joined:
Jan 11, 2016
Posts:
87
C# doesn't support overloading a shift operator without an int as a second parameter.

[]'s

42. ### Vanamerax

Joined:
Jan 12, 2012
Posts:
818
Oh, really? I don't overload my shift operators all that often. The more you know..

Here's still hoping that Unity will support a vectorized shift operation somehow.

43. ### LazyGameDevZA

Joined:
Nov 10, 2016
Posts:
76
You can write your own function for that and I suspect it might be easily vectorized by the Burst compiler. A simple jab at this I would write it like such:

Code (CSharp):
1.
2. [MethodImpl(MethodImplOptions.AggressiveInlining)]
3. public int4 shiftLeft(int4 value, int4 shift)
4. {
5.     return new int4(value.x << shift.x, value.y << shift.y, value.z << shift.z, value.w << shift.w);
6. }
If it does become something that could make part of the mathematics library I'm sure Unity will look at adding it as well as making sure Burst vectorizes it correctly.

44. ### Vanamerax

Joined:
Jan 12, 2012
Posts:
818
Of course I can write my own function. However I wasn't sure whether it would be properly vectorized. Will have to check that later. Thanks anyway.

45. ### shongbee2

Joined:
Nov 29, 2016
Posts:
10
How to use GitHub source code to compile into our project? I need get starting compilation tutorial。

46. ### Antypodish

Joined:
Apr 29, 2014
Posts:
5,170
You either copy whole project, copy cs files or its classes to your project, and execute as normal. That is, providing these are not already part of packages.

47. ### Draveler

Joined:
Jul 1, 2018
Posts:
53
Anybody have any insights on using Unity.Mathematics.noise? I'd like to use this, but I'm not sure how the various methods work just from reading the docs. For example, can I get/set some generative seed? Does this directly relate to Unity.Mathematics.Random?

Joined:
Oct 17, 2016
Posts:
1,363
49. ### Draveler

Joined:
Jul 1, 2018
Posts:
53
Anybody have a clever solution for manually implementing midpoint-rounding modes?

Would love to be able to specify whether I want to round to nearest even int, away from zero, etc.

My current method involves a lot of conditional checks on vector components, and then selectively ceiling or flooring

Last edited: Apr 28, 2019
50. ### DreamingImLatios

Joined:
Jun 3, 2017
Posts:
360
nearest even int: divide by 2, round, then multiply by 2.
away from zero: multiply ceiling of absolute value with the sign of the original value.

In general, try to avoid conditionals even if it is less instructions total for such trivial things. However, comparisons to generate bools are cheap and one line conditionals (or preferably math.select) which don't generate branch instructions are usually the way to go.

Draveler likes this.