6 ms·
Hi, I'm on the Pony core team and I generally agree with you. The problem is, if you want to allow people to write high performance code, you are penalizing th
by spooneybarger 8y ago
Hi,
I'm on the Pony core team and I generally agree with you. The problem is, if you want to allow people to write high performance code, you are penalizing them becaues, for floating point:
1.0/0.0 is infinity. That's not C# being clever. That's C# following the floating point standard and using the math that the computer provides. To not use that standard means that you make every use of division slower, even if the programmer has in some way assert and otherwise knows that that they won't be dividing by zero.
Note that 1/0 is integer math and for that there is no standard and its undefined behavior. You can't return NaN or Infinity for that without boxing numbers which is a performance hit and would be penalizing programmers who want/need to go as fast as possible.
- skybrian 8y agoI'm curious, what do you think about Julia's approach with its special "missing" value? Does this approach make sense outside the context of data analysis? https://julialang.org/blog/2018/06/missing https://julialang.org/blog/2018/06/missing
- spooneybarger 8y agoI can't really comment. I don't know how they are doing it and why they made that choice. I assume that Julia was already boxing integers in some fashion at which point this 100% makes sense to me. Also, given the performance profile that you are seeking to allow programmers to achieve, I think boxing all integers makes sense, then you can give folks protection from integer overflow and underflow and otherwise make how the computer does math more closely approximate what we expect from doing math. I think that following my above reasoning that only having floating point math can also make sense. That is... in most programming languages 3 and 3.0 are different. Such that 3/ 2 = 1 and 3.0/2.0 = 1.5. We allow for 3/2=1 because, integer math is faster than floating point math and we want to allow folks to go as fast as possible when doing things like addition, subtraction and multiplication and accept that we can't represent all the numbers that come from division and give an approximation.
- skybrian 8y agoIf I understand correctly, instead of the usual kind of boxing, they use a separate type tag (one byte) and support union types with up to 255 other "special" enum values. The type tags and data are stored separately, so instead of an array of boxed values, they internally have two arrays, one for type tags and the other for data. Apparently this can work well with SIMD instructions.
- spooneybarger 8y agoThat's pretty cool. There's a lot that a couple of us on the Pony core team like about Julia from our limited knowledge. I'll have to look into that more.
- spooneybarger 8y agoI would like to add, given that this is my favorite talk, that the decisions a language ends up making in things like this are a good reflection of its values. Bryan Cantrill has an incredibly good talk on this that I recommend to anyone reading this: https://vimeo.com/230142234 https://vimeo.com/230142234
- ChrisRackauckas 8y agoJulia doesn't box integers, that would destroy speed. It also doesn't protect from overflow/underflow. It specializes on Vector{Int} so that's it's just a standard vector of integers. Then Vector{Union{Int,Missing}} is stored in memory as a vector of integers with a bitarray declaring missings. Indexing operations are expanded to ifelse a check for the existence and then return the value if it exists or a missing. Then branches are added by the compiler to handle the small unions. This keeps pure integer use without overhead, and gives a small penalty when using missing (which doesn't turn out to be all that bad due to how pipelining is usually done), but it's safe and any type can have missing values.
- spooneybarger 8y agoThank you. I look forward into learning more about how Julia handles this.
- oever 8y agoAnothor option is to use a NonZero type. A NonZero type is one that has been checked to not be zero. The type system ensures that you can only use a NonZero as a denominator in a division. You can minimize the number of checks for zero and the type system still protects you. And at points where performance trumps safetly you can still use a special version of division that returns 0 when the denominator is 0. How can 1 / 0 = 0 be fast? It's not a standard floating point instruction, so extra logic is needed to convert the Inf to a 0.