> The operation is finished when the progress float reaches 1.0 and isDone is called. If you set allowSceneActivation to false, progress is halted at 0.9 until it is set to true.
So, I needed to have my UI do other stuff until both this and something else was ready. Obvious thing to do would be to check this for "AsyncOperation.progress >= 0.9" and also check the other thing. Right?
Except AsyncOperation.progress is a float, 0.9 is a double and 0.9f < 0.9. Progress is not halted at 0.9. It never reaches 0.9. It's halted at 0.9f! Just a few million ulps short!
addaon 4 hours ago [-]
This is insane in so many different ways.
1) Why would you use floating point instead of fixed point or other fractional representation (uh, percent?) for this sort of thing?
2) Why would you design an interface that's specifically set up to make progress bars stall at 90%? This is insanely user hostile -- there are great UI patterns for expressing indeterminate progress when your progress is indeterminate!
3) Why in the example would you prompt user interaction at 90%? (I'll give them credit for at least comparing to 0.9f instead of 0.9 here.) What user expects a prompt to appear before progress is complete?
truemotive 5 hours ago [-]
trigger warning, lol
Zarathruster 6 hours ago [-]
Interesting. When I first got started with Unity I found really buggy behavior if you do any kind of physics calculations near world origin (0, 0, 0). It has a weird gravity well effect if you get too near it. I never found a satisfactory explanation for it but maybe this is it.
aras_p 5 hours ago [-]
If you mean built-in Unity physics, then unlikely. All built-in physics stuff (either 3D physics which is PhysX, or 2D physics which is Box2D) are done entirely in C++ code and are unaffected by Mono float<->double shenanigans.
gcr 1 hours ago [-]
How close to 0,0,0 are you talking?
Subnormal floating point shenanigans maybe?
garaetjjte 4 hours ago [-]
>Official Mono releases have switched to do that since then, but (I think) for backwards compatibility reasons Unity never enabled that functionality and kept everything at double precision so far.
Probably because Unity uses ancient Mono fork. And that apparently started because they didn't renew their non-copyleft license with Xamarin.
aras_p 4 hours ago [-]
That is not actually true.
Unity used to be on ancient version of Mono before year 2017. Then until 2019 the option to use “up to date” version was optional. Since 2019 it has been on more or less current Mono version (Mono itself stopped getting any serious updates around 2020).
koolala 8 hours ago [-]
I wish JavaScript or any open-source Array Language could do Single-precision Floats. It's awesome they were able to show the assembly breakdown.
taeric 7 hours ago [-]
I wish there was more explicit support for fixed point decimal out there.
bee_rider 6 hours ago [-]
Do you mean fixed point using integers, or actually decimal (base-10)? My gut would be to use fixed-point integers with a power of two in the denominator.
On the other hand, I’m not sure if modern compilers even bother converting division/multiplications by powers of two to shifts these days, so maybe it isn’t worth it…
taeric 5 hours ago [-]
Fair that relying on decimal is an interesting choice. My gut is that it would help with a lot of reasoning for folks.
This comes up all of the time with stuff like lat/lng values. People are convinced you have to use doubles because of the inaccuracy of floats. Completely skipping over the fact that you could have fixed point accuracy to 6 decimal digits with the same number of bits as a float. You just reduce your max/min value that you can represent. Which, for lat/lng, you are already heavily bounded.
I think it is fair to argue that basic libraries don't support trig on common fixed point sizes. But that is ultimately my lament. Floats are amazing for what they need to do. For what many people need, though, it feels overkill because it is overkill.
addaon 4 hours ago [-]
> This comes up all of the time with stuff like lat/lng values. People are convinced you have to use doubles because of the inaccuracy of floats.
Using any floating point representation for lat/long makes no sense at all to me. Floating point is designed for representing values where expected error scales with magnitude, not for values where error is constant with magnitude; the latter requires fixed point. I truly don't understand why someone would optimize their position representation for maximum accuracy off the coast of Africa, instead of having it uniform across the world.
taeric 4 hours ago [-]
Agreed. But I'm assuming we are in the minority on this one? Bad assumption?
addaon 4 hours ago [-]
Depends how you measure. The choice of floating point lat/long is very favorable for people in the area of Null Island, and while the population there nearly zero, the population density is either NaN or infinite, depending on how you handle your divide-by-zeros. I can certainly see optimizing your implementation for an infinite-population-density-area region...
taeric 3 hours ago [-]
Funny, though I think the main measure most people actually pay attention to is how complicated your code is to do the distance functions.
addaon 3 hours ago [-]
I've almost never seen a real complexity difference between floating point and fixed point math in a language that supports fixed point either natively or through operator overloading. Yeah, scaling sometimes changes across an operation; but that's the type system's job, it's not actual complexity. And the error analysis is almost always much simpler for the fixed point implementation than the floating point implementation; and anyone writing code doing numeric approximations in any representation without considering numeric stability and doing the error analysis probably isn't worth running software from.
taeric 2 hours ago [-]
I am a little confused. My assertion is that most languages don't offer fixed point trig functions. Am I wrong on that assertion?
If you have the trig functions already implemented for the fixed point you are doing, what you are saying makes perfect sense to me. But I swear I get challenged on that point every time it comes up, as nobody has a fixed point trig library. (Well, that seems to be the assertion.)
addaon 1 hours ago [-]
Fixed-point CORDIC is not hard… but a trivial implementation will be slower than a hardware float implementation, true. Several of the micros I work on have a CORDIC accelerator on a (usually only one) low-latency core designed for BLDC control etc, but that’s neither universal, nor general, of course.
kbolino 3 hours ago [-]
> People are convinced you have to use doubles because of the inaccuracy of floats
With single-precision floats, considering the worst case, i.e. longitudes close to the equator but far away from the prime meridian, one ulp can translate into as much as 1.68 m (5.5 ft) of distance on the surface (*). That's good enough for some uses, but not for dGPS or any other serious geometric computation. Whereas, with double precision, one ulp in this worst case scenario corresponds to about 3 nanometers. It's overkill, for sure, but if these are the only two types you have, you pick the latter.
* = To represent the integer 179, you need 8 bits, leaving only 16 for the fraction. Since 1 degree of longitude near the equator is about 110 km, you have 1/2^16 degrees * 110 km/degree giving 0.0016784... km.
taeric 2 hours ago [-]
Right. My point is that I wish more people would reach instead for a fixed point lat/lng library. It would almost certainly be easier to reason with for most people. Similar for most people doing financial math should probably use something other than IEEE floats.
And again, IEEE numbers are amazingly well done for what they are. Which is largely the digital version of scientific notation that is using base-2.
kbolino 2 hours ago [-]
It's quite difficult to find fixed-point number systems that include trigonometry, never mind fancier tools like elliptic integrals. The problem is not just one of static number representations, but also geodetic/geometric computations. [ed: I see this is where the other thread is heading already]
chainingsolid 4 hours ago [-]
Compilers will convert mul/div to shifts, if they notice one of the operands is a power of 2. I would have included a link to an example on compiler explorer (https://godbolt.org/) but the source editor didn't work on my Pinephone for some reason..
bee_rider 3 hours ago [-]
Ah, interesting, I’m playing around with it on godbolt and it is doing all the sort of obvious stuff you might expect (division by 2 implemented as a shift, multiplication by 2 or 3 represented as adds, etc). You are right.
For some reason this was in my head as one of those “surprisingly, optimizing compilers might skip it” situations (like loop unrolling). Dunno where I picked that up.
taeric 2 hours ago [-]
I think the trick is to make sure the compiler knows you are doing the math with a constant and such? They likely won't branch on arbitrary numbers to sometimes do it as a shift and other times do the multiplication. But compilers for a long time would propagate constants through and pick a faster option for basic a*2.
koolala 7 hours ago [-]
Speed wise no hardware can do it though.
taeric 5 hours ago [-]
This depends entirely on the sizes needed. For a surprising number of things people would use fixed point for, I would be surprised if you couldn't get good speed with surprisingly little effort.
vardump 5 hours ago [-]
I would be surprised if you could get even one third of performance of floats. So why bother?
taeric 4 hours ago [-]
If you don't have to do trig, I'd be surprised if you aren't faster by default, oddly. Indeed, if you are just adding and subtracting, it is just a number. If you are doing multiplication, it is a multiply and shift. So long as you don't try and support massive numbers of different fixed sizes, that shift is almost certainly still cheaper than float hardware. (Indeed, a lot of multiplications wouldn't even need the shift...)
Again, I do not mean this as a criticism of floats. For simulations and for numbers where you do have to support completely arbitrary values, there is a reason floats are a thing.
jcranmer 4 hours ago [-]
An integer add, sub, or shift is 1 cycle of latency; integer mul is generally 3 cycles; integer div is lol-that-is-slow. Floating-point adds, subs, muls, and fmas are generally 4 cycles, with div being lol-that-is-slow (but generally faster than integer division because your divisor and dividend have fewer bits).
So fixed-point addition and subtraction are definitely faster, multiplication is a wash if you're doing binary-based fixed point (but slower if you're doing decimal-based fixed point), and fixed-point division is definitely slower than floating-point division.
taeric 4 hours ago [-]
Kudos on providing the numbers. I wasn't confident in the numbers that I remembered and with how pipelined everything is, I didn't know how much to lean on them. Not exactly my standard workflow to care about this level of speed.
My gut would still be that it is typically a wash for most everyone as far as speeds go? If default libraries supported it more directly, I would think it would largely be a win for a lot of reasoning. In particular, silly stuff like 1e32 + 1e1 would not be nearly as surprising to most people. And the entire class of bugs around stuff like doing something until it reaches 0.9 would almost certainly go away if we guaranteed precision to a set number decimal places.
Alas, default libraries do not support this, though. So the above is admittedly wishful thinking on my end. And I could as easily describe a world where people insist on arbitrary numbers of fixed point values and how that would be its own set of landmines.
adgjlsfhk1 6 hours ago [-]
What do you mean by Array Language? Would Julia qualify here?
koolala 6 hours ago [-]
I was thinking like APL, all the open ones are float64 based.
> The operation is finished when the progress float reaches 1.0 and isDone is called. If you set allowSceneActivation to false, progress is halted at 0.9 until it is set to true.
So, I needed to have my UI do other stuff until both this and something else was ready. Obvious thing to do would be to check this for "AsyncOperation.progress >= 0.9" and also check the other thing. Right?
Except AsyncOperation.progress is a float, 0.9 is a double and 0.9f < 0.9. Progress is not halted at 0.9. It never reaches 0.9. It's halted at 0.9f! Just a few million ulps short!
1) Why would you use floating point instead of fixed point or other fractional representation (uh, percent?) for this sort of thing?
2) Why would you design an interface that's specifically set up to make progress bars stall at 90%? This is insanely user hostile -- there are great UI patterns for expressing indeterminate progress when your progress is indeterminate!
3) Why in the example would you prompt user interaction at 90%? (I'll give them credit for at least comparing to 0.9f instead of 0.9 here.) What user expects a prompt to appear before progress is complete?
Subnormal floating point shenanigans maybe?
Probably because Unity uses ancient Mono fork. And that apparently started because they didn't renew their non-copyleft license with Xamarin.
Unity used to be on ancient version of Mono before year 2017. Then until 2019 the option to use “up to date” version was optional. Since 2019 it has been on more or less current Mono version (Mono itself stopped getting any serious updates around 2020).
On the other hand, I’m not sure if modern compilers even bother converting division/multiplications by powers of two to shifts these days, so maybe it isn’t worth it…
This comes up all of the time with stuff like lat/lng values. People are convinced you have to use doubles because of the inaccuracy of floats. Completely skipping over the fact that you could have fixed point accuracy to 6 decimal digits with the same number of bits as a float. You just reduce your max/min value that you can represent. Which, for lat/lng, you are already heavily bounded.
I think it is fair to argue that basic libraries don't support trig on common fixed point sizes. But that is ultimately my lament. Floats are amazing for what they need to do. For what many people need, though, it feels overkill because it is overkill.
Using any floating point representation for lat/long makes no sense at all to me. Floating point is designed for representing values where expected error scales with magnitude, not for values where error is constant with magnitude; the latter requires fixed point. I truly don't understand why someone would optimize their position representation for maximum accuracy off the coast of Africa, instead of having it uniform across the world.
If you have the trig functions already implemented for the fixed point you are doing, what you are saying makes perfect sense to me. But I swear I get challenged on that point every time it comes up, as nobody has a fixed point trig library. (Well, that seems to be the assertion.)
With single-precision floats, considering the worst case, i.e. longitudes close to the equator but far away from the prime meridian, one ulp can translate into as much as 1.68 m (5.5 ft) of distance on the surface (*). That's good enough for some uses, but not for dGPS or any other serious geometric computation. Whereas, with double precision, one ulp in this worst case scenario corresponds to about 3 nanometers. It's overkill, for sure, but if these are the only two types you have, you pick the latter.
* = To represent the integer 179, you need 8 bits, leaving only 16 for the fraction. Since 1 degree of longitude near the equator is about 110 km, you have 1/2^16 degrees * 110 km/degree giving 0.0016784... km.
And again, IEEE numbers are amazingly well done for what they are. Which is largely the digital version of scientific notation that is using base-2.
For some reason this was in my head as one of those “surprisingly, optimizing compilers might skip it” situations (like loop unrolling). Dunno where I picked that up.
Again, I do not mean this as a criticism of floats. For simulations and for numbers where you do have to support completely arbitrary values, there is a reason floats are a thing.
So fixed-point addition and subtraction are definitely faster, multiplication is a wash if you're doing binary-based fixed point (but slower if you're doing decimal-based fixed point), and fixed-point division is definitely slower than floating-point division.
My gut would still be that it is typically a wash for most everyone as far as speeds go? If default libraries supported it more directly, I would think it would largely be a win for a lot of reasoning. In particular, silly stuff like 1e32 + 1e1 would not be nearly as surprising to most people. And the entire class of bugs around stuff like doing something until it reaches 0.9 would almost certainly go away if we guaranteed precision to a set number decimal places.
Alas, default libraries do not support this, though. So the above is admittedly wishful thinking on my end. And I could as easily describe a world where people insist on arbitrary numbers of fixed point values and how that would be its own set of landmines.